带头链表⾥的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这⾥“放哨的”。哨兵位存在的意义:避免链表出现死循环。
双向链表的结构:数据+指向下一个节点的指针+指向前一个节点的指针
typedef int LTDataType; typedef struct ListNode { LTDataType data; struct Listnode* prev; struct Listnode* next; }LTNode;
双向链表为空,只有一个头结点。
首先我们进行初始化:
void LTInit(LTNode**pphead);//双向链表的初始化 LTNode* LTBuyNode(LTDataType x) { LTNode*node=(LTNode*)malloc(sizeof(LTNode)); if(node==NULL) { perror("malloc fail"); exit(1); } node->data=x; node->next=node->prev=node; return node; } void LTPushBack(//插入链表之前,链表必须初始化到只有一个头节点的情况 { //给链表创建一个哨兵位 *pphead=LTBuyNode(-1); }
插入数据
首先我们要申请一个新的节点,再改变指针的指向。
void LTPushBack(LTNode* pphead,LTDataType x)//不改变头结点的位置,只用传一级指针就可以 { assert(phead);//首先头指针不能为空 //先把newnode插入链表,再改变原链表前驱节点和后继节点指针的指向 newnode->prev=phead->prev; newnode->next=phead; phead->prev->next=newnode;//先改变原头节点的前驱节点的后继节点 phead->prev=newnode; }
这个函数对空链表的情况也满足。
打印链表
void LTPrint(LTNode*phead) { LTNode*pcur=phead->next; while(pcur!=phead) { printf("%d->",pcur->data); pcur=pcur->next; } printf("\n"); }
头插
往头结点的后面插入
void LTPushFront(LTNode* phead,LTDataType x) { assert(phead); LTNode* newnode=BuyNode(x); newnode->next=phead->next; newnode->prev=head; phead->next->prev=newnode; phead->next=newnode; }
尾删
void LTPopBack(LTNode* phead) { //链表必须有效且链表不能为空 assert(phead&&phead->next!=phead); LTNode*del=phead->prev;//把头结点的上一个节点储存起来 del->prev->next=phead; phead->prev=del->prev; free(del); del=NULL: }
头删
void LTPopFront(LTNode* phead) { assert(phead&&phead->next!=phead); LTNode* del=phead->next; phead->next=del->next; del->next->prev=phead; free(del); del=NULL; }
在pos位置之后插入数据
void LTFind(LTNode* phead,LTDataType x) { LTNode*pcur=phead->next; while(pcur!=phead) { if(pcur->data==x) { return pcur; } pcur=pcur->next; } return NULL; }
void LTInsert(LTNode* pos,LTDataType x) { assert(pos); LTNode*newnode=LTBuyNode(x); newnode->next=pos->next; newnodeprev=pos; pos->next->prev=newnode; pos->next=newnode; }
LTInsert方法包含了头插
删除pos节点
void LTErase(LTNode* pos) { assert(pos); pos->next->prev=pos->prev; pos->prev->next=pos->next; free(pos); pos=NULL; }
销毁链表
void LTDestory(LTNode* phead) { assert(phead); LTNode* pcur=phead->next; while(pcur!=phead) { LTNode* next=pcur->next; free(pcur); pcur=next; } //此时pcur指向phead,而phead还没有被销毁 free(phead); phead=NULL; }