双向链表
双向链表也称双链表,每个数据结点都有两个指针,分别指向直接前驱和直接后继。所以从双向链表的任何结点开始都可以方便的找到他的前驱和后继。
双向链表的每个结点如图所示:
双向链表由N个此类结点构成:
定义双向链表(C语言):包括前驱,后继,还有数据
typedef struct Node{
struct Node *prior;
Element data;
struct Node *next;
}Node;
typedef struct Node * ListNode;
复制代码
接下来,创建一个双向链表:
思路:
1.创建一个首元结点(为了方便操作,不用经常挪动头指针)
2.在链表中加入数据(单纯的为了后面的操作方便,也可以先初始化,之后再插数据)
复制代码
初始化代码如下
Status creatListNode(ListNode *L){
*L = (ListNode)malloc(sizeof(Node));
if (!(*L)) return ERROR;
(*L)->data = 0;
(*L)->prior = NULL;
(*L)->next = NULL;
//初始化这里直接增加数据,可以方便查询
ListNode p = *L;
for (int i = 0; i<5; i++) {
ListNode temp = (ListNode)malloc(sizeof(Node));
temp->next = NULL;
temp->prior = NULL;
temp->data = i;
p->next = temp;
temp->prior = p;
p = p->next;
}
return OK;
}
复制代码
为了方便操作调试,加了个打印链表的方法:
void printListNode(ListNode L){
printf("打印链表\n");
ListNode temp = L->next;
if (temp == NULL) {
printf("打印链表为空\n");
return;
}
while (temp) {
printf("%d\t",temp->data);
temp = temp->next;
}
printf("\n");
}
复制代码
下面说下插入结点:
思路:
1、首先找到插入结点的位置。
2、是不是在链表尾部(这个就直接看代码就好了)
3、temp的next指向p的next
4、p的next的prior指向temp
5、p的next指向temp
6、temp的prior指向p
如下图所示:
复制代码
Status insertListNode(ListNode *L, int place, Element data){
ListNode p = *L;
//1. 插入的位置不合法 为0或者为负数
if(place < 1) return ERROR;
ListNode temp = (ListNode)malloc(sizeof(Node));
temp->data = data;
temp->prior = NULL;
temp->next = NULL;
//找到前驱 p
for (int i = 1;i < place && p; i++) {
p = p->next;
}
//灭有
if(p==NULL) return ERROR;
//尾部
if (p->next == NULL) {
p->next = temp;
temp->prior = p;
}else{
//插入
temp->next = p->next;
p->next->prior = temp;
temp->prior = p;
p->next = temp;
}
return OK;
}
复制代码接下来是删除代码:
老规矩--思路:
1、找到要删除位置的前一个
2、p的next指向要删除结点的next
3、删除结点的next的prior指向p
4、看下面的图(已经很生动了。。)
复制代码
代码:
Status deleteListNode(ListNode *L, int place){
if(place < 0) return ERROR;
ListNode p = *L;
int i;
for (i = 1; i
p = p->next;
}
if (place>i || p == NULL) {
return ERROR;
}
//要删除的结点
ListNode deleTemp = p->next;
printf("要删除的值为:%d\n",deleTemp->data);
//删除
p->next = deleTemp->next;
if (deleTemp->next != NULL) {
deleTemp->next->prior = p;
}
free(deleTemp);
return OK;
}
复制代码
双向链表的查找:
思路:
简单来说就是把值传过来,然后遍历,找一样的。。
复制代码
还是直接上代码吧
Status searchListNode(ListNode L, Element data){
int j = 0;
ListNode p = L->next;
for (int i = 1;p != NULL ; i++) {
if (p->data == data) {
printf("此数值存在,位置是%d\n",i);
j = 1;
break;
}
p = p->next;
}
if (j == 0) {
printf("没有发现此数值\n");
}
return OK;
}
复制代码
给大家看下main函数:
printf("双向链表\n");
ListNode L;
Status iStatus;
int place;
Element value;
//创建双向链表
printf("创建双向链表\n");
iStatus = creatListNode(&L);
printListNode(L);
//插入
printf("输入插入元素的位置和值,中间用空格隔开\n");
scanf("%d %d",&place,&value);
iStatus = insertListNode(&L,place,value);
printListNode(L);
//删除
printf("输入删除的位置\n");
scanf("%d",&place);
iStatus = deleteListNode(&L, place);
printListNode(L);
//删除指定元素
printf("删除指定元素\n");
scanf("%d",&value);
iStatus = deleData(&L, value);
printListNode(L);
//查找
printf("查找元素\n");
scanf("%d",&value);
iStatus = searchListNode(L, value);
复制代码
控制台输出:
双向链表
创建双向链表
打印链表
01234
输入插入元素的位置和值,中间用空格隔开
1 99
打印链表
9901234
输入删除的位置
1
要删除的值为:99
打印链表
01234
删除指定元素
4
打印链表
0123
查找元素
3
此数值存在,位置是4
复制代码
ok,双向链表就告一段落了。开始双向循环链表,
双向循环链表
双向循环链表和双向链表的区别简单理解就是首尾相连了。
正常的双向循环链表:
上图所示,大家应该理解双向循环链表是什么样子了。
接下来创建双向循环链表:
Status createListNode(ListNode *L){
*L = (ListNode)malloc(sizeof(Node));
if (!(*L)) return ERROR;//么有创建成功。。(这种情况基本不会存在,但是考虑代码严谨性,我还是写上了。。)
(*L)->data = 0;
(*L)->next = (*L);
(*L)->prior = (*L);
ListNode p = (*L);
//我加点数据
for (int i = 1; i < 11; i++) {
ListNode temp = (ListNode)malloc(sizeof(Node));
temp->data = i;
p->next = temp;
temp->prior = p;
temp->next = (*L);
(*L)->prior = temp;
p = p->next;
}
return OK;
}
复制代码
然后--双向循环链表的插入:
双向循环链表的插入和双向链表的插入差不多,就是要注意下首尾情况
废话我就不说了。直接上代码:
复制代码Status insertListNode(ListNode *L, int place, Element data){
//是否合法
if (place<0) return ERROR;
ListNode p = *L;
int i;
for (i = 1; p->next != *L && i < place; i++) {
p = p->next;
}
if (i > place) return ERROR;
//创建新结点
ListNode tempNode = (ListNode)malloc(sizeof(Node));
//6.temp 结点为空,则返回error
if (tempNode == NULL) return ERROR;
tempNode->data = data;
tempNode->next = p->next;
p->next->prior = tempNode;
p->next = tempNode;
tempNode->prior = p;
return OK;
}
复制代码
双向循环链表的删除
同样类似于双向链表,注意下首尾情况即可。
代码如下:
复制代码Status deleListNode(ListNode *L, int place){
int i;
ListNode p = (*L)->next;
if (*L == NULL) {
return ERROR;
}
if (p->next == (*L)) {
free(*L);
(*L) = NULL;
return OK;
}
for (i = 1; i < place; i++) {
p = p->next;
}
printf("要删除的数据是%d\n",p->data);
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return OK;
}
复制代码为了方便调试,写了个打印方法
复制代码void printListNode(ListNode L){
printf("打印链表\n");
if (L == NULL) {
printf("双向循环链表为空!\n");
return;
}
ListNode p = L->next;
for (int i=0; p != L; i++) {
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
复制代码
main方法:
printf("双向循环链表\n");
ListNode L;
Status iStatus;
int place;
Element data;
printf("创建链表\n");
iStatus = createListNode(&L);
printListNode(L);
printf("插入位置和数据中间空格隔开\n");
scanf("%d %d",&place,&data);
iStatus = insertListNode(&L, place, data);
printListNode(L);
printf("删除数据,输入删除的位置\n");
scanf("%d",&place);
iStatus = deleListNode(&L, place);
printListNode(L);
复制代码
输出如下:
双向循环链表
创建链表
打印链表
1 2 3 4 5 6 7 8 9 10
插入位置和数据中间空格隔开
1 99
打印链表
99 1 2 3 4 5 6 7 8 9 10
删除数据,输入删除的位置
2
要删除的数据是1
打印链表
99 2 3 4 5 6 7 8 9 10
复制代码