一、基本概念
- 线性表:由n(n>=0)个数据特性相同的元素构成的有限序列称为线性表。线性表中元素的个数n定义为线性表的长度,n=0时称为空表。
- 顺序表:是线性表的顺序存储结构的一种别称。
- 特点:是以“存储位置相邻”表示两个元素之间的前驱、后继关系。
- 优点:是可以随机存取表中任意一个元素。
- 缺点:是每作一次插入或删除操作时,平均来说必须移动表中一半元素。 常应用于主要是为查询而很少作插入和删除操作,表长变化不大的线性表。
- 链表:是线性表的链式存储结构的别称。
- 特点:是以“指针”指示后继元素,因此线性表的元素可以存储在存储器中任意一组存储单元中。
- 优点:是便于进行插入和删除操作。
- 缺点:是不能进行随机存取,每个元素的存储位置都存放在其前驱元素的指针域中,为取得表中任意一个数据元素都必须从第一个数据元素起查询。
二、线性表的表示与实现
1、顺序表示和实现
#include <iostream> using namespace std; //顺序表的存储结构,ElemType假设为int #define MAXSIZE 100 typedef struct{ int *elem; int length; }SqList; //顺序表的初始化 bool InitList(SqList &list){ list.elem =new int[MAXSIZE]; list.length=0; return true; }; //顺序表的取值 bool GetElem(SqList list,int i,int &e){ if(i<1||i>list.length){ return false; } else{ e=list.elem[i-1]; return true; } } //顺序表的插入,将e插入位置i bool ListInsert(SqList &list,int i,int e){ if(i<1||(i>list.length+1)){ return false; } else if(list.length==MAXSIZE){ return false; } else{ int len = list.length; for (int j = (len-1); j >=(i-1); j--) { list.elem[j+1]=list.elem[j]; } list.elem[i-1]=e; list.length++; return true; } } //顺序表的删除 bool ListDelete(SqList &list,int i){ if (i<1||i>(list.length+1)){ return false; }else{ int len = list.length; for (int j = i-1; j <=len-1 ; j++) { list.elem[j]=list.elem[j+1]; } list.length--; return true; } } //顺序表的输出 void ListDisplay(SqList sqList){ for (int i = 0; i < sqList.length; ++i) { cout<< sqList.elem[i]; } cout<<endl; } ``` ## 2、链式表示和实现 ```cpp #include <iostream> #define ElemType int #define OK true #define ERROR false #define Status bool typedef struct LNode { ElemType data; struct LNode* next; }LNode, * LinkList; //单链表的初始化,构造一个空的单链表 Status InitList(LinkList& L) { L = (LinkList)malloc(sizeof(LinkList)); L->next = NULL; return OK; } //在带头结点的单链表L中第i个位置之前插入元素e Status ListInsert(LinkList& L, int i, int e) { LinkList p = L; int j = 0; while (p && j < (i - 1)) { p = p->next; j++; } if (!p||j>i-1){ return ERROR; } LinkList s = (LinkList)malloc(sizeof(LinkList)); s->data = e; s->next = p->next; p->next = s; return OK; } //单链表的删除,在带头结点的单链表L中,删除第i个元素 Status ListDelete(LinkList& L, int i) { LinkList p = L; LinkList q; int j = 0; while (p && j < i - 1) { p = p->next; j++; } if (!p || j > i - 1) { return ERROR; } q = p->next; p->next = q->next; free(q); return OK; } //在带头结点的单链表L中根据序号i获取元素的值,用e返回 void GetElem(LinkList& L, int i, int& e) { LinkList p = L->next; int j = 1; while (j < i && p) { p = p->next; j++; } e = p->data; } //头插法创建带头结点的单链表 void createList_H(LinkList& L, int n) { L = (LinkList)malloc(sizeof(LinkList)); L->next = NULL; LinkList p; for (int i = 0; i < n; ++i) { p = (LinkList)malloc(sizeof(LinkList)); scanf_s("%d",&p->data); p->next = L->next; L->next = p; } } //尾插法创建带头结点的单链表 void createList_R(LinkList& L, int n) { L = new LNode; L->next = NULL; LinkList p, rear=L; for (int i = 0; i < n; ++i) { p = (LinkList)malloc(sizeof(LinkList)); scanf_s("%d", &p->data); p->next = NULL; rear->next = p; rear = p; } } //在带头结点的单链表中查找值为e的元素 LinkList LocateElem(LinkList L, int e) { LinkList p = L->next; while (p->data != e) { p = p->next; } return p; } //单链表的遍历 void displayList(LinkList L) { while (L != NULL) { L = L->next; printf("%d ",L->data); } } //已知单链表La和Lb的元素按值非递减排列 //归并La和Lb得到新的单链表Lc,元素也按值非递减排列 void MergeList_L(LinkList& La, LinkList& Lb,LinkList& Lc) { LinkList pa, pb,pc; pa = La->next; pb = pb->next; Lc = pc = La; //用La的头结点作为Lc的头结点 while (pa&&pb){ if (pa->data<=pb->data){ pc->next = pa; pc = pa; pa = pa->next; } else{ pc->next = pb; pc = pb; pb = pb->next; } } pc->next = pa ? pa : pb; free(Lb); //释放Lb的头结点 } int main() { std::cout << "Hello World!\n"; }
顺序表和链表的比较
三、循环链表、双向链表
1、循环链表
>循环链表是另一种形式的链式存储结构。其特点是表中的最后一个结点的指针指向头结点。整个链表形成一个环。由此,从表中的任一结点出发均可找到表中其他结点。
>循环单链表的操作和单链表基本一致,差别仅在于:当链表遍历时,判别当前指针p是否指向表尾结点得到终止条 件不同。在单链表中,判断条件为p!=NULL或p->next!=NULL,而循环单链表的判别条件为p!=L或p->next!=L
在某些情况下,若在循环链表中设立尾指针而不设头指针,可使一些操作简化。例如,将两个线性表合并成一个表时,仅需将第一个表的尾指针指向第二个表的第一个结点,第二个表的尾指针指向第一个表的头结点,然后释放第二个表的头结点。(“第一个结点”指头结点所指的结点)
这个操作仅需改变两个指针值即可。
LinkList Connect(LinkList Ta,LinkList Tb) {//假设Ta、Tb都是非空的单循环链表 p = Ta->next; //①p存表头结点 Ta->next = Tb->next->next; //②Tb表头连结Ta表尾 delete Tb->next; //③释放Tb表头结点 return Tb;//④修改指针 return Tb; }
2、双向链表
//双向链表的存储结构 typedef struct DuLNode{ ElemType data; struct DuLNode *prior; struct DuLNode *next; }DuLNode, *DuLinkList
//在带头结点的双向循环链表L中第i个位置之前插入元素e Status ListInsert_DuL(DuLinkList &L,int i,ElemType e){ if(!(p=GetElemP_DuL(L,i))) return ERROR; s= (DuLinkList)malloc(sizeof(DuLinkList)); s->data=e; s->prior=p->prior; p->prior->next=s; s->next=p; p->prior=s; return OK; }
//删除带头结点的双向循环链表L的第i个元素 Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e){ if(!(p=GetElemP_DuL(L,i))) return ERROR; e=p->data; p->prior->next=p->next; p->next->prior=p->prior; free(p); return OK; }