带头循环双向链表详解 2

简介: 带头循环双向链表详解

2.6尾删节点

没什么好说的,和之前的一样关键点在链接上,自己画了图什么都知道

void list_popback(listnode*phead)
{
  assert(phead);
  if (phead->next == phead)
  {
    printf("链表为空,操作失败\n");//为空就别删了
    return;
  }
  listnode* tail = phead->prev;//找到尾节点
  phead->prev = tail->prev;
  tail->prev->next = phead;
  free(tail);
}

测试代码:

void test4()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  list_pushfront(plist, 10086);
  print_list(plist);
  list_popback(plist);
  print_list(plist);
  list_popback(plist);
  print_list(plist);
  list_popback(plist);
  print_list(plist);
  list_popback(plist);
  print_list(plist);
}
int main()
{
  test4();
}


测试效果:


f7e17e8ef8374655aedcbff2c8db3205.png


2.7查找节点

遍历一遍,找不到就返回NULL即可

listnode* list_find(listnode* phead, LTDateType x)
//哨兵节点和目标
{
  assert(phead);
  listnode* head = phead->next;//找到头节点
  while (head!=phead)//相等意味着已经遍历完了
  {
    if (head->data == x)
    //找到目标,直接返回
    {
      return head;
    }
    head = head->next;
  }
  return NULL;//遍历完还找不到,返回空指针
}

2.8在指定位置前插入节点

根据目标进行链接即可

void list_insert(listnode*pos,LTDateType x)
//目标位置,和在其前面插入数据为x的节点
{
  if (pos == NULL)//传空意味着没找到目标
  {
    printf("目标不存在,操作失败\n");
    return;
  }
  listnode*newnode=buy_listnode(x);//创建新节点
  newnode->next = pos;
  newnode->prev= pos->prev;
  pos->prev->next = newnode;
  pos->prev = newnode;
}

测试代码:

void test5()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  list_pushfront(plist, 10086);
  print_list(plist);
  listnode*pos=list_find(plist,2);
  list_insert(pos, 888);//在2之前插入888
  print_list(plist);
  list_insert(plist->next, 666);
  //在头节点前插入666,与头插效用一致
  //可以在头插中复用这个函数
  print_list(plist);
  list_insert(plist, 520);
  //在哨兵节点前插入520,与尾插效用一致
  //可以在尾插中复用这个函数
  print_list(plist);
}
int main()
{
  test5();
}


测试效果:

539c746f44b547fbaeb33edd8e56376a.png


2.9删除指定位置节点.

void list_erase(listnode* pos)
{
  assert(pos && pos->next != pos);
    //pos为空意味着不存在,pos->next==pos意味着为哨兵节点
  pos->next->prev = pos->prev;
  pos->prev->next = pos->next;
  free(pos);
}

测试代码:

void test6()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  //list_erase(plist->prev);//尾删,测试报错
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  list_pushfront(plist, 3);
  list_pushfront(plist, 4);
  list_pushfront(plist, 5);
  print_list(plist);
  listnode* pos = list_find(plist, 2);
  list_erase(pos);//把2删除
  print_list(plist);
  list_erase(plist->next);//头删
  print_list(plist);
  list_erase(plist->prev);//尾删
  print_list(plist);
}
int main()
{
  test6();
}


测试效果:


ddbe8be6909b4ad6a9f9adc86613bd53.png


2.10摧毁链表

void destory_list(listnode* phead)
{
  listnode* tail = phead->prev;
  while (tail != phead)
  {
    listnode* tmp = tail;//存储尾
    tail = tail->prev;//从后往前遍历
    free(tmp);
    //不需要管什么链接了,直接摧毁就行
  }
  free(phead);//单独摧毁
}

测试代码:

void test7()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  //list_erase(plist->prev);//尾删,测试报错
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  list_pushfront(plist, 3);
  list_pushfront(plist, 4);
  list_pushfront(plist, 5);
  destory_list(plist);
}
int main()
{
  test7();
}

测试效果:


从监视来看,确实全部释放


878b199ed833423c870d041549860c4b.png


三、全部代码

1.接口头文件

#pragma once//防止头文件二次引用
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDateType;
//这样创建结构体数据类型,不仅是为了和int做区分
//也是为了到时更好的替换,想换直接把int改了就行
typedef struct listnode
{
  struct listnode* prev;//存放上一个节点的地址
  struct listnode* next;//存放下一个节点的地址
  LTDateType data;//该节点存放的数据
}listnode;
listnode* buy_listnode(LTDateType x);
listnode* init_listnode(listnode* phead);
void print_list(listnode* phead);
void list_pushback(listnode* phead, LTDateType x);
void list_pushfront(listnode* phead, LTDateType x);
void list_popfront(listnode* phead);
void list_popback(listnode* phead);
listnode* list_find(listnode* phead, LTDateType x);
void list_insert(listnode* pos, LTDateType x);
void list_erase(listnode* pos);
void destory_list(listnode* phead);


2.接口实现

#define _CRT_SECURE_NO_WARNINGS 1
#include"list.h"
listnode* buy_listnode(LTDateType x)
{
  listnode*newnode=(listnode*)malloc(sizeof(listnode));
  if (newnode == NULL)
  {
    perror("buy_listnode");//错误提示
    exit(-1);//节点都没创建出来,直接退出程序
  }
  newnode->data = x;//将新节点的数据初始化成我们需要的
  newnode->next = NULL;//不清楚插入的方式,先初始化成空
  newnode->prev = NULL;
}
listnode* init_listnode(listnode* phead)
{
  phead = buy_listnode(-1); //-1是随便给的,初始化哨兵节点中的数据为-1,代表着没意义的数据
  phead->next = phead;//初始化哨兵节点,自己指向自己
  phead->prev = phead;
  return phead;
}
void print_list(listnode* phead)
{
  assert(phead);//哨兵节点地址不可能为空
  listnode* head = phead->next;
  //哨兵位节点不存储有效数据,因此phead->next才是头节点
  printf("head<=>");//纯属美观
  while (head != phead)//当head和phead相等意味着已经遍历完一遍链表
  {
    printf("%d<=>", head->data);
    head = head->next;
  }
  printf("\n");
}
void list_pushback(listnode*phead,LTDateType x)
//尾插一个新节点,此节点存储x
{
  listnode* newnode = buy_listnode(x);
  //创建一个我们需要的新节点
  listnode* tail = phead->prev;
  //先找尾,尾很显然是哨兵位节点的上一个节点
  tail->next = newnode;
  newnode->prev = tail;
  newnode->next = phead;
  phead->prev = newnode;
}
void list_pushfront(listnode* phead, LTDateType x)
{
  listnode* head = phead->next;//找到头节点
  listnode* newnode = buy_listnode(x);//创建新节点
  head->prev = newnode;
  newnode->next = head;
  phead->next = newnode;
  newnode->prev = phead;
}
void list_popfront(listnode*phead)
{
  assert(phead);
  if (phead->next == phead)
  {
    printf("链表为空,操作失败\n");//为空就别删了
    return;
  }
  listnode* head = phead->next;//找到头节点
  phead->next = head->next;
  head->next->prev = phead;
  free(head);//链接完成,彻底删除
}
void list_popback(listnode*phead)
{
  assert(phead);
  if (phead->next == phead)
  {
    printf("链表为空,操作失败\n");//为空就别删了
    return;
  }
  listnode* tail = phead->prev;//找到尾节点
  phead->prev = tail->prev;
  tail->prev->next = phead;
  free(tail);
}
listnode* list_find(listnode* phead, LTDateType x)
//哨兵节点和目标
{
  assert(phead);
  listnode* head = phead->next;//找到头节点
  while (head!=phead)//相等意味着已经遍历完了
  {
    if (head->data == x)
    //找到目标,直接返回
    {
      return head;
    }
    head = head->next;
  }
  return NULL;//遍历完还找不到,返回空指针
}
void list_insert(listnode*pos,LTDateType x)
//目标位置,和在其前面插入数据为x的节点
{
  if (pos == NULL)//传空意味着没找到目标
  {
    printf("目标不存在,操作失败\n");
    return;
  }
  listnode*newnode=buy_listnode(x);//创建新节点
  newnode->next = pos;
  newnode->prev= pos->prev;
  pos->prev->next = newnode;
  pos->prev = newnode;
}
void list_erase(listnode* pos)
{
  assert(pos && pos->next != pos);
  pos->next->prev = pos->prev;
  pos->prev->next = pos->next;
  free(pos);
}
void destory_list(listnode* phead)
{
  listnode* tail = phead->prev;
  while (tail != phead)
  {
    listnode* tmp = tail;//存储尾
    tail = tail->prev;//从后往前遍历
    free(tmp);
    //不需要管什么链接了,直接摧毁就行
  }
  free(phead);//单独摧毁
}

3.测试文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"list.h"
void test1()
{
  listnode* plist=NULL;
  plist=init_listnode(plist);
  list_pushback(plist,1);
  list_pushback(plist,2);
  list_pushback(plist,3);
  list_pushback(plist,4);
  print_list(plist);
}
void test2()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  print_list(plist);
  list_pushfront(plist, 10086);
  print_list(plist);
}
void test3()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  print_list(plist);
  list_pushfront(plist, 10086);
  print_list(plist);
  list_popfront(plist);
  print_list(plist);
  list_popfront(plist);
  print_list(plist);
  list_popfront(plist);
  print_list(plist);
  list_popfront(plist);
  print_list(plist);
}
void test4()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  list_pushfront(plist, 10086);
  print_list(plist);
  list_popback(plist);
  print_list(plist);
  list_popback(plist);
  print_list(plist);
  list_popback(plist);
  print_list(plist);
  list_popback(plist);
  print_list(plist);
}
void test5()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  list_pushfront(plist, 10086);
  print_list(plist);
  listnode*pos=list_find(plist,2);
  list_insert(pos, 888);//在2之前插入888
  print_list(plist);
  list_insert(plist->next, 666);
  //在头节点前插入666,与头插效用一致
  //可以在头插中复用这个函数
  print_list(plist);
  list_insert(plist, 520);
  //在哨兵节点前插入520,与尾插效用一致
  //可以在尾插中复用这个函数
  print_list(plist);
}
void test6()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  //list_erase(plist->prev);//尾删,测试报错
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  list_pushfront(plist, 3);
  list_pushfront(plist, 4);
  list_pushfront(plist, 5);
  print_list(plist);
  listnode* pos = list_find(plist, 2);
  list_erase(pos);//把2删除
  print_list(plist);
  list_erase(plist->next);//头删
  print_list(plist);
  list_erase(plist->prev);//尾删
  print_list(plist);
}
void test7()
{
  listnode* plist = NULL;
  plist = init_listnode(plist);
  //list_erase(plist->prev);//尾删,测试报错
  list_pushfront(plist, 1);
  list_pushfront(plist, 2);
  list_pushfront(plist, 3);
  list_pushfront(plist, 4);
  list_pushfront(plist, 5);
  destory_list(plist);
}
int main()
{
  test7();
}

好了,今天的分享到这里就结束了,感谢各位友友来访,祝各位友友前程似锦O(∩_∩)O


相关文章
|
4月前
|
存储 算法 C语言
C语言手撕实战代码_循环单链表和循环双链表
本文档详细介绍了用C语言实现循环单链表和循环双链表的相关算法。包括循环单链表的建立、逆转、左移、拆分及合并等操作;以及双链表的建立、遍历、排序和循环双链表的重组。通过具体示例和代码片段,展示了每种算法的实现思路与步骤,帮助读者深入理解并掌握这些数据结构的基本操作方法。
|
8月前
特殊链表(循环单链表,循环双链表,静态链表)
特殊链表(循环单链表,循环双链表,静态链表)
63 3
|
8月前
|
存储
【数据结构】【版本1.2】【线性时代】——链表之王(双向带头循环)
【数据结构】【版本1.2】【线性时代】——链表之王(双向带头循环)
带头循环双向链表详解 1
带头循环双向链表详解
图文版实现无头非循环单链表的增加和删除操作
图文版实现无头非循环单链表的增加和删除操作
不带头非循环的单向链表的增删查改的实现(代码版)
不带头非循环的单向链表的增删查改的实现(代码版)
|
8月前
|
Python Go Java
Golang每日一练(leetDay0042) 二叉树最大路径和、回文串、单词接龙II
Golang每日一练(leetDay0042) 二叉树最大路径和、回文串、单词接龙II
59 0
Golang每日一练(leetDay0042) 二叉树最大路径和、回文串、单词接龙II
|
8月前
|
Python C++ Java
C/C++每日一练(20230405) 数组元素循环右移、输出字符图形、移除链表元素
C/C++每日一练(20230405) 数组元素循环右移、输出字符图形、移除链表元素
52 0
C/C++每日一练(20230405) 数组元素循环右移、输出字符图形、移除链表元素
|
8月前
|
存储 缓存 程序员
手撕【双向链表】带头双向循环(2)
手撕【双向链表】带头双向循环(2)
38 0
|
存储 算法
数据结构单链表之检测和删除链表中的循环 | 第十三套
数据结构单链表之检测和删除链表中的循环 | 第十三套
59 0

热门文章

最新文章