因为一篇文章着实塞不下,线性表的内容是如此的多,更进一步说明了线性表在数据结构这门学科中的地位。在此主要是对线性表的链式存储这个知识点作进一步的探究。
结点是线性表的组成单位,当结点中只有数据域的时候,多个结点构成的是顺序表,而当结点中还有指针域的时候,多个结点构成的是线性链表。在实际中,数据往往比我们想象的要更加复杂,前文讨论的指针域只有一个的情况,当指针域有多个的时候会发生什么样的化学反应呢?
一、一个指针域
结构特点:
多个结点构成的结果:
1、顺序链表
2、循环链表
当链表的最后一个指针域不为NULL,而是指向标头结点时,可构成循环链表
注:
循环链表的运算与线性链表基本一致。但两者循环条件(判断是否到表尾的条件)不同:
线性表:判断某结点的指针域是否为空。
循环链表:判断某结点的指针域值是否等于头指针。
关于算法:
上文已有一定的介绍,在此不再赘述。
二、两个指针域:
结构特点:
多个结点构成的结果:
特点:1、
对双向循环链表中任一结点的指针有:
p == p→prior→next == p→next→prior
2、置空双向循环链表:p->prior=p;p->next=p;
关于算法:
1、双向链表的存储结构:
typedef struct DuLNode{
ElemType data;
struct DuLNode *prior;
struct DuLnode *next;
}DuLNode, * DuLinkList;
DuLinkList GetElemP_DuL(DuLinkList va, int i) {
// L为带头结点的单链表的头指针。
// 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
DuLinkList p;
p = va->next;
int j = 1; // 初始化,p指向第一个结点,j为计数器
while (p!=va && j<i) { //顺指针向后查找,直到p指向第i个元素或p为空
p = p->next;
++j;
}
if (p==va || j<i) return NULL; // 第i个元素不存在
else return p;
} // GetElem_L
3、双向循环链表中插入元素:
Status ListInsert_DuL(DuLinkList &L, int i, ElemType e) {
// 在带头结点的双链循环线性表L的第i个元素之前插入元素e,
// i的合法值为1≤i≤表长+1。
DuLinkList p,s;
if (!(p = GetElemP_DuL(L, i))) // 在L中确定第i个元素的位置指针p
return ERROR; // p=NULL, 即第i个元素不存在
if (!(s = (DuLinkList)malloc(sizeof(DuLNode))))
return ERROR;
s->data = e;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
return OK;
} // ListInsert_DuL
4、双向循环链表中删除元素:
Status ListDelete_DuL(DuLinkList &L, int i, ElemType &e) {//算法2.19
// 删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i≤表长
DuLinkList p;
if (!(p = GetElemP_DuL(L, i))) // 在L中确定第i个元素的位置指针p
return ERROR; // p=NULL, 即第i个元素不存在
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return OK;
} // ListDelete_DuL
具体代码实现(C)
#include<string.h>
#include<ctype.h>
#include<malloc.h> /* malloc()等 */
#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
typedef struct DuLNode
{
int data;
struct DuLNode *prior,*next;
}DuLNode,*DuLinkList;
int InitList(DuLinkList *L)
{ /* 产生空的双向循环链表L */
*L=(DuLinkList)malloc(sizeof(DuLNode));
if(*L)
{
(*L)->next=(*L)->prior=*L;
return 1;
}
else
return -2;
}
int ListLength(DuLinkList L)
{ /* 初始条件:L已存在。操作结果:返回L中数据元素个数 */
int i=0;
DuLinkList p=L->next; /* p指向第一个结点 */
while(p!=L) /* p没到表头 */
{
i++;
p=p->next;
}
return i;
}
int GetElem(DuLinkList L,int i,int *e)
{ /* 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */
int j=1; /* j为计数器 */
DuLinkList p=L->next; /* p指向第一个结点 */
while(p!=L&&j<i) /* 顺指针向后查找,直到p指向第i个元素或p指向头结点 */
{
p=p->next;
j++;
}
if(p==L||j>i) /* 第i个元素不存在 */
return 0;
*e=p->data; /* 取第i个元素 */
return 1;
}
int ListInsert(DuLinkList L,int i,int e) /* 改进算法2.18 */
{ /* 在带头结点的双链循环线性表L中第i个位置之前插入元素e,i的合法值为1≤i≤表长+1 */
DuLinkList p,s;
if(i<1||i>ListLength(L)+1) /* i值不合法 */
return 0;
s=(DuLinkList)malloc(sizeof(DuLNode));
if(!s)
return -2;
s->data=e; /* 在第i-1个元素之后插入 */
s->prior=p;
s->next=p->next;
p->next->prior=s;
p->next=s;
return 1;
}
int ListDelete(DuLinkList L,int i,int *e) /* 算法2.19 */
{ /* 删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i≤表长+1 */
DuLinkList p;
if(i<1||i>ListLength(L)) /* i值不合法 */
return 0;
p=GetElem(L,i); /* 在L中确定第i个元素的位置指针p */
if(!p) /* p=NULL,即第i个元素不存在 */
return 0;
*e=p->data;
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
return 1;
}
void ListTraverse(DuLinkList L,void(*visit)(int))
{ /* 由双链循环线性表L的头结点出发,正序对每个数据元素调用函数visit() */
DuLinkList p=L->next; /* p指向头结点 */
while(p!=L)
{
visit(p->data);
p=p->next;
}
printf("\n");
}
void visit(int c)
{
printf("%d ",c);
}
void main()
{
LinkList L;
int e;
int j;
int i;
i=InitList(&L); /* 初始化单循环链表L */
printf("初始化单循环链表L i=%d (1:初始化成功)\n",i);
ListInsert(&L,1,3); /* 在L中依次插入3,5 */
ListInsert(&L,2,5);
i=GetElem(L,1,&e);
j=ListLength(L);
printf("L中数据元素个数=%d,第1个元素的值为%d。\n",j,e);
printf("L中的数据元素依次为:");
ListTraverse(L,visit);
i=ListDelete(&L,2,&e);
printf("删除L的第2个元素:\n");
if(i)
{
printf("删除的元素值为%d,现在L中的数据元素依次为:",e);
ListTraverse(L,visit);
}
else
printf("删除不成功!\n");
}