一、基本概念
- 线性表:由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;
}