赞
踩
注意:
这⾥的“带头”跟前面我们说的“头节点”是两个概念,带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这里“放哨的”。
“哨兵位”存在的意义:遍历循环链表避免死循环。
//定义双向链表中节点的结构
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* prev;
struct ListNode* next;
}LTNode;
注意,双向链表是带有哨兵位的,插入数据之前链表中必须要先初始化一个哨兵位
void LTInit(LTNode** pphead)
{
*pphead = (LTNode*)malloc(sizeof(LTNode));
if (NULL == *pphead)
{
perror("malloc fail!");
exit(1);
}
(*pphead)->data = -1;
(*pphead)->next = (*pphead)->prev = *pphead;
}
也可以这样写:
LTNode* LTInit()
{
LTNode* phead = (LTNode*)malloc(sizeof(LTNode));
if (NULL == phead)
{
perror("malloc fail!");
exit(1);
}
phead->data = -1;
phead->next = phead->prev = phead;
return phead;
}
概念: 当链表中只有哨兵位节点的时候,我们称该链表为空链表;即哨兵位是不能删除的。
不需要改变哨兵位,则不需要传二级指针;如果需要修改哨兵位的话,则传二级指针。
LTNode* LTBuyNode(LTDataType x) { LTNode* newnode = (LTNode*)malloc(sizeof(LTNode)); if (NULL == newnode) { perror("malloc fail!"); exit(1); } newnode->data = x; newnode->next = newnode->prev = newnode; return newnode; } //尾插 void LTPushBack(LTNode* phead, LTDataType x) { assert(phead); LTNode* newnode = LTBuyNode(x); //phead phead->prev(ptail) newnode newnode->next = phead; newnode->prev = phead->prev; phead->prev->next = newnode; phead->prev = newnode; }
因为写了申请新节点的函数,所以上面的初始化代码可以优化:
LTNode* LTInit()
{
LTNode* phead = LTBuyNode(-1);
return phead;
}
void LTPrint(LTNode* phead)
{
//phead不能为空
assert(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 = LTBuyNode(x);
//phead newnode phead->next
newnode->next = phead->next;
newnode->prev = phead;
phead->next->prev = newnode;
phead->next = newnode;
}
//尾删 void LTPopBack(LTNode* phead) { assert(phead); //链表为空:只有一个哨兵位节点 assert(phead->next != phead);//若哨兵位节点的next指针或者prev指针指向的是自己,说明当前链表为空 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(phead->next != phead); LTNode* del = phead->next; LTNode* next = del->next; //phead del next next->prev = phead; phead->next = next; free(del); del = NULL; }
LTNode* LTFind(LTNode* phead, LTDataType x) { assert(phead); LTNode* pcur = phead->next; while (pcur != phead) { if (x == pcur->data) { return pcur; } pcur = pcur->next; } return NULL; }
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = LTBuyNode(x);
//pos newnode pos->next
newnode->next = pos->next;
newnode->prev = pos;
pos->next->prev = newnode;
pos->next = newnode;
}
//删除pos位置的数据
void LTErase(LTNode* pos)
{
assert(pos);
//pos->prev pos pos->next
pos->next->prev = pos->prev;
pos->prev->next = pos->next;
free(pos);
pos = NULL;
}
void LTDesTroy(LTNode** pphead) { assert(pphead); //哨兵位不能为空 assert(*pphead); LTNode* pcur = (*pphead)->next; while (pcur != *pphead) { LTNode* next = pcur->next; free(pcur); pcur = next; } //链表中只有一个哨兵位 free(*pphead); *pphead = NULL; }
也可以这样写:
void LTDesTroy(LTNode* phead) { //哨兵位不能为空 assert(phead); LTNode* pcur = phead->next; while (pcur != phead) { LTNode* next = pcur->next; free(pcur); pcur = next; } //链表中只有一个哨兵位 free(phead); phead = NULL; }
但是要注意:这样写要在调用完函数后再写一句 plist = NULL;
这两种写法我们更推荐第二种:推荐传一级指针**(保持接口一致性)**
完整代码:
//List.h #include <stdio.h> #include <stdlib.h> #include <assert.h> //定义双向链表中节点的结构 typedef int LTDataType; typedef struct ListNode { LTDataType data; struct ListNode* prev; struct ListNode* next; }LTNode; //注意,双向链表是带有哨兵位的,插入数据之前链表中必须要先初始化一个哨兵位 //void LTInit(LTNode** pphead); LTNode* LTInit(); //void LTDesTroy(LTNode** pphead); void LTDesTroy(LTNode* phead);//推荐传一级指针(保持接口一致性) void LTPrint(LTNode* phead); //概念:当链表中只有哨兵位节点的时候,我们称该链表为空链表;即哨兵位是不能删除的 //不需要改变哨兵位,则不需要传二级指针 //如果需要修改哨兵位的话,则传二级指针 void LTPushBack(LTNode* phead, LTDataType x); void LTPushFront(LTNode* phead, LTDataType x); //头删、尾删 void LTPopBack(LTNode* phead); void LTPopFront(LTNode* phead); //查找 LTNode* LTFind(LTNode* phead, LTDataType x); //在pos位置之后插入数据 void LTInsert(LTNode* pos, LTDataType x); //删除pos位置的数据 void LTErase(LTNode* pos);
//List.c #include "List.h" //void LTInit(LTNode** pphead) //{ // *pphead = (LTNode*)malloc(sizeof(LTNode)); // // if (NULL == *pphead) // { // perror("malloc fail!"); // exit(1); // } // // (*pphead)->data = -1; // (*pphead)->next = (*pphead)->prev = *pphead; //} LTNode* LTBuyNode(LTDataType x) { LTNode* newnode = (LTNode*)malloc(sizeof(LTNode)); if (NULL == newnode) { perror("malloc fail!"); exit(1); } newnode->data = x; newnode->next = newnode->prev = newnode; return newnode; } //LTNode* LTInit() //{ // LTNode* phead = (LTNode*)malloc(sizeof(LTNode)); // // if (NULL == phead) // { // perror("malloc fail!"); // exit(1); // } // // phead->data = -1; // phead->next = phead->prev = phead; // // return phead; //} LTNode* LTInit() { LTNode* phead = LTBuyNode(-1); return phead; } //尾插 void LTPushBack(LTNode* phead, LTDataType x) { assert(phead); LTNode* newnode = LTBuyNode(x); //phead phead->prev(ptail) newnode newnode->next = phead; newnode->prev = phead->prev; phead->prev->next = newnode; phead->prev = newnode; } //头插 void LTPushFront(LTNode* phead, LTDataType x) { assert(phead); LTNode* newnode = LTBuyNode(x); //phead newnode phead->next newnode->next = phead->next; newnode->prev = phead; phead->next->prev = newnode; phead->next = newnode; } void LTPrint(LTNode* phead) { //phead不能为空 assert(phead); LTNode* pcur = phead->next; while (pcur != phead) { printf("%d->", pcur->data); pcur = pcur->next; } printf("\n"); } //尾删 void LTPopBack(LTNode* phead) { assert(phead); //链表为空:只有一个哨兵位节点 assert(phead->next != phead);//若哨兵位节点的next指针或者prev指针指向的是自己,说明当前链表为空 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(phead->next != phead); LTNode* del = phead->next; LTNode* next = del->next; //phead del next next->prev = phead; phead->next = next; free(del); del = NULL; } LTNode* LTFind(LTNode* phead, LTDataType x) { assert(phead); LTNode* pcur = phead->next; while (pcur != phead) { if (x == pcur->data) { return pcur; } pcur = pcur->next; } return NULL; } //在pos位置之后插入数据 void LTInsert(LTNode* pos, LTDataType x) { assert(pos); LTNode* newnode = LTBuyNode(x); //pos newnode pos->next newnode->next = pos->next; newnode->prev = pos; pos->next->prev = newnode; pos->next = newnode; } //删除pos位置的数据 void LTErase(LTNode* pos) { assert(pos); //pos->prev pos pos->next pos->next->prev = pos->prev; pos->prev->next = pos->next; free(pos); pos = NULL; } //void LTDesTroy(LTNode** pphead) //{ // assert(pphead); // //哨兵位不能为空 // assert(*pphead); // // LTNode* pcur = (*pphead)->next; // // while (pcur != *pphead) // { // LTNode* next = pcur->next; // free(pcur); // pcur = next; // } // // //链表中只有一个哨兵位 // free(*pphead); // *pphead = NULL; //} void LTDesTroy(LTNode* phead) { //哨兵位不能为空 assert(phead); LTNode* pcur = phead->next; while (pcur != phead) { LTNode* next = pcur->next; free(pcur); pcur = next; } //链表中只有一个哨兵位 free(phead); phead = NULL; }
//Test.c #include "List.h" void ListTest01() { //LTNode* plist = NULL; //LTInit(&plist); LTNode* plist = LTInit(); //尾插 //LTPushBack(plist, 1); //LTPushBack(plist, 2); //LTPushBack(plist, 3); //LTPushBack(plist, 4); //LTPrint(plist); //头插 LTPushFront(plist, 1); LTPushFront(plist, 2); LTPushFront(plist, 3); LTPushFront(plist, 4); LTPrint(plist); //LTPopBack(plist); //LTPrint(plist); //LTPopBack(plist); //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); LTPopFront(plist); LTPrint(plist); LTNode* findRet = LTFind(plist, 3); //if (NULL == findRet) //{ // printf("未找到!\n"); //} //else //{ // printf("找到了!\n"); //} //在指定位置之后插入数据 //LTInsert(findRet, 66); //LTPrint(plist); //删除pos位置的节点 LTErase(findRet); LTPrint(plist); //LTDesTroy(&plist); LTDesTroy(plist); plist = NULL; } int main() { ListTest01(); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。