线性表(List):零个或多个数据元素的有限序列。
一般复杂操作基本可以用基本操作组合而成,比如GetElem、LocateElem、ListInsert、ListDelete、ListLength等。
顺序存储结构—顺序表
用一段地址连续的存储单元依次存储线性表的数据元素。比如C语言的一维数据。结构图示:
顺序存储结构的缺点是插入和删除时需要移动大量元素。
一般操作示例:
#define MAXSIZE 20
typedef int ElemType; /*元素类型假设为int*/
typedef struct
{
ElemType data[MAXSIZE]; /*数组的长度,开辟存储空间长度,一般不变,初动态分配数组*/
int length; /*线性表当前长度,数据元素的个数,随着插入删除操作变化着*/
}SqList;
/*取数组L中第i个元素给e*/
void GetElem(SqList L, int i, ElemType *e)
{
if (L.length == 0 || i<1 || i>L.length)
return;
*e = L.data[i - 1];
}
/*在第i个元素前插入新的元素e,L的长度增加1*/
void ListInsert(SqList *L, int i, ElemType e)
{
int k;
if (L->length == MAXSIZE || i<1 || i>L->length + 1)
return;
if (i <= L->length) /*插入位置不在表尾时,把后面的元素均向后移动一位*/
{
for (k = L->length - 1; k >= i - 1; k--)
L->data[k + 1] = L->data[k];
}
L->data[i - 1] = e;
L->length++;
}
/*删除L的第i个元素,其值给e,长度减1*/
void ListDelete(SqList *L, int i, ElemType *e)
{
int k;
if (L->length == 0 || i<1 || i>L->length)
return;
*e = L->data[i - 1];
if (i < L->length) /*删除的不是最后元素,后面元素向前移*/
{
for (k = i; k < L->length; k++)
L->data[k - 1] = L->data[k];
}
L->length--;
}
链式存储结构—链表
用一组任意的存储单元存储数据元素,这些存储单元可以是连续的,也可以是不连续的。
这就是链表。存储单元就是结点(Node)。结点 = 数据域 + 指针域(指示后继的存储位置),结构图示为:
以下是链表的几种:
单链表
单链表的结构(左)和 空链表的结构(右):
一般操作示例:
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node *LinkList;
/*取链表中第i个数据元素的值给e*/
void GetElem(LinkList L, int i, ElemType *e)
{
LinkList p; /*声明一结点p*/
p = L->next; /*让p指向链表L的第一个结点*/
int j;
j = 1; /*计数器j*/
while (p && j<i) /*p不为空且j还没有到i*/
{
p = p->next;
++j;
}
if (!p || j>i)
return; /*第i个元素不存在*/
*e = p->data;
}
/*在链表L中第i个位置之前插入新的元素e,L长度加1*/
void ListInsert(LinkList *L, int i, ElemType e)
{
LinkList p, s;
p = *L;
int j;
j = 1;
while (p && j<i)
{
p = p->next;
++j;
}
if (!p)
return; /*第i个结点不存在*/
s = (LinkList)malloc(sizeof(Node));
s->data = e;
s->next = p->next;
p->next = s;
}
/*删除L的第i个元素,用e返回其值,L的长度减1*/
void ListDelete(LinkList *L, int i, ElemType *e)
{
LinkList p, q;
p = *L;
int j;
j = 1;
while (p->next && j<i)
{
p = p->next;
++j;
}
if (!p->next) /*没有第i个元素*/
return;
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
}
循环链表
循环链表是头尾相接的单链表。结构图示:
或
上图中,终端结点用【尾指针rear】指示,头结点是 rear->next,第一个结点是 rear->next->next
合并操作示例:
p = rearA->next;
rearA->next = rearB->next->next; /*将A的尾端指向B的第一个结点(不是头结点)*/
rearB->next = p; /*将B的尾端指向A的头结点*/
free(p);
双向链表
双向链表就是单链表的结点中多加了一个指向前驱结点的指针。结构图示:
删除结点操作示例:
typedef struct DulNode
{
ElemType data;
struct DulNode *prior; /*前驱指针*/
struct DulNode *next; /*后继指针*/
}DulNode, *DuLinkList;
/*双向链表的删除操作*/
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);