数据结构-带头双向链表的建立,详细教程
前言
上一篇文章中我们学习了单链表的实现 本节将带大家学习带头双向链表的实现,希望能够对大家有一些帮助,话不多说,直接开干!!
文章目录
- 前言
- 一、带头双向链表的概念和结构
- 二. 带头双向链表的接口实现
- 2.1 打印
- 2.2 初始化
- 2.3 开辟节点
- 2.4 尾部插入节点
- 2.5 尾部删除节点
- 2.6 头部插入节点
- 2.7 头部删除节点
- 2.8 查找
- 2.9 在Pos位置前插入
- 2.10 在Pos位置删除
- 2.11 销毁链表
- 总结
一、带头双向链表的概念和结构
概念:带头双向链表是一种 带不存储数据的哨兵卫,循环,双向的一种链表结构。它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。
特点:
- 在数据结构中具有双向指针
- 插入数据的时候方便找到上一个
- 同样,删除数据的是有也需要考虑前后方向的操作
和单链表的比较:
1.无头单向非循环链表:结构简单,但一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶,图的邻接表等等。另外,这种结构在笔试中出现很多。。
2.带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外,这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单。后面我们代码实现了就知道了。
看代码
typedef int LTDataType;
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}ListNode;
首先我们定义了一个结构体,结构体里的data被叫做数据域用来存放数据,next是指针域用来存放下一个节点的地址,prev是指针域用来存放上一个节点的地址。
二. 带头双向链表的接口实现
我们要实现如下的一些接口:
// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
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);
2.1 打印
*注意:头指针的位置不要轻易的去改动,所以在这定义了一个Cur来代替我们的头指针。
代码示例如下
// 单链表打印
void ListPrint(ListNode* pHead)
{assert(pHead);ListNode* cur=pHead->next;while(cur!=pHead) //这个条件很重要的{printf("%d->",cur->data);cur=cur->next;}
printf("NULL\n");
}
2.2 初始化
- 注意:带头双向链表的初始化 需要创建一个哨兵卫的头指针,该位置不存储有效数据 。
// 创建返回链表的头结点.
ListNode* ListCreate()
{ListNode* phead=BuySListNode(-1);phead->next=phead;phead->prev=phead;return phead;
}
2.3 开辟节点
**当我们插入的时候需要开辟新的节点,而我们有头插、尾插和任意位置插,每次写这些插入的时候都要<br />
申请节点,所以我们不妨写一个函数就直接申请节点,后面只需要调用就好了**
代码实现:
LTDataType* BuySListNode(LTDataType x)
{LTDataType* newnode=(LTDataType*) malloc(sizeof(ListNode));assert(newnode);newnode->data=x;newnode->next=NULL;newnode->prev=NULL;return newnode;
}
2.4 尾部插入节点
要尾插的话,我们首先得要开辟一个结点才能插啊,其次是要找到尾结点,那么如何找到尾结点呢?很简单,一个while循环就搞定了。
代码示例如下:
// 单链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{ListNode* newNode = BuySListNode(x);// 先不断开原链表,然后新节点连接到链表中newNode->prev = pHead->prev;newNode->next = pHead;newNode->prev->next = newNode;pHead->prev = newNode;
}
2.5 尾部删除节点
示例代码如下:
void ListPopBack(ListNode* pHead)
{assert(pHead);assert(pHead->next!=pHead);
ListNode* cur=pHead->next;while(cur!=pHead){ListNode* prev=cur;cur=cur->next;}prev->next=pHead;pHead->next=prev;free(cur);
}
2.6 头部插入节点
示例代码如下:
void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newnode=BuySListNode( x);ListNode* next=pHead->next;pHead->next=newnode;newnode->next=next;newnode->prev=pHead;next->prev=newnode;
}
2.7 头部删除节点
示例代码如下:
void ListPopFront(ListNode* pHead)
{assert(pHead);assert(pHead->next!=pHead);ListNode* next=pHead->next;pHead->next=next->next;next->next->prev=pHead;free(next);
}
2.8 查找
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* cur=pHead->next;while(cur!=pHead){if(cur->data==x){return cur;}cur=cur->next;}return NULL;
}
2.9 在Pos位置前插入
示例代码如下:
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newnode=BuySListNode(x);ListNode* prev=pos->prev;prev->next=newnode;newnode->next=pos;newnode->prev=prev;pos->prev=newnode;
}
2.10 在Pos位置删除
示例代码如下:
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{assert(pos);ListNode* next=pos->next;ListNode* prev=pos->prev;prev->next=next;next->prev=prev;free(pos);
}
2.11 销毁链表
示例代码如下:
// 双向链表销毁
void ListDestory(ListNode** pHead)
{assert(phead);ListNode* cur=(*pHead)->next;while(cur!=*pHead){ListNode* next=cur->next;free(cur);cur=next;}free(*pHead);*pHead=NULL;
}
总结
List.h完整代码:
#pragma once//防止头文件重复包含#include <stdio.h>
#include <stdlib.h>
#include <assert.h>// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}ListNode;// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
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);
List.c
完整代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
// 动态申请一个节点LTDataType* BuySListNode(LTDataType x){LTDataType* newnode=(LTDataType*) malloc(sizeof(ListNode));assert(newnode);newnode->data=x;newnode->next=NULL;newnode->prev=NULL;return newnode;
}// 创建返回链表的头结点.ListNode* ListCreate()
{ListNode* phead=BuySListNode(-1);phead->next=phead;phead->prev=phead;return phead;
}// 双向链表销毁void ListDestory(ListNode** pHead)
{assert(phead);ListNode* cur=(*pHead)->next;while(cur!=*pHead){ListNode* next=cur->next;free(cur);cur=next;}free(*pHead);*pHead=NULL;
}// 双向链表打印
void ListPrint(ListNode* pHead)
{assert(pHead);ListNode* cur=pHead->next;while(cur!=pHead) //这个条件很重要的{printf("%d->",cur->data);cur=cur->next;}
printf("NULL\n");
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{ListNode* newNode = BuySListNode(x);// 先不断开原链表,然后新节点连接到链表中newNode->prev = pHead->prev;newNode->next = pHead;newNode->prev->next = newNode;pHead->prev = newNode;
}
// 双向链表尾删void ListPopBack(ListNode* pHead){assert(pHead);assert(pHead->next!=pHead);
ListNode* cur=pHead->next;while(cur!=pHead){ListNode* prev=cur;cur=cur->next;}prev->next=pHead;pHead->next=prev;free(cur);
}// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newnode=BuySListNode( x);ListNode* next=pHead->next;pHead->next=newnode;newnode->next=next;newnode->prev=pHead;next->prev=newnode;
}// 双向链表头删
void ListPopFront(ListNode* pHead)
{assert(pHead);assert(pHead->next!=pHead);ListNode* next=pHead->next;pHead->next=next->next;next->next->prev=pHead;free(next);
}// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* cur=pHead->next;while(cur!=pHead){if(cur->data==x){return cur;}cur=cur->next;}return NULL;
}// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newnode=BuySListNode(x);ListNode* prev=pos->prev;prev->next=newnode;newnode->next=pos;newnode->prev=prev;pos->prev=newnode;
}// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{assert(pos);ListNode* next=pos->next;ListNode* prev=pos->prev;prev->next=next;next->prev=prev;free(pos);
}
码字不易,如果觉得内容有用的话,就给博主三连吧!!!
数据结构-带头双向链表的建立,详细教程相关推荐
- 【数据结构】双向链表(带头双向循环链表)——超详细代码
文章目录 1. 双链表 1.1 前言 1.2 带头双向循环链表 2. 带头双向循环链表的实现 2.1 双向链表的定义声明 2.2 双向链表的初始化 2.3 释放双向链表 2.4 打印双向链表 2.5 ...
- 七牛云详细教程(包含与阿里云建立连接)
七牛云详细教程(包含与阿里云建立连接) 1.七牛云简介 不管是设计师,还是开发者,亦或是个人.公司.我们有时会需要将图片存在网络上,然后用链接来分享给他人.或是,用来给网站做图片外链,通过CDN加速, ...
- ramdisk和linux PE,PE下建立Ramdisk盘的详细教程
如何在PE下建立一个Ramdisk盘呢?之前我们有介绍过如何在PE下安装系统ghost,有看过教程的朋友应该都会安装了吧.但是如果要在PE下建立一个Ramdisk盘,要如何建立呢?今天U大侠小编就和大 ...
- 【数据结构】一文带你学会带头双向链表
目录 前言 链表的实现 List.h List.c ListCreate() LTInit() ListPushBack() ListPopBack() ListPrint() ListPushFro ...
- 如何建立一个网站,可用互联网访问?(原创详细教程)
总体需要准备的东西: web服务器/虚拟主机. 域名. 网页源码. FTP上传下载工具. 数据库管理软件.(若搭建静态网站则不需要) 注:在此过程中,重点需要将域名解析到服务器,服务器与域名绑定. 详 ...
- c语言数组指定位置插入和删除_玩转C语言链表,单链表/双向链表的建立/遍历/插入/删除...
最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层).Service(业务逻辑层).Persistence(持久化层)的分离和耦合, ...
- Ubuntu16.04在线安装MongoDB详细教程
Ubuntu16.04在线安装MongoDB详细教程 文章目录 Ubuntu16.04在线安装MongoDB详细教程 前言 安装流程 信任MongoDB公钥 创建列表文件 安装MongoDB 常见问题 ...
- Linux-安装MongoDB(详细教程)
文章目录 前言 一.概述 二.下载 三.安装与启动 四.连接 五.可能会遇到的问题 前言 MongoDB 是一个基于分布式文件存储的数据库,主要用于为 web 应用提供可扩展的高性能数据存储解决方案. ...
- Flink 教程 gitbook 从入门到入土(详细教程)
Flink从入门到入土(详细教程) 和其他所有的计算框架一样,flink也有一些基础的开发步骤以及基础,核心的API,从开发步骤的角度来讲,主要分为四大部分 1.Environment Flink J ...
最新文章
- 腾讯云 已连接到实验云主机 linux 运维基本操作
- 剑指offer:剪绳子
- SQLiteOpenHelper的实现
- python判断字符串
- 华为mate40RS能升级鸿蒙,mate40Pro和40RS能用上鸿蒙系统吗
- 【计算机组成原理】磁盘存储器
- PAT乙级(1020 月饼)
- 【Elasticsearch】Elasticsearch 缓存深度剖析:一次提高一种缓存的查询速度
- Mqtt 客户端 java API 教程
- 最详细的jsp基础教程
- 学术规范与论文写作(期末考试答案)(方便检索版)
- Android----banner使用详解
- PC微信最新版HOOK接口3.7.6.44
- HTML的两种盒子模型
- 数学天才破解世界级难题,23岁被聘为正教授,丘成桐:运气好而已
- 通信电子电路(二十一) 第二章 知识点总结+作业分析
- PJBLOG首页调用
- 安装Django4.0最详细教程 pip总是报错怎么办
- 通过压力测试提升服务器并发性能实例
- 【最终版】PyQt5 自定义标题栏,实现无边框,最小化最大化关闭事件,窗口拖动移动,窗口改变大小,仿百度网盘色调美化,添加内容窗口
热门文章
- C#开发之——Mutex(14.8)
- 设计模式之静态代理模式
- js选项卡 php,JS实现选项卡实例详解_javascript技巧
- 【转】自使用linux常用命令练习题
- 8岁女儿写代码哄程序员爸爸开心,网友直呼:破防了
- Vue抛 Property or method turn is not defined on the instance but referenced during render. 的解决方法
- JavaScript BOM操作
- 第7节 代码添加书签/快速查找/定位
- TOTAL COMMANDER 7 ( TC7 ) 的遺憾
- ext-js 中 Ext.data.Model 的 phantom 属性的讨论