链表:
顺序由各对象的指针决定,可以灵活的表示动态集合,但效率不及数组高,形式如下图所示:
next[x]指向链表中x的下一个元素,prev[x]指向上一个元素,head[L]指向第一个元素,若head[L]=NULL,则该链表为空。
程序中使用的是双向链表。
#include <stdio.h>
#include <stdlib.h>
//链表中的每一个元素,包含一个值x,一个指向前驱的指针prev以及指向后继的指针next
typedef struct Node
{
int x;
struct Node* prev;
struct Node* next;
}Node;
//链表结构,只包含指向第一个元素的指针,初始化时设置为NULL
typedef struct List
{
Node* first;
}List;
//链表的查询,从第一个元素开始依次往下即可
Node* List_Search(List L,int k)
{
Node* N=L.first;
while(N!=NULL&&N->x!=k)
N=N->next;
return N;
}
//链表的插入操作,需要判断边界条件
//假设链表一开始是空的话,只需要将第一个头指针给他即可
void List_Insert(List* L,Node* N)
{
(*N).next=(*L).first;
if((*L).first!=NULL)
(*L).first->prev=N;
(*L).first=N;
(*N).prev=NULL;
}
//链表的删除操作,需要调用List_Search找到该元素的指针,同样注意边界条件
void List_Delete(List* L,int k)
{
Node* N=List_Search(*L,k);
if(N!=NULL)
{
if(N->prev!=NULL)
N->prev->next=N->next;
else
L->first=N->next;
if(N->next!=NULL)
N->next->prev=N->prev;
}
else
printf("链表中不存在该元素\n");
}
//主函数进行测试
int main()
{
List L={first:NULL};
Node N1={x:1,prev:NULL,next:NULL};
Node N2={x:2,prev:NULL,next:NULL};
Node N3={x:3,prev:NULL,next:NULL};
List_Insert(&L,&N1);List_Insert(&L,&N2);List_Insert(&L,&N3);
Node* NP;
NP=List_Search(L,4);
if(NP!=NULL)
printf("查找数据%d成功\n",NP->x);
else
printf("查找失败\n");
List_Delete(&L,2);
List_Delete(&L,2);
return 0;
}
可以看到,无论是插入操作,还是删除操作,都需要考虑到边界条件,那么,有没有什么办法可以忽略边间条件直接对链表进行操作呢?
带哨兵的环形双向链表:
如图,哨兵元素nil[L]介于头和尾之间,空链表只包含一个哨兵元素。
操作与原来差不多,附上源代码:
#include <stdio.h>
#include <stdlib.h>
//元素类型依旧是结构体内的数据成员以及两个指针
//不同的是不需要首指针而是通过设置哨兵也就是讲一个元素放置在首部构成循环链表
//这个哨兵的区别方式是数据成员x的值为0,那么该元素为哨兵节点
typedef struct Node
{
int x;
struct Node* prev;
struct Node* next;
}Node;
Node* List_Search(Node* Nil,int k)
{
Node* N=Nil->next;
while(N!=Nil&&N->x!=k)
N=N->next;
return N;
}
void List_Insert(Node* Nil,Node* N)
{
N->next=Nil->next;
Nil->next->prev=N;
Nil->next=N;
N->prev=Nil;
}
//不需要判别边界条件,只需两行代码就可以解决
void List_Delete(Node* Nil,int k)
{
Node* NP=List_Search(Nil,k);
if(NP->x!=0)
{
NP->prev->next=NP->next;
NP->next->prev=NP->prev;
}
else
printf("链表中不存在该元素\n");
}
//主函数进行测试
int main()
{
Node Nil={x:0,prev:&Nil,next:&Nil};//不要忘记哨兵的初始化方式!
Node N1={x:1,prev:NULL,next:NULL};
Node N2={x:2,prev:NULL,next:NULL};
Node N3={x:1,prev:NULL,next:NULL};
List_Insert(&Nil,&N1);List_Insert(&Nil,&N2);List_Insert(&Nil,&N3);
Node* NP;
NP=List_Search(&Nil,2);
if(NP->x!=0)
printf("查找数据%d成功\n",NP->x);
else
printf("查找失败\n");
List_Delete(&Nil,2);
NP=List_Search(&Nil,2);
if(NP->x!=0)
printf("查找数据%d成功\n",NP->x);
else
printf("查找失败\n");
return 0;
}