线性表是最常用且最简单的一种数据结构,也就是n个元素的有限序列。
表示为(a1,...ai,...,an);
线性表的顺序表示
用一组地址连续的存储单元依次有序存储线性表的数据元素,若每个元素占用l个储存单元,则线性表第i个元素的位置与第一个元素的位置关系为loc(ai)=loc(1)+(i-1)*l;
typedef struct //定义顺序表{//指向数组第一位 int *elem; int length;} SqList;
初始化一个顺序表
void InitSqList(SqList &L) //创建顺序表{//MAXSIZE可以预定义//给顺序表分配空间 L.elem = new int[MAXSIZE]; //若储存空间分配失败 if (!L.elem) exit(0); //初始时顺序表长度为零 L.length = 0;}
顺序表元素从键盘输入
void SqListInput(SqList &L) //顺序表数据的输入{ int i = L.length; string line, word; //读取一行数据 getline(cin, line); stringstream stream(line); while(stream >> word) { //把字符串转化为int型 L.elem[i++] = stoi(word); } //顺序表的长度 L.length = i;}
顺序表元素的输出
void output(SqList L) { int i; cout << '['; for (i = 0; i < L.length; i++) { if (i) cout << ","; cout << L.elem[i]; } cout << ']' << endl;}
顺序表的重置
// 重置顺序表(释放L.elem)void resetSqlist(SqList &L){ if (L.elem) { //取消内存分配 delete(L.elem); L.elem = NULL; L.length = 0; }}
取出顺序表中第i位的值
//算法2.2 顺序表的取值int GetElem(SqList L, int i) { if (i < 1 || i > L.length) return ERROR; //判断i值是否合理,若不合理,返回ERROR else return L.elem[i - 1]; }
查找顺序表中是否有e值
//算法2.3 顺序表的查找int LocateElem(SqList L, int e) { for (int i = 0; i < L.length; i++) if (L.elem[i] == e) return i + 1;//查找成功,返回序号i+1 return 0;//查找失败,返回0}
顺序表的插入
//算法2.4 顺序表的插入//在顺序表L中第i个位置之前插入新的元素eint ListInsert(SqList &L, int i, int e) { //i值的合法范围是1<=i<=L.length+1 if ((i < 1) || (i > L.length + 1)) return ERROR; //i值不合法 if (L.length == MAXSIZE) return ERROR; //当前存储空间已满 for (int j = L.length - 1; j >= i - 1; j--) L.elem[j + 1] = L.elem[j]; //插入位置及之后的元素后移 L.elem[i - 1] = e; //将新元素e放入第i个位置 ++L.length; //表长增1 return OK;}
当有n个元素,在第i个位置插入时,要移动n-i+1位,假设每个位置插入都是等概率的,那么时间复杂度为O(n/2);
顺序表的删除
int Listdelet(SqList &L,int i){if(i<1||i>L.length)return ERROR;for(int j=i;j-1;j++){L.elem[j]=L.elem[j+1];}L.length--;return OK;}
顺序表倒置
//T1:顺序表头尾颠倒void reverseSqList(SqList &L){//将第i个元素与n-i+1个元素转换for(int i=0;i2;i++){ int t=L.elem[i]; L.elem[i]=L.elem[L.length-i-1]; L.elem[L.length-i-1]=t;}}
合并两个顺序表(不含重复元素)
思路:遍历b表的所有元素,每次在A表中查询是否存在,若存在不操作,若不存在,则插入
//T2:算法2.14 线性表的合并(顺序表)//将所有在线性表LB中但不在LA中的数据元素插入到LA中void unionSqList(SqList &LA, SqList LB) {for(int i=1;i<=LB.length;i++){ int temp=GetElem(LB,i); if(!LocateElem(LA,temp)){ LA.elem[LA.length]=temp; LA.length++; }}} //unionList
顺序有序表的合并
思路:用两个指针分别指向两个有序表,逐一比较两个指针元素的数据大小,若小的则插入,并让指针后移,直到表尾
//T3:算法2.16 顺序有序表的合并//已知顺序有序表LA和LB的元素按值非递减排列//归并LA和LB得到新的顺序有序表LC,LC的元素也按值非递减排列void MergeSqList(SqList LA, SqList LB, SqList &LC) {int* pa=LA.elem;int* pb=LB.elem;LC.length=LA.length+LB.length;int *pc=LC.elem=(int*) malloc(LC.length*sizeof(int));if(!LC.elem) exit(0);int* pa_last=LA.elem+LA.length-1;int* pb_last=LB.elem+LB.length-1;while(pa<=pa_last&&pb<=pb_last){ if(*pa<=*pb) *pc++=*pa++; else *pc++=*pb++;}while(pa<=pa_last) *pc++=*pa++;while(pb<=pb_last) *pc++=*pb++;} //MergeList_List
线性表的链式储存结构
线性表的链式储存结构的特点是用一组任意的储存单元储存线性表的数据元素,这组储存单元可以是连续的,也可以是不连续的,因此,为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,还需要储存一个表示其直接后继的信息。
定义方法
typedef struct LNode { int data; //结点的数据域 struct LNode *next; //结点的指针域 //LinkList(List)指针分别指向带头结点的单链表(不带头结点的单链表)} LNode, *LinkList, *List;
创建链表的头结点
void InitLinkList(LinkList &L) //创建链表头结点{ L = new LNode; L->next = NULL;}
创建链表
void inputLL(LinkList &L) //链表数据的输入{//r记录前指针 LinkList p, r = L; int count = 0; string line, word; D(cout << "从键盘输入用空格间隔的一组整数: " << endl;) getline(cin, line); stringstream stream(line); while(stream >> word) { //新建一个结点 p = new LNode; p->data = stoi(word); p->next = NULL; r->next = p; r = p; //记录结点个数 count++; } //头结点储存链表结点个数 L->data = count;}
链表元素的输出
void outputLL(LinkList L) //输出LinkList{ LinkList p; cout << '[' << L->data << ']'; p = L->next; while (p && p->next) { cout << p->data << "-"; p = p->next; } if (p) cout << p->data << endl;}
链表空间的释放
void deleteLL(LinkList L) //释放LinkList{ LinkList c = L; while (L) { L = L->next; delete(c); c = L; }}
链表的查找
//算法2.8 按值查找LNode *LocateElem(LinkList L, int e) { //在带头结点的单链表L中查找值为e的元素 LinkList p; p = L->next; //从第一个位置开始遍历 while (p && p->data != e) p = p->next; return p; //查找成功返回值为e的结点地址p,查找失败p为NULL }
链表的插入
//算法2.9 单链表的插入int ListInsert(LinkList &L, int i, int e) { //在带头结点的单链表L中第i个位置插入值为e的新结点 int j; LinkList p, s; p = L; j = 0; while (p && j < i - 1) { p = p->next; ++j; } //插入的位置不合理 if (!p || j > i - 1) return ERROR; s = new LNode; s->data = e; s->next = p->next; p->next = s; //增加结点个数 ++L->data; return OK;}
链表的删除
int ListDelete(LinkList &L,int i){int j;LinkList p, s; p = L; j = 0; while (p->next && j < i - 1) { p = p->next; ++j; } if(!(p->next)||j>i-1) return ERROR;//删除的位置不合理 p->next=p->next->next; return OK;}
判断是否有某个元素
bool HasElem(LinkList L, int e) { LinkList p=L->next; while(p){ //相等即找到 if(p->data==e) { return true; } p=p->next; } return false;}
合并两个链表
//T2: 算法2.15 线性表的合并(链表)//将所有在线性表LB中但不在LA中的数据元素插入到LA中void unionLinkList(LinkList &LA, LinkList LB) { LinkList p,q; p=LA->next;q=LB->next; //往前插 while(q){ if(!HasElem(LA,q->data)){ ListInsert(LA,1,q->data); } q=q->next; } // deleteLL(LB);}
判断两个链表是否完全相同
//T3: 判断两张单链表是否完全相等bool equal(LinkList LA, LinkList LB){ //长度不同直接返回 if(LA->data!=LB->data) return false; LinkList a,b; a=LA->next;b=LB->next; while(a&&b){ if(a->data!=b->data) return false; a=a->next;b=b->next; }return true;}
判断两个链表内容是否一致
//T4: 判断两张单链表的内容是否一致bool contains(LinkList LA, LinkList LB){ //a指向长链,b指向短链 LinkList a,b; if(LA->data >= LB->data){a=LA;b=LB;} else{a=LB;b=LA;} //关键一步 b=b->next; while(b){ if(!LocateElem(a,b->data)) return false; b=b->next; } return true }
删除指定元素
//T5: 在带头结点的单链表L中,删除所有的元素evoid deleteAll(LinkList &L, int e) { LinkList p=L->next; LinkList pre=L; while(p){ if(p->data==e){ pre->next=p->next; L->data--; }else{ pre=p; } p=p->next; }}
顺序表完整代码
#include#includeusing namespace std;//#define DEBUG#ifdef DEBUG#define D(x) x#else #define D(x) #endif#define MAXSIZE 100#define ERROR 0#define OK 1typedef int Status;typedef struct //定义顺序表{ int *elem; int length;} SqList;void InitSqList(SqList &L) //创建顺序表{ L.elem = new int[MAXSIZE]; if (!L.elem) exit(0); L.length = 0;}void SqListInput(SqList &L) //顺序表数据的输入{ int i = L.length; string line, word; getline(cin, line); stringstream stream(line); while(stream >> word) { L.elem[i++] = stoi(word); } L.length = i;}//依次输出顺序表里的每个元素void output(SqList L) { int i; cout << '['; for (i = 0; i < L.length; i++) { if (i) cout << ","; cout << L.elem[i]; } cout << ']' << endl;}// 重置顺序表(释放L.elem)void resetSqlist(SqList &L){ if (L.elem) { delete(L.elem); L.elem = NULL; L.length = 0; }}//算法2.2 顺序表的取值int GetElem(SqList L, int i) { if (i < 1 || i > L.length) return ERROR; //判断i值是否合理,若不合理,返回ERROR else return L.elem[i - 1]; }//算法2.3 顺序表的查找int LocateElem(SqList L, int e) { for (int i = 0; i < L.length; i++) if (L.elem[i] == e) return i + 1;//查找成功,返回序号i+1 return 0;//查找失败,返回0}//算法2.4 顺序表的插入//在顺序表L中第i个位置之前插入新的元素eStatus ListInsert(SqList &L, int i, int e) { //i值的合法范围是1<=i<=L.length+1 if ((i < 1) || (i > L.length + 1)) return ERROR; //i值不合法 if (L.length == MAXSIZE) return ERROR; //当前存储空间已满 for (int j = L.length - 1; j >= i - 1; j--) L.elem[j + 1] = L.elem[j]; //插入位置及之后的元素后移 L.elem[i - 1] = e; //将新元素e放入第i个位置 ++L.length; //表长增1 return OK;}//--------------------------------解答--//T1:顺序表头尾颠倒void reverseSqList(SqList &L){for(int i=0;i2;i++){ int t=L.elem[i]; L.elem[i]=L.elem[L.length-i-1]; L.elem[L.length-i-1]=t;}}//T2:算法2.14 线性表的合并(顺序表)//将所有在线性表LB中但不在LA中的数据元素插入到LA中void unionSqList(SqList &LA, SqList LB) {for(int i=1;i<=LB.length;i++){ int temp=GetElem(LB,i); if(!LocateElem(LA,temp)){ LA.elem[LA.length]=temp; LA.length++; }}} //unionList//T3:算法2.16 顺序有序表的合并//已知顺序有序表LA和LB的元素按值非递减排列//归并LA和LB得到新的顺序有序表LC,LC的元素也按值非递减排列void MergeSqList(SqList LA, SqList LB, SqList &LC) {int* pa=LA.elem;int* pb=LB.elem;LC.length=LA.length+LB.length;int *pc=LC.elem=(int*) malloc(LC.length*sizeof(int));if(!LC.elem) exit(0);int* pa_last=LA.elem+LA.length-1;int* pb_last=LB.elem+LB.length-1;while(pa<=pa_last&&pb<=pb_last){ if(*pa<=*pb) *pc++=*pa++; else *pc++=*pb++;}while(pa<=pa_last) *pc++=*pa++;while(pb<=pb_last) *pc++=*pb++;} //MergeList_Listint main() { SqList La, Lb, Lc; InitSqList(La); SqListInput(La); InitSqList(Lb); SqListInput(Lb); //*/ T1 D(cout << "倒置之前的顺序表A:\n";) output(La); reverseSqList(La); D(cout << "倒置之后的顺序表A:\n";) output(La);//*///*/ T3 D(cout << "非递减顺序表A,B合并后的非递减线性表C为:\n";) MergeSqList(La, Lb, Lc); output(Lc);//*///* T2 D(cout << "顺序表B合并到A表(不能出现重复元素):\n";)//output(La); unionSqList(La, Lb);// output(Lb); output(La);//*/ return 0;}
链表完整代码
#include#include#includeusing namespace std;//#define DEBUG#ifdef DEBUG#define D(x) x#else #define D(x) #endif#define ERROR 0#define OK 1typedef int Status;typedef struct LNode { int data; //结点的数据域 struct LNode *next; //结点的指针域} LNode, *LinkList, *List; //LinkList(List)指针分别指向带头结点的单链表(不带头结点的单链表)void InitLinkList(LinkList &L) //创建链表头结点{ L = new LNode; L->next = NULL;}void inputLL(LinkList &L) //链表数据的输入{ LinkList p, r = L; int count = 0; string line, word; D(cout << "从键盘输入用空格间隔的一组整数: " << endl;) getline(cin, line); stringstream stream(line); while(stream >> word) { //新建一个结点 p = new LNode; p->data = stoi(word); p->next = NULL; r->next = p; r = p; //记录结点个数 count++; } L->data = count;}//算法2.8 按值查找LNode *LocateElem(LinkList L, int e) { //在带头结点的单链表L中查找值为e的元素 LinkList p; p = L->next; while (p && p->data != e) p = p->next; return p; //查找成功返回值为e的结点地址p,查找失败p为NULL }//算法2.9 单链表的插入Status ListInsert(LinkList &L, int i, int e) { //在带头结点的单链表L中第i个位置插入值为e的新结点 int j; LinkList p, s; p = L; j = 0; while (p && j < i - 1) { p = p->next; ++j; } if (!p || j > i - 1) return ERROR; s = new LNode; s->data = e; s->next = p->next; p->next = s; //增加结点个数 ++L->data; return OK;}void outputLL(LinkList L) //输出LinkList{ LinkList p; cout << '[' << L->data << ']'; p = L->next; while (p && p->next) { cout << p->data << "-"; p = p->next; } if (p) cout << p->data << endl;}void deleteLL(LinkList L) //释放LinkList{ LinkList c = L; while (L) { L = L->next; delete(c); c = L; }}//--------------------------------------解答--//T1: 判断表里有没有e这个元素bool HasElem(LinkList L, int e) { LinkList p=L->next; while(p){ //相等即找到 if(p->data==e) { return true; } p=p->next; } return false;}//T2: 算法2.15 线性表的合并(链表)//将所有在线性表LB中但不在LA中的数据元素插入到LA中void unionLinkList(LinkList &LA, LinkList LB) { LinkList p,q; p=LA->next;q=LB->next; /* //找到链表A的末尾 while(p->next){p=p->next;} while(q){ if(!HasElem(LA,q->data)){ LinkList t=new LNode; t->data=q->data; p->next=t; LA->data++; } q=q->next; }*/ //往前插 while(q){ if(!HasElem(LA,q->data)){ ListInsert(LA,1,q->data); } q=q->next; } // deleteLL(LB);}//T3: 判断两张单链表是否完全相等bool equal(LinkList LA, LinkList LB){ //长度不同直接返回 if(LA->data!=LB->data) return false; LinkList a,b; a=LA->next;b=LB->next; while(a&&b){ if(a->data!=b->data) return false; a=a->next;b=b->next; } return true;}//T4: 判断两张单链表的内容是否一致bool contains(LinkList LA, LinkList LB){ //a指向长链,b指向短链 LinkList a,b; if(LA->data >= LB->data){a=LA;b=LB;} else{a=LB;b=LA;} //关键一步 b=b->next; while(b){ if(!LocateElem(a,b->data)) return false; b=b->next; } return true; }//T5: 在带头结点的单链表L中,删除所有的元素evoid deleteAll(LinkList &L, int e) { LinkList p=L->next; LinkList pre=L; while(p){ if(p->data==e){ pre->next=p->next; L->data--; }else{ pre=p; } p=p->next; }}int main() { LinkList LA, LB;//* T1 初始化LA InitLinkList(LA); //输入LA inputLL(LA); cout << HasElem(LA, 2) << endl; deleteLL(LA);//*///*T2 InitLinkList(LA); inputLL(LA); InitLinkList(LB); inputLL(LB); unionLinkList(LA, LB); outputLL(LA); deleteLL(LA); deleteLL(LB);//*///* T3 InitLinkList(LA); inputLL(LA); InitLinkList(LB); inputLL(LB); cout << equal(LA, LB) << endl; deleteLL(LA); deleteLL(LB);//*///* T4 InitLinkList(LA); inputLL(LA); InitLinkList(LB); inputLL(LB); D(outputLL(LA)); D(outputLL(LB)); cout << contains(LA, LB) << endl; deleteLL(LA); deleteLL(LB);//*///* T5 InitLinkList(LA); inputLL(LA); deleteAll(LA, 2); outputLL(LA); deleteLL(LA);//*/ return 0;}