一.线性表的定义
1.线性表是一个具有相同特性的数据元素的有限序列。
2.线性表中所含元素的个数叫做线性表的长度,用n表示,n≥0。n=0时,表示线性表是一个空表,即表中不包含任何元素。
3.线性表的逻辑表示为:(a1,a2,…,ai,ai+1,…,an)
4.线性表是客观事物的抽象。
二.线性表的运算
1.线性表的9个基本运算:
①初始化线性表InitList(&L):构造一个空的线性表L。
②销毁线性表DestroyList(&L):释放线性表L占用的内存空间。
③判线性表是否为空表ListEmpty(L):若L为空表,则返回真,否则返回假。
④求线性表的长度ListLength(L):返回L中元素个数n。
⑤输出线性表DispList(L):线性表L不为空时,顺序显示L中各结点的值域。
⑥求线性表L中指定位置的某个数据元素GetElem(L,i,&e):用e返回L中第 i(1≤i≤n)个元素的值。
⑦定位查找LocateElem(L,e):返回L中第一个值域与e相等的逻辑位序。若这样的元素不存在,则返回值为0。
⑧插入一个数据元素ListInsert(&L,i,e):在L的第i(1≤i≤n)个元素之前插入新的元素e,L的长度增1。
⑨删除数据元素ListDelete(&L,i,&e):删除L的第i(1≤i≤n)个元素,并用e返回其值,L的长度减1。
2.线性表的作用
①程序员可以直接使用它来存放数据,作为存放数据的容器。
②程序员可以直接使用它的基本运算,完成更复杂的功能。
3.线性表的知识结构
①线性表的概念:线性表ADT=逻辑结构+ 基本运算
②线性表的存储结构:Ⅰ.顺序存储结构:顺序表
Ⅱ.链式存储结构:单链表,双链表,循环链表
③线性表的应用
④特殊的线性表—有序表
三.线性表的顺序存储结构
1.线性表的顺序存储—顺序表
线性表的顺序存储结构:把线性表中的所有元素按照顺序存储方法进行存储。
线性表(a1,a2,…,ai,…an)
2.顺序表运算的实现
①建立顺序表
void CreateList(SqList *&L,ElemType a[],int n)
//整体建立顺序表
{ int i;
L=(SqList *)malloc(sizeof(SqList));
for (i=0;i<n;i++)
L->data[i]=a[i];
L->length=n;
}
②初始化线性表InitList(L)
void InitList(SqList *&L)
{ L=(SqList *)malloc(sizeof(SqList));
//分配存放线性表的顺序表空间
L->length=0;
}
③销毁线性表DestroyList(L)
void DestroyList(SqList *&L)
{
free(L);
}
④判定是否为空表ListEmpty(L)
bool ListEmpty(SqList *L)
{
return(L->length==0);
}
⑤求线性表的长度ListLength(L)
int ListLength(SqList *L)
{
return(L->length);
}
⑥输出线性表DispList(L)
void DispList(SqList *L)
{ int i;
if (ListEmpty(L)) return;
for (i=0;i<L->length;i++)
printf("%c",L->data[i]);
printf("\n");
}
⑦求某个数据元素值GetElem(L,i,e)
bool GetElem(SqList *L,int i,ElemType &e)
{
if (i<1 || i>L->length) return false;
e=L->data[i-1];
return true;
}
⑧按元素值查找LocateElem(L,e)
int LocateElem(SqList *L, ElemType e)
{ int i=0;
while (i<L->length && L->data[i]!=e)
i++;
if (i>=L->length) return 0;
else return i+1;
}
⑨插入数据元素ListInsert(L,i,e)
bool ListInsert(SqList *&L,int i,ElemType e)
{ int j;
if (i<1 || i>L->length+1)
return false; //参数错误时返回false
i--; //将顺序表逻辑序号转化为物理序号
for (j=L->length;j>i;j--) //将data[i..n]元素后移一个位置
L->data[j]=L->data[j-1];
L->data[i]=e; //插入元素e
L->length++; //顺序表长度增1
return true; //成功插入返回true
}
⑩删除数据元素ListDelete(L,i,e)
bool ListDelete(SqList *&L,int i,ElemType &e)
{ int j;
if (i<1 || i>L->length) //参数错误时返回false
return false;
i--; //将顺序表逻辑序号转化为物理序号
e=L->data[i];
for (j=i;j<L->length-1;j++) //将data[i..n-1]元素前移
L->data[j]=L->data[j+1];
L->length--; //顺序表长度减1
return true; //成功删除返回true
}
四.线性表的链式存储结构
1.线性表的链式存储—链表
每个物理结点增加一个指向后继结点的指针域 ---单链表。
每个物理结点增加一个指向后继结点的指针域和一个指向前驱结点的指针域 ---双链表。
存储密度:指结点数据本身所占的存储量和整个结点结构中所占的存储量之比。
一般地,存储密度越大,存储空间的利用率就越高。显然,顺序表的存储密度为1(100%),而链表的存储密度小于1。
2.单链表
单链表中结点类型LinkNode的定义
typedef struct LNode //定义单链表结点类型
{ ElemType data;
struct LNode *next; //指向后继结点
} LinkNode;
单链表的特点:当访问过一个结点后,只能接着访问它的后继结点,而无法访问它的前驱结点。
3.双链表
在线性表的链式存储结构中,每个物理结点增加一个指向后继结点的指针域和一个指向前驱结点的指针域 ---双链表。
双链表的优点:从任一结点出发可以快速找到其前驱结点和后继结点;
从任一结点出发可以访问其他结点。
4.循环链表
循环单链表:将表中尾结点的指针域改为指向表头结点,整个链表形成一个环。由此从表中任一结点出发均可找到链表中其他结点。
循环双链表:形成两个环。
①循环单链表
与非循环单链表相比,循环单链表:链表中没有空指针域
p所指结点为尾结点的条件:p->next==L
②循环双链表
与非循环双链表相比,循环双链表:链表中没有空指针域
p所指结点为尾结点的条件:p->next==L
一步操作即L->prior可以找到尾结点