上一节详解了
不带头结点的单向链表,通过单向链表我们虽然可以完成链表的基本操作,但是如果需要添加、删除尾结点等,我们时间复杂度会成为O(n),并且在单向链表中我们无法直接得到结点的前驱,只能苦苦遍历。
与单向链表相比,带头结点双向循环链表可以很好的解决上述出现的问题,并且可以有效避免二级指针的问题。
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
想要完成双链表的增删查改,首先要建立一个正确的链表结构
双向 和 循环 是此链表的基本特点,所以会有一个前驱指针和一个后继指针以及数据域。
typedef int ElemType;
typedef struct ListNode
{
struct ListNode* next;
struct ListNode* prev;
ElemType data;
}ListNode;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这里很简单,我们就不做冗赘。
ListNode* CreatNode(ElemType x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->data = x;
newnode->prev = NULL;
newnode->next = NULL;
return newnode;
}
还是简单说一下,创建一个data = x 的结点之后,返回结点的地址。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
注意: 这里可以使用二级指针作为形参接受实参,因为我们这里需要在函数里修改头结点的值,所以我们实参进行址传递。
ListNode* ListInit()
{
ListNode* phead = CreatNode(0);
phead->next = phead;
phead->prev = phead;
return phead;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
创建新节点,链接前驱和后继。
//头插
void ListPushHead(ListNode* phead, ElemType x)
{
ListNode* newnode = CreatNode(x);
//保存第一个结点
ListNode* first = phead->next;
phead->next = newnode;
newnode->prev = phead;
newnode->next = first;
first->prev = newnode;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如果链表是空,直接返回。
void ListHeadDelt(ListNode* phead)
{
if (phead->next == phead)
{
return;
}
ListNode* first = phead->next;
ListNode* second = first->next;
phead->next = second;
second->prev = phead;
free(first);
first = NULL;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
尾结点就是头结点的前驱,尾结点的后继就是头结点。
void ListPushTail(ListNode* phead, ElemType x)
{
ListNode* tail = phead->prev;
ListNode* newnode = CreatNode(x);
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
寻找尾结点的前驱,跳过尾结点,链接新链表,free结点空间。
void ListTailDelt(ListNode* phead)
{
ListNode* tail = phead->prev;
//尾结点的前驱
ListNode* prev_tail = tail->prev;
prev_tail->next = phead;
phead->prev = prev_tail;
free(tail);
tail = NULL;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
遍历链表,找到结点就返回此结点的位置。
ListNode* ListFind(ListNode* phead, ElemType x)
{
ListNode* now = phead->next;
while (now != phead)
{
if (now->data == x)
{
return now;
}
now = now->next;
}
return NULL;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
创建一个新的结点并完成链表的双向链接特性。
void ListInsert(ListNode* pos, ElemType x)
{
ListNode* find_prev = pos->prev;
ListNode* newnode = CreatNode(x);
find_prev->next = newnode;
newnode->prev = find_prev;
newnode->next = pos;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
跳过删除的位置,链接链表
void ListDelt(ListNode* pos)
{
ListNode* find_prev = pos->prev;
find_prev->next = pos->next;
pos->next->prev = find_prev;
free(pos);
pos = NULL;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
循环的条件已经不是 != NULL ,而是 != 头结点 ,因为链表是双向循环的。
void ListDestory(ListNode* phead)
{
ListNode* now = phead->next;
while (now != phead)
{
ListNode* next = now->next;
free(now);
now = next;
}
free(phead);
phead = NULL;
return;
}
#pragma once
//带头结点的双向循环 链表
#include
#include
typedef int ElemType;
typedef struct ListNode
{
struct ListNode* next;
struct ListNode* prev;
ElemType data;
}ListNode;
//初始化
ListNode* ListInit();
//清空链表
void ListDestory(ListNode* phead);
//尾插
void ListPushTail(ListNode* phead, ElemType x);
//打印链表
void ListPrint(ListNode* phead);
//头插
void ListPushHead(ListNode* phead, ElemType x);
//头删
void ListHeadDelt(ListNode* phead);
//尾删
void ListTailDelt(ListNode* phead);
//随机插入 pos位置之前插入
void ListInsert(ListNode* pos, ElemType x);
//随机删除 pos位置删除
void ListDelt(ListNode* pos);
//查找
ListNode* ListFind(ListNode* phead, ElemType x);
#include "LinkList.h"
//创建空间
ListNode* CreatNode(ElemType x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->data = x;
newnode->prev = NULL;
newnode->next = NULL;
return newnode;
}
//初始化
ListNode* ListInit()
{
ListNode* phead = CreatNode(0);
phead->next = phead;
phead->prev = phead;
return phead;
}
//尾插
void ListPushTail(ListNode* phead, ElemType x)
{
ListNode* tail = phead->prev;
ListNode* newnode = CreatNode(x);
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
//ListInsert(phead, x);
}
//打印链表
void ListPrint(ListNode* phead)
{
ListNode* new = phead->next;
while (new != phead)
{
printf("%d->", new->data);
new = new->next;
}
printf("NULL\n");
}
//头插
void ListPushHead(ListNode* phead, ElemType x)
{
//ListNode* newnode = CreatNode(x);
保存第一个结点
//ListNode* first = phead->next;
//phead->next = newnode;
//newnode->prev = phead;
//newnode->next = first;
//first->prev = newnode;
ListInsert(phead->next,x);
}
//头删
void ListHeadDelt(ListNode* phead)
{
/*if (phead->next == phead)
{
return;
}
ListNode* first = phead->next;
ListNode* second = first->next;
phead->next = second;
second->prev = phead;
free(first);
first = NULL;*/
ListDelt(phead->next);
}
//尾删
void ListTailDelt(ListNode* phead)
{
//ListNode* tail = phead->prev;
尾结点的前驱
//ListNode* prev_tail = tail->prev;
//prev_tail->next = phead;
//phead->prev = prev_tail;
//free(tail);
//tail = NULL;
ListDelt(phead->prev);
}
//查找
ListNode* ListFind(ListNode* phead, ElemType x)
{
ListNode* now = phead->next;
while (now != phead)
{
if (now->data == x)
{
return now;
}
now = now->next;
}
return NULL;
}
//随机插入 pos位置之前插入
void ListInsert(ListNode* pos, ElemType x)
{
ListNode* find_prev = pos->prev;
ListNode* newnode = CreatNode(x);
find_prev->next = newnode;
newnode->prev = find_prev;
newnode->next = pos;
}
//随机删除 pos位置删除
void ListDelt(ListNode* pos)
{
ListNode* find_prev = pos->prev;
find_prev->next = pos->next;
pos->next->prev = find_prev;
free(pos);
pos = NULL;
}
//清空链表
void ListDestory(ListNode* phead)
{
ListNode* now = phead->next;
while (now != phead)
{
ListNode* next = now->next;
free(now);
now = next;
}
free(phead);
phead = NULL;
return;
}
#include "LinkList.h"
void TestList()
{
//初始化
ListNode* plist = ListInit();
//尾插
ListPushTail(plist, 5);
ListPushTail(plist, 6);
ListPushTail(plist, 7);
ListPushTail(plist, 8);
printf("尾插: ");
ListPrint(plist);
//头插
ListPushHead(plist, 4);
ListPushHead(plist, 3);
ListPushHead(plist, 2);
printf("头插: ");
ListPrint(plist);
//头删
ListHeadDelt(plist);
ListHeadDelt(plist);
printf("头删: ");
ListPrint(plist);
//尾删
ListTailDelt(plist);
printf("尾删: ");
ListPrint(plist);
//查找 随机插入
ListNode* pos = ListFind(plist, 5);
ListInsert(pos, 555);
printf("随机插入: ");
ListPrint(plist);
// 随机删除
pos = ListFind(plist, 7);
ListDelt(pos);
printf("随机删除: ");
ListPrint(plist);
//销毁链表
ListDestory(plist);
}
int main()
{
TestList();
return 0;
}