1.带头双向循环链表
带头链表的头结点实际为“哨兵位 ”,哨兵位节点不存储任何有效元素,只是再放哨。
带头链表中,除了头结点,其他节点都存储有效得的数据。
实际中我们用的最多的还是单链表、和双向链表(带头双向循环链表)。
双向链表的节点结构:数据+指向后面节点的指针+指向前面节点的指针
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//双向链表的创建
typedef int LTdatatyp;typedef struct ListNode
{LTdatatyp data;struct ListNode* next;//指向后面struct ListNode* prev;//前面节点}LTNode ;
1.1双向链表的初始化
大家来思考一下这里的双向链表能不能为空,
答案是不能,
来猜测一下这样写是正确的吗?
因为next 和perv都要指向一个节点所以为NULL是不可以的。这里让他们指向newnode即可
当双向链表为空的时候:只有一个节点就是头结点。
下面调试一下来看看哨兵创建成功没。
1.2双向链表的尾插
传一级 或者二级指针是要看phead是否会改变,改变传地址 用** 接收, 不改变传一直指针即可。
尾插大概可以这样来修改next 、prev节点
代码大概是这样的,下面我们来测试一下
1.3双向链表的头插
这里的头插不是在哨兵位头插,而是在哨兵位后面进行头插。
下面的代码就是头插,
大概就是这样
1.4双向链表的打印
打印的结果就如下
1.5双向链表的尾删
这里的图可以了解一下。
上面的LTEmpty 是链表不为空
尾删后的结果如下:
1.6双向链表的头删
1.7 双向链表的查找
双向链表的查找和前面的单链表的查找类似,
1.8在pos位置之后插入节点
下面是在3的后面插入23
1.9删除pos位置的结点
Find 返回的值是3 ,删除的值就是3
销毁链表
大家可以进行调试来看看链表的销毁
那么讲到这里的话我们的双向链表就结束了。加油!!
List.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//双向链表的创建typedef int LTdatatyp;typedef struct ListNode
{ LTdatatyp data;struct ListNode* next;//指向后面struct ListNode* prev;//前面节点}LTNode ;//初始化void ListInit(LTNode** pphead);//创建新的空间LTNode* LTBuyNode(LTdatatyp x);//尾插void LTPushback(LTNode* phead,LTdatatyp x);//头插void LTPushFront(LTNode* phead, LTdatatyp x);//打印void LTPrint(LTNode* phead);//bool LTEmpty(LTNode* phead);//尾删void LTPopback(LTNode* phead);//头删void LTPopFront(LTNode* phead);//查找数据LTNode* LTFind(LTNode* phead, LTdatatyp x);//pos后插入数据void LTInsert(LTNode* pos, LTdatatyp x);//删除pos节点void LTErase(LTNode* pos);//销毁链表void LTDesTroy(LTNode** pphead);
List.c
#include "List.h"
LTNode* LTBuyNode(LTdatatyp x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc fail");exit(1);}newnode->data = x;newnode->next = newnode->prev = newnode ;return newnode;
}void ListInit(LTNode** pphead)
{//创建一个头节点(哨兵位)*pphead = LTBuyNode(-1);}
//尾插
void LTPushback(LTNode* phead,LTdatatyp x)//这里的插入为什么不用 * *phead 呢 这是因为头结点不会改变,
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->next = phead;// newnode的next 与phead连接newnode->prev = phead->prev;//与 最后一个数据连接newnode的 头指针phead->prev->next = newnode; //插入newnodephead->prev = newnode;}void LTPushFront(LTNode* phead, LTdatatyp x)
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;}void LTPrint(LTNode* phead)
{assert(phead);LTNode* pcur = phead ->next;//这里的pcur不能等于哨兵点while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");}
//判断有效数据的第一个是否为空
bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;
}
//尾删
void LTPopback(LTNode* phead)
{assert(phead);assert(! LTEmpty(phead));LTNode* del = phead->prev;LTNode* prev = del->prev;prev->next = phead;phead->prev = prev;free(del);del = NULL;}
//头删
void LTPopFront(LTNode* phead)
{assert(phead);assert(!LTEmpty(phead));LTNode* del = phead->next;del->next->prev = phead;phead->next = del->next;free(del);del = NULL;}
//查找数据
LTNode* LTFind(LTNode* phead, LTdatatyp x)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead)//pcur不等于头指针{if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;}//pos后插入数据
void LTInsert (LTNode* pos, LTdatatyp x)
{assert(pos);LTNode* newnode = LTBuyNode(x); newnode->next = pos->next;newnode->prev = pos;pos->next = newnode;pos->next->prev = newnode;
}//删除指定位置pos节点
void LTErase(LTNode* pos)
{assert(pos);pos->prev->next = pos->next;pos->next->prev = pos->prev;free(pos);pos =NULL;}
//销毁链表
void LTDesTroy(LTNode** pphead)
{assert(pphead &&*pphead );//头结点也不能为空LTNode* pcur = (*pphead)->next;while (pcur != *pphead){LTNode* Next = pcur->next;free(pcur);pcur = Next;}//销毁头结点free(*pphead);*pphead = NULL;pcur = NULL;
}
text.c
#include "List.h"
void Listext01()
{LTNode* plist = NULL;ListInit(&plist);//尾插LTPushback(plist, 1);LTPushback(plist, 2);LTPushback(plist, 3);LTPushback(plist, 4);//头插/*LTPushFront(plist, 1);LTPrint(plist);LTPushFront(plist, 2);LTPrint(plist);LTPushFront(plist, 3);LTPrint(plist);LTPushFront(plist, 4);LTPrint(plist);*///尾删/*LTPopback(plist);LTPrint(plist);LTPopback(plist);LTPrint(plist);LTPopback(plist);LTPrint(plist);*///头删//LTPopFront(plist);//LTPrint(plist);//LTPopFront(plist);//LTPrint(plist);//LTPopFront(plist);//LTPrint(plist);//LTPopFront(plist);LTPrint(plist);//查找LTNode* Find = LTFind(plist, 4);//if (Find == NULL)//{// printf("找不到了\n");//}//else// printf("找到了\n");//指定位置后插入//LTInsert(Find, 23);//LTPrint(plist);//删除指定位置数据//LTErase(Find);//LTPrint(plist);//销毁链表LTDesTroy(&plist);LTPrint(plist);LTDesTroy(&plist);LTPrint(plist);LTDesTroy(&plist);LTPrint(plist);LTDesTroy(&plist);LTPrint(plist);}
int main()
{Listext01();return 0;
}