1.14k likes | 1.32k Views
第二章 数组. 线性表 顺序表 稀疏矩阵 字符串. 一、线性表. 线性表 相同数据类型的元素的有限序列 叫线性表。 ( a 1 , a 2 , … ,a n-1 , a n ) a 1 为 首元 , a n 为 末元 , n 叫 线性表的 长度 a i 的 后继 是 a i+1 , i=1, …,n-1. a n 没有后继 。 a i 的 前驱 是 a i-1 , i=2, …,n. a 1 没有前驱 。 a i 可以是基本数据类型也可以是 struct 类型。 没有数据的线性表叫 空表 。空表的长度 n=0 。.
E N D
第二章 数组 • 线性表 • 顺序表 • 稀疏矩阵 • 字符串
一、线性表 线性表 相同数据类型的元素的有限序列 叫线性表。 (a1, a2, … ,an-1, an) a1为首元,an为末元,n叫线性表的长度 ai的后继是ai+1, i=1, …,n-1. an没有后继。 ai的前驱是ai-1, i=2, …,n. a1没有前驱。 ai可以是基本数据类型也可以是struct 类型。 没有数据的线性表叫空表。空表的长度n=0。 a1 a2 a3 a4 a5 a6
线性表是最简单的也是最基本的数据结构。 • 线性表可以用来构造字符串,集合,栈,队列,用来排序。 • 线性表可以顺序表示用一组地址连续的存储单元一次存储数据元素。 • 线性表也可以用线性链表表示。
二、顺序表——线性表的顺序表示 可以用通用数组定义通用线性表。 通用数组是可变长度的数组,也叫安全数组。
类模版 通用数据类型 //array.h 例. 通用数组 抽象数组类型 template <class T> class Array { T *alist; //指针数据 表示一个数组 int size; //表示数组长度 public: Array(int s=50) //构造函数 Array(const Array<T>&X); //拷贝构造函数 ~Array( ){delete[ ] element;} //析构函数 Array<T>&operator=(const Array<T>&X);// 赋值函数重载 T& operator[ ](int i); //一元运算[ ]重载 下标函数 operator T*( )const;//强制类型转换,将当前 //对象变成指向它的首地址的指针, int ArraySize( )const; //取数组长 void Resize(int sz); //数组长重定义 friend ostream& operator<<(ostream&, const Array<T>&); //输出操作重载 };
#include <array.h> template<class T> class SeqList { Array<T>listitem; //list storage array int size; public: SeqList(void); // constructor构造函数 // list access methods 线性表的访问操作 int ListSize(void) const; //取线性表的长 int ListEmpty(void)const; //问表是否空表 int Find (T& item) const; //查找一个元素 TGetData(int pos) const; //取线性表中元素
// list modification methods线性表的修改操作 void Insert(const T& item);//表尾插入元素 void Insert(const T& item,int i); // 在第i个位插入一个新元素 void Delete(const T& item);//删除一个元素 T DeleteFront(void); //删除首元 void ClearList(void); //清空 };
// constructor. set size to 0 template<class T> SeqList<T>::SeqList(void): listitem(size),size(0) { }
// return number of elements in list template<class T> int SeqList<T>::ListSize(void) const { return size; }
// tests for an empty list template<class T> int SeqList<T>::ListEmpty(void) const { return size == 0; }
// clears list by setting size to 0 template<class T> void SeqList<T>::ClearList(void) { size = 0; }
// Take item as key and search the list. //return True if item is in the list and // false otherwise. If found, assign the list // element to the reference parameter item. template<class T> int SeqList<T>::Find(T& item) const { int i = 0; if (ListEmpty())return 0; // return False when list empty
while(i<size &&!(item==listitem[i])) i++; if (i < size) { item = listitem[i]; // assign list element to item return 1; // return True } else return 0; // return false }
// insert item at the rear of the list. template<class T> void SeqList<T>::Insert(const T& item) { //如果超长,扩大内存 if (size+1 > listitem.ListSize( )) listitem.Resize(size+1); // index of rear is current value of //size. insert at rear listitem[size] = item; size++; // increment list size }
template<class T> //在第i位插入 void SeqList<T>::Insert(const T& item, int i) { if (i<0) {cout<<“’i’can not be negative!"; return;} if(i>=size){Insert(item);return;} if (size+1 > listitem.ListSize( )) listitem.Resize(size+1); int k=size-1;
//shift the tail of the list //to the right one position while (k >= i) { listitem[k+1] = listitem[k]; k--; } listitem[i] = item; size++; // increament list size }
//search for item in the list //and delete it if found template<class T> void SeqList<T>::Delete(const T& item) { int i = 0; // search for item while (i < size && !(item == listitem[i])) i++; if (i < size) // successful if i < size {
// shift the tail of the list //to the left one position while (i < size-1) { listitem[i] = listitem[i+1]; i++; } size--;// decreament size } }
//delete element at front of list and return // its value. terminate the program with// an error message if the list is empty. template<class T> TSeqList<T>::DeleteFront(void) { TfrontItem; // list is empty if size == 0 if (size == 0) { cerr << "Attempt to delete the front / of an empty list!" << endl; exit(1); }
frontItem = listitem[0]; // get value from position 0. Delete(frontItem); // delete the first item and shift terms return frontItem; // return the original value }
// return value at position pos in list. // if pos is not valid list position, // teminate program with an error message. template<class T> TSeqList<T>::GetData(int pos) const { // terminate program if pos out of range if (pos < 0 || pos >= size) {cerr << "pos is out of range!" << endl; exit(1); } return listitem[pos]; }
测试 #include “ iostream.h” #include “aseqlist.h” void main(void) { SeqList<int> a,b; int x; for(int i=0;i<20;i++) {a.Insert(i); cout<<"input "<<i’s<<“ integer:"; cin>>x; b.Insert(x+1);} for(i=0;i<20;i++) cout<<a.GetData(i)<<' '; cout<<endl;
for(i=0;i<20;i++) cout<<b.GetData(i)<<' '; cout<<endl; a.Insert(99,0); a.Insert(98,10); a.Insert(97,20); a.Insert(96,30); int k=a.ListSize( ); for(i=0;i<k;i++) cout<<a.GetData(i)<<' '; cout<<endl; }
顺序表应用的例: 1. 用顺序表做插入,选择排序. 2. 合并两个已排序的线性表 3. 用顺序表做集合: 只插入不重复的元素 4. 求两个集合的交合并 5. 表示一个多项式 6. 求多项式的和差积商,微分,积分 7. 存储一个矩阵, 求矩阵的和,积,逆
顺序线性表复杂度分析 • 从已建立的顺序表中“取表长” ,“取第i个元素”的复杂性是O(1), 2. 在表长n的顺序表第i位前插入一个元素,要把表尾n-i+1个元素后移一格。 假设每一位都插入一个数,从第1位到末尾第n+1位,总移动次数是: Σi=1i=n+1(n-i+1)=1+2+…+n=n*(n+1)/2 平均复杂度为O(n/2). 3. 删除第i位元素,要把表尾n-i个元素前移一格。假设每一位都删除一个数,从第1位到末尾第n位,总移动次数是: Σi=1i=n+1(n-i)=1+2+…+(n-1)=n*(n-1)/2 平均复杂度为O((n-1)/2).
三、稀疏矩阵 一个阶数很高的矩阵中如果有许多相等的元素,或零元素,成为特殊矩阵。 对特殊矩阵可以进行压缩存储
特殊矩阵 对称矩阵 上(下)三角矩阵 对角矩阵 稀疏矩阵
对称矩阵 矩阵 A=(aij)n,n aij= aji , 0≤i,j≤n 每一对元素分配一个存储空间,可以 将n2个元素存储到n(n+1)/2个空间中
下三角矩阵 1+2+3+ ……+n=n(n+1)/2 T s[n(n+1)/2]; a11 a21a22 a31a32 a33 …… an1an2 an3 ……ann s[0]=a11;s[1]=a21; s[k]=aij k=i(i-1)/2+j-1; i≥j; k=j(j-1)/2+i-1; i<j. s[12]=aij=aji; i=4, j=3
对角矩阵 a11 a12 a21 a22 a23 · · · · · · · · an-1n ann-1 ann s[k]=aij; k=3(i-1)+j; j=k%3; i=(k-j)/3
稀疏矩阵 Sparse Matrix 0 12 9 0 0 0 0 0 0 0 0 0 0 0 -3 0 0 0 0 14 0 0 0 24 0 0 0 0 0 18 0 0 0 0 0 15 0 0 -7 0 0 0 m*n阶矩阵 A=(aij)mn中有t个非零元素, 如果 δ=t/(m*n)≤5%, 称A为稀疏矩阵
//smatrix.dat 6 7 8 1 2 12 1 3 9 3 1 –3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7
稀疏矩阵的存储 row col elem 1 2 12 1 3 9 3 1 –3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7
稀疏矩阵元素的类TRiple template<class T> class Triple { public: int row, col; T elem; SetVal(int r,int c,T d) {elem=d;row=r;col=c;} };
稀疏矩阵类的定义 #define MAXSIZE 500 template<class T> class SparseMatrix { Triple<T> data[MAXSIZE+1]; int mu, nu, tu; //行数、列数、元素个数 public: SparseMatrix( ){mu=nu=tu=0;} SparseMatrix(char*filename); SparseMatrix<T> Transpose( ); SparseMatrix<T> Add(SparseMatrix<T> b); SparseMatrix<T> Muliply(SparseMatrix<T> b); void print( )const; };
template<class T> SparseMatrix<T>::SparseMatrix(char *filename) { ifstream fin; int i,r,c; T d; fin.open(filename, ios::in | ios::nocreate); if (!fin){ cerr << "The maze data file " << filename << " cannot be opened!" << endl; exit(1); } fin >> mu>>nu>>tu; for (i = 1; i <= tu; i++) { fin >> r >> c>>d; data[i].SetVal(r,c,d);} fin.close( ); };
矩阵的转置 T=M’ for(col=1;col<=nu;col++) for(row=1;row<=mu;row++) T[col][row]=M[row][col] 时间复杂度O(mu*nu)
M’ rowcol elem 21 12 3 1 9 1 3 –3 6 3 14 3 4 24 2 5 18 1 6 15 46 -7 M rowcol elem 12 12 1 3 9 3 1 –3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7
M rowcol elem 12 12 1 3 9 3 1 –3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 M’ rowcol elem 13 -3 16 15 21 12 2 5 18 31 9 34 24 4 6 -7 6 3 14
稀疏矩阵的转置 T=M’ 算法5.1 template <class T> SparseMatrix<T> SparseMatrix<T> ::Transpose( ) {SparseMatrix<T> temp; int i, j, k=1; temp.mu=nu; temp.nu=mu; temp.tu=tu; if(tu){for(i=1;i<=nu;++i) for(j=1;j<=tu;++j) if(data[j].col==i) {temp.data[k].row=data[j].col; temp.data[k].col=data[j].row; temp.data[k].elem=data[j].elem; k++;} return temp;}
稀疏矩阵的转置的时间复杂度 O(nu*tu) 若tu~nu*mu O(nu*tu)=O(mu*nu*nu) 不是一个好算法! 应当改进!
快速转置 依次逐个对号入座 M rowcol elem 12 12 1 3 9 3 1 –3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 M’ rowcol elem 2 1 12 3 1 9 先求出M中每一列(即M’中每一行)元素的个数num[col],确定M’每行起始位置cpot[col]。
快速转置 M rowcol elem 12 12 1 3 9 3 1 –3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7
时间复杂性O(nu+tu) 快速转置算法5.2 template <class T> SparseMatrix<T> SparseMatrix<T> ::Transpose( ) {SparseMatrix<T> temp; int i, j, k; int*num=new int[nu+1]; int* cpot=new int[nu+1]; cpot[1]=1; temp.mu=nu; temp.nu=mu;temp.tu=tu; if(tu){for(i=1;i<=nu;++i)num[i]=0; for(i=1;i<=tu;++i)++num[data[i].col]; for(i=1;i<nu;++i)cpot[i+1]=cpot[i]+num[i]; for(i=1;i<=tu;++i){j=data[i].col;k=cpot[j]; temp.data[k].row=j; temp.data[k].col=data[i].row; temp.data[k].elem=data[i].elem; ++cpot[j];} } return temp; }
稀疏矩阵的加法 template <class T> SparseMatrix<T> SparseMatrix<T>:: Add(SparseMatrix<T> b ) {SparseMatrix<T> temp; if(mu!=b.mu||nu!=b.nu) {cerr<<“error ”<<end;return temp;} temp.mu=mu; temp.nu=nu; int i=1, j=1, k=1; while(i<=tu||j<=b.tu) {if((data[i].row<b.data[j].row) || (data[i].row==b.data[j].row) && (data[i].col<b.data[j].col)) {temp.data[k]=data[i]; k++;i++;}
else if((data[i].row==b.data[j].row)&& (data[i].col==b.data[j].col)) {temp.data[k].row=data[i]. row; temp.data[k].col=data[i].col; temp.data[k].elem=data[i]. elem+b.data[j]. elem k++;i++;j++;} else { temp.data[k]=b.data[j];k++;j++;} temp.tu=k-1; return temp; }
矩阵的乘法 Amp*Bpn 时间复杂度mpn (aij)*(bij)=(Σ1≤k≤paik*bkj) 2 0 0 -1 0 1 0 3 0 0 1 0 1 0 1 0 0 -1 0 0 0 2 0 1 3 0 1 0 a11*b11 a11*b12 a11*b13 a11*b14 a12*b21a12*b22 a12*b23a12*b24 a13*b31a13*b32 a13*b33a13*b34 a14*b41a14*b42 a14*b43a14*b44
稀疏矩阵的乘法 B rowcol elem rpos[row] 11 8 rpos[1]= 1 2 3 4 rpos[2]= 2 3 2 1 rpos[3]=3 3 5 -1 4 1 2 rpos[4]=5 4 4 -3 5 1 5 rpos[5]=7 6 2 -2 rpos[6]=8 A rowcol elem 12 12 1 3 9 3 1 –3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7
template <classT>SparseMatrix<T> SparseMatrix<T>::Multiply(SparseMatrix<T> b ) {SparseMatrix<T> temp; if(nu!=b.mu) {cer<<“error ”<<end;return temp;} temp.mu=mu;temp.nu=b.nu; int *num=new int[b.mu+1]; int *rpos=new int[b.mu+1]; rpos[1]=1; T ctemp[b.nu+1]; for(int i=1;i<=b.mu;i++) num[i]=0; for(i=1;i<=b.tu;i++)++num[b.data[i].row]; for(i=1;i<=b.mu;i++)rpos[i+1]=rpos[i]+num[i];
int k=1,j, r,c,t=0; while(k<=tu) { for( j=1;j<=b.nu;j++) ctemp[j]=0; r=data[k].row; while(k<=tu&&data[k]=r) {c=data[k].col; for(i=rpos[c];i<rpos[c+1];i++;) {j=b.data[i].col; ctemp[j]=ctemp[j]+data[k].elem*b.data[i].elem;} k++;}