赞
踩
上一节详解了
不带头结点的单向链表,通过单向链表我们虽然可以完成链表的基本操作,但是如果需要添加、删除尾结点等,我们时间复杂度会成为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 <stdio.h> #include <stdlib.h> 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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。