双向带头循环链表
Posted 别碰我的宏定义
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双向带头循环链表相关的知识,希望对你有一定的参考价值。
双向带头循环链表:
特点,带头,循环,双向,可以在任意位置插入,除了初始化和销毁需要修改头节点的内容外,其他时候不需要动头指针。
大概就是下面这么个玩意,图画的有点丑,
根据这个图就可以看出这个链表的基本组成结构了,两个指针域一个数据域,类型完成定义了就将创建节点的函数也一定定义好
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}ListNode;
// 创建链表节点
ListNode* ListCreate(LTDataType date)
{
ListNode *node = (ListNode *)malloc(sizeof(ListNode));
if (node == NULL)
{
printf("节点申请失败\\n");
assert(0);
}
node->next = NULL;
node->prev = NULL;
node->data = date;
return node;
}
基本的类型定义完成后,就需要来初始化了,先把头节点创好
注意头节点的两个指针,不能指向空,在没有元素的时候指向本身
,需要让链表循环起来
//初始化头节点
void ListInit(ListNode **Head)
{
assert(Head != NULL);
*Head = ListCreate(0);
(*Head)->next = *Head;
(*Head)->prev = *Head;
}
头插添加新节点:有头节点了,接下来就要实现他的一些关于链表的基本功能了
先把申请的节点挂在链表上,再动链表的指针,不然指针就可能玩飞了。
然后将node的next的prev指针指向node,后一个节点的前指针就挂好了,再将前一个指针的后一个指针挂好,节点添加即可完成。
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead != NULL);
ListNode *node = ListCreate(x);
node->prev = pHead;
node->next = pHead->next;
node->next->prev = node;
pHead->next = node;
}
尾插肯定少不了和头插一样也是先挂链,再动原链表的指针
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
assert(pHead != NULL);
ListNode *node = ListCreate(x);
node->prev = pHead->prev;
node->next = pHead;
node->prev->next = node;
pHead->prev = node;
}
插入完了,调一个打印函数来看看是不是成功插入,注意,犹豫期是循环链表,遍历链表,开始的元素是头节点的下一个,结束的元素是头节点
// 双向链表打印
void ListPrint(ListNode* pHead)
{
assert(pHead != NULL);
ListNode *node = pHead->next;
if (node == pHead)
{
printf("链表已空,无元素\\n");
return ;
}
while (node!= pHead)
{
printf("%d ", node->data);
node = node->next;
}
printf("\\n");
}
尾删链表元素:1.判空,为空则不可操作,2.动态申请的内存必须要free掉
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
assert(pHead != NULL);
ListNode *node = pHead->prev;
if (node == pHead)
{
printf("链表已空,不可操作\\n");
return;
}
pHead->prev = node->prev;
node->prev->next = pHead;
free(node);
}
双向链表头删链表元素:1.判链表空(头指针的next和prev指针是否都指向自己),为空则不可操作,2.动态申请的内存必须要free掉
// 双向链表头删
void ListPopFront(ListNode* pHead)
{
assert(pHead != NULL);
ListNode *node = pHead->next;
if (node == pHead)
{
printf("链表已空,不可操作\\n");
return;
}
pHead->next = node->next;
node->next->prev = node->prev;
free(node);
}
双向循环链表查找
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead != NULL);
ListNode *node = pHead->next;
if (node == pHead)
{
printf("没有元素,不可查找\\n");
return NULL;
}
while (node != pHead)
{
if (node->data == x)
return node;
node = node->next;
}
return NULL;
}
void display(ListNode *node)
{
if (node)
printf("%d\\n", node->data);
else
printf("Not Find\\n");
}
双向循环链表的某个位置元素删除,单向的只能删除其位置之后的元素。双向的就可以删除本位置的元素。
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
assert(pos != NULL);
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
free(pos);
}
把他们整理到一起
#LTNode_H_
#pragma once
#include<stdio.h>
#include<windows.h>
#include<assert.h>
#include<stdlib.h>
// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}ListNode;
// 创建返回链表的头结点.
ListNode* ListCreate();
//带头双相链表的初始化
void ListInit(ListNode **Head);
// 双向链表销毁
void ListDestory(ListNode **pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
//节点查找结果显示
void display(ListNode *node);
void test2();
附上功能模块代码
#include"HTNode.h"
// 创建链表节点
ListNode* ListCreate(LTDataType date)
{
ListNode *node = (ListNode *)malloc(sizeof(ListNode));
if (node == NULL)
{
printf("节点申请失败\\n");
assert(0);
}
node->next = NULL;
node->prev = NULL;
node->data = date;
return node;
}
//初始化头节点
void ListInit(ListNode **Head)
{
assert(Head != NULL);
*Head = ListCreate(0);
(*Head)->next = *Head;
(*Head)->prev = *Head;
}
// 双向链表销毁
void ListDestory(ListNode **Head)
{
assert((*Head) != NULL);
ListNode *node = (*Head)->next;
while (node != (*Head))
{
ListPopFront(*Head);
node = (*Head)->next;
}
free(*Head);
}
// 双向链表打印
void ListPrint(ListNode* pHead)
{
assert(pHead != NULL);
ListNode *node = pHead->next;
if (node == pHead)
{
printf("链表已空,无元素\\n");
return ;
}
while (node!= pHead)
{
printf("%d ", node->data);
node = node->next;
}
printf("\\n");
}
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead != NULL);
ListNode *node = ListCreate(x);
node->prev = pHead;
node->next = pHead->next;
node->next->prev = node;
pHead->next = node;
}
// 双向链表头删
void ListPopFront(ListNode* pHead)
{
assert(pHead != NULL);
ListNode *node = pHead->next;
if (node == pHead)
{
printf("链表已空,不可操作\\n");
return;
}
pHead->next = node->next;
node->next->prev = node->prev;
free(node);
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
assert(pHead != NULL);
ListNode *node = ListCreate(x);
node->prev = pHead->prev;
node->next = pHead;
node->prev->next = node;
pHead->prev = node;
}
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
assert(pHead != NULL);
ListNode *node = pHead->prev;
if (node == pHead)
{
printf("链表已空,不可操作\\n");
return;
}
pHead->prev = node->prev;
node->prev->next = pHead;
free(node);
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead != NULL);
ListNode *node = pHead->next;
if (node == pHead)
{
printf("没有元素,不可查找\\n");
return NULL;
}
while (node != pHead)
{
if (node->data == x)
return node;
node = node->next;
}
return NULL;
}
void display(ListNode *node)
{
if (node)
printf("%d\\n", node->data);
else
printf("Not Find\\n");
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode *node = ListCreate(x);
node->prev = pos->prev;
node->next = pos;
pos->prev->next = node;
pos->prev = node;
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
assert(pos != NULL);
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
free(pos);
}
void test2()
{
ListNode *Head;
ListInit(&Head);
ListPushBack(Head, 10);
ListPushBack(Head, 9);
ListPushBack(Head, 8);
ListPushBack(Head, 7);
ListPushBack(Head, 6);
ListPrint(Head);
display(ListFind(Head, 10));
display(ListFind(Head, 12));
ListInsert(ListFind(Head, 10), 12);
ListPrint(Head);
ListErase(ListFind(Head, 12));
ListPrint(Head);
ListPopBack(Head);
ListPrint(Head);
ListPopBack(Head);
ListPrint(Head);
ListPopBack(Head);
ListPrint(Head);
ListPopBack(Head);
ListPrint(Head);
ListPopBack(Head);
ListPrint(Head);
ListPopBack(Head);
ListPushFront(Head, 10);
ListPushFront(Head, 9);
ListPushFront(Head, 8);
ListPushFront(Head, 7);
ListPushFront(Head, 6);
ListPrint(Head);
ListDestory(&Head);
}
贴上主函数
#include"HTNode.h"
int main()
{
//test1();
test2();
system("pause");
return 0;
}
有不完善的地方,希望大家多多指点。
以上是关于双向带头循环链表的主要内容,如果未能解决你的问题,请参考以下文章