1 初始化链表
ListNode* ListNodeCreat(LTDataType x) { ListNode* newnode = (ListNode*)malloc(sizeof(ListNode)); if (newnode) { newnode->data = x; newnode->next = NULL; newnode->prev = NULL; } return newnode; } ListNode* InitList(void) { ListNode* phead = ListNodeCreat(1); phead->next = phead; phead->prev = phead; return phead; }
链表的初始化我们将phead的prev与next都指向phead,这里的处理在后面有一些妙用,这里就先不说了,头结点这里是通过返回值实现的,当然,通过二级指针也可以,效果都差不多。头结点是不存储数据的,只是充当哨兵的作用。
2 尾插和头插
尾插的具体代码:
void ListPushBack(ListNode* phead, LTDataType x) { assert(phead); ListNode* tail = phead->prev; ListNode* newtail = ListNodeCreat(x); tail->next = newtail; newtail->prev = tail; newtail->next = phead; phead->prev = newtail; //ListInsert(phead, x); }
尾插的实现很简单,都能够看懂。在这里我们就可以看见将phead的prev与next都指向phead的好处了,就算phead后面一个结点都没有依然能够处理,这样写代码就很简练了。
头插的具体代码:
void ListPushFront(ListNode* phead, LTDataType x) { assert(phead); ListNode* next = phead->next; ListNode* newnode = ListNodeCreat(x); phead->next = newnode; newnode->prev = phead; newnode->next = next; next->prev = newnode; //ListInsert(phead->next, x); }
头插的实现也比较简单,其实把图画好就能够解决问题,这里当头结点后面一个结点都没有也能够处理。
来看看效果:
3 尾删和头删
尾删和头删对于双链表来说也比较简单,这里就放在一起写了:
void ListPopBack(ListNode* phead) { assert(phead); ListNode* tail = phead->prev; ListNode* prev = tail->prev; prev->next = phead; phead->prev = prev; free(tail); //ListErase(phead->prev); } void ListPopFront(ListNode* phead) { assert(phead); ListNode* next = phead->next->next; free(phead->next); phead->next = next; next->prev = phead; //ListErase(phead->next); }
按部就班的写,注意不要写漏了就ok了。
效果:
4 查找和查插和查删)
查找的具体代码:
ListNode* ListFind(ListNode* phead, LTDataType x) { assert(phead); ListNode* cur = phead->next; while (cur != phead) { if (cur->data == x) { return cur; } else { cur = cur->next; } } return NULL; }
与单链表一样,这个也可以改变数据:
查插的具体代码:
void ListInsert(ListNode* pos, LTDataType x) { assert(pos); ListNode* prev = pos->prev; ListNode* newnode = ListNodeCreat(x); prev->next = newnode; newnode->prev = prev; newnode->next = pos; pos->prev = newnode; }
这里是在pos位前面插入数据,实现起来也比较简单。
查删的具体代码:
void ListErase(ListNode* pos) { assert(pos); ListNode* prev = pos->prev; ListNode* next = pos->next; prev->next = next; next->prev = prev; free(pos); }
有了查删和查插后我们不难发现,头插和尾插都可以用查插实现,头删和尾删都可以用查删实现。
头插在 phead->next前插入,尾插在phead前插入,头删位置为phead->next,尾删位置为phead->prev.
在上面实现代码的时候注释掉的就是这种方法。
5 释放
void ListDestroy(ListNode* phead) { ListNode* cur = phead; ListNode* next = phead->next; while (cur->next!=phead) { free(cur); cur = next; next = next->next; } }
释放链表与单链表差不多,比较容易理解。
好了,今天的分享就到这里了,如果该文对你有帮助的话能不能3连支持一下博主呢?