C语言类的双向链表详解

目录
  • 前言
  • 双向链表的定义
  • 双向链表的创建
  • 节点的创建
  • 双向链表节点查找
  • 双向链表的插入
  • 双向链表的节点删除
  • 双向链表的删除
  • 总结

前言

链表(linked list)是一种这样的数据结构,其中的各对象按线性排列。数组的线性顺序是由数组下标决定的,然而于数组不同的是,链表的各顺序是由链表中的指针决定的。

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

双向链表的定义

双链表(doubly linked list)的每一个元素都是一个对象,每一个对象都有一个数据域和两个指针front和tail。对象中还可以包含其他辅助数据。设L为链表的一个元素,L.front指向他在链表中的后继元素,L.tail指向他的前继元素。

我们可以定义一个结构体封装这些数据

typedef struct Node
{
	int data;
	struct Node* front;
	struct Node* tail;
}NODE, * LPNODE;

双向链表的创建

在C++中,我们以类的形式封装了双向链表。在类中,我们定义了两个指针,一个是指向链表的头部 frontNode,一个是指向了链表的尾部 tailNode,另外我们还加入了 curSize属性,记录节点的个数。在对象创建的过程就是链表创建的过程,我们只需要在类的构造函数中初始化参数即可。

class duplexHead {
public:
	duplexHead() {
		frontNode = NULL;
		tailNode = NULL;
		curSize = 0;
	}

	LPNODE createNode(int data);
	LPNODE seachNode(int data);
	void push_front(int data);
	void push_back(int data);
	void push_appoin(int posData, int data);
	void pop_front();
	void pop_back();
	void pop_appoin(int posData);
	void printByFront();
	void printByTail();

protected:

	LPNODE frontNode;
	LPNODE tailNode;
	int curSize;

};

节点的创建

在上面,我们已经知道双向链表的单体长啥样了,我们只需要给他的单体分配空间然后初始化他的参数即可。

LPNODE duplexHead::createNode(int data)
{
	LPNODE newNode = new NODE;
	assert(newNode);
	newNode->front = nullptr;
	newNode->tail = nullptr;
	newNode->data = data;
	return newNode;
}

双向链表节点查找

链表的查找我们可以定义一个函数LPNODE seachNode(int data),当满足查找条件时,我们就返回当前节点的链表。在实际操作过程中,链表的数据域可能会有多个数据,可能要比较int 类型,可能要比较string类型等多种变化,这是我们可以在参数列表预留一个函数指针 (int)  (*comparData)(LPNODE  data),以应对多种需求。当然,在这里为了演示方便,我们就用一个int 类型的数据代替了。

LPNODE duplexHead::seachNode(int data)
{
	if (!curSize)
	{
		printf("链表为空,无法查找");
		return;
	}
	LPNODE preNode = frontNode;
	LPNODE curNode = frontNode;
	while (curNode != NULL && curNode->data != data)
	{
		preNode = curNode;
		curNode = preNode->tail;
	}
	if (curNode == nullptr)
	{
		printf("链表中没有该数据");
		return nullptr;
	}

	return curNode;

}

双向链表的插入

插入节点,我们分为头部插入和尾部插入以及指定位置插入。而这三种插入,都可分为3步。

(1)创建新节点

(2)找到插入位置

(3)插入

我们就以制定位置插入为例,如图所示,我们只需把原来相连的两个节点断开,然后再分别用指针拼接起来,当然我们也可以调用我们的seachNode来查找位置,这样就更方便一些了。

void duplexHead::push_appoin(int posData, int data)
{

	if (curSize == 0)
		return;
	if (frontNode->data == posData)
	{
		push_front(data);
	}
	else
	{
		LPNODE preNode = frontNode;
		LPNODE curNode = frontNode;
		while (curNode != NULL && curNode->data != posData)
		{
			preNode = curNode;
			curNode = preNode->tail;
		}
		if (curNode == NULL)
		{
			printf("未找到指定位置,无法插入!\n");
		}
		else
		{
			LPNODE newNode = createNode(data);
			preNode->tail = newNode;
			newNode->tail = curNode;
			curNode->front = newNode;
			newNode->front = preNode;
			curSize++;
		}
	}
}

双向链表的节点删除

删除节点我们也可以分为头部删除,尾部删除,指定数据删除。他与插入节点几乎是一样的

(1)找到删除位置

(2)删除

我们就以指定数据删除为例,我们通过while或者seachNode来查找到要删除的节点,然后把他的front 指向的位置和tail指向的位置记住,就可以直接删除节点了。删除完了节点要记得把前后段的链表连接上即可。

void duplexHead::pop_appoin(int posData)
{
	if (frontNode == NULL || curSize == 0)
	{
		printf("链表为空无法删除!");
		return;
	}
	if (frontNode->data == posData)
	{
		pop_front();
		return;
	}
	LPNODE preNode = frontNode;
	LPNODE curNode = frontNode;
	while (curNode != NULL && curNode->data != posData)
	{
		preNode = curNode;
		curNode = preNode->tail;
	}
	if (curNode == NULL)
	{
		printf("未找到指定位置无法删除!\n");
	}
	else
	{
		if (tailNode == curNode)
		{
			pop_back();
		}
		else
		{
			preNode->tail = curNode->tail;
			//curNode->tail是不是不空
			//当删除的表尾时候,curNode->tail等于空
			curNode->tail->front = preNode;
			free(curNode);
			curNode = NULL;
			curSize--;
		}
	}
}

双向链表的删除

于双向链表的创建一样,我们可以把双向链表的删除放在析构函数中,实现创建和删除自动化,当对象被创建,双向链表就被创建,当对象消亡,双向链表就删除了。

duplexHead::~duplexHead()
{
	if (!frontNode)return;
	LPNODE pmove ;

	while (!pmove)
	{
		pmove = frontNode->tail;
		delete frontNode->tail;
		frontNode = pmove;
	}

}

总结

到此这篇关于C语言类的双向链表详解的文章就介绍到这了,更多相关C语言双向链表内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言实现双向链表

    这个小代码是我凭自己对指针和链表的理解和认识,自己实现的,没有参考其他人的代码,如果有相同的地方,那真的只是巧合,代码我在ubuntu 15.04下测试通过,可能存在很多错误和漏洞. doublelist.c /************************************************************************* > File Name: doublelist.c > Author: ChenYiLiang > Mail: chenyilian

  • C语言双向链表的表示与实现实例详解

    1.概述: C语言中一种更复杂的链表是"双向链表"或"双面链表".其表中的每个节点有两个连接:一个指向前一个节点,(当这个"连接"为第一个"连接"时,指向空值或者空列表):而另一个指向下一个节点,(当这个"连接"为最后一个"连接"时,指向空值或者空列表) 一个双向链表有三个整数值: 数值, 向后的节点链接, 向前的节点链接 在一些低级语言中, XOR-linking 提供一种在双向链表中

  • C语言 数据结构双向链表简单实例

    双向链表的基本操作 1.利用尾插法建立一个双向链表. 2.遍历双向链表. 3.实现双向链表中删除一个指定元素. 4.在非递减有序双向链表中实现插入元素e仍有序算法. 5.判断双向链表中元素是否对称若对称返回1否则返回0. 6.设元素为正整型,实现算法把所有奇数排列在偶数之前. 7.在主函数中设计一个简单的菜单调试上述算法. 实例代码: //排序的时候因为没有说明奇数和偶数需不需要各自再排序,我就没有排序,只是将奇数放在偶数后面. //创建链表的时候,因为这个实验没有要求输出链表的长度,所以我就输

  • C语言数据结构 双向链表的建立与基本操作

    C语言数据结构 双向链表的建立与基本操作 双向链表比单链表有更好的灵活性,其大部分操作与线性表相同.下面总结双向链表与单链表之间的不同之处及我在实现过程中所遇到的问题. 1.双向链表的建立 双向链表在初始化时,要给首尾两个节点分配内存空间.成功分配后,要将首节点的prior指针和尾节点的next指针指向NULL,这是十分关键的一步,因为这是之后用来判断空表的条件.同时,当链表为空时,要将首节点的next指向尾节点,尾节点的prior指向首节点. 2.双向链表的插入操作 由于定义双向链表时指针域中

  • C语言中双向链表和双向循环链表详解

    双向链表和双向循环链表 和单向链表相比,多了一个前驱结点.如果他为空,那么next和prior都指向自己.而对于双循环链表,只需要最后一个元素的next指向head->next,head->next的prior指向最后一个节点即可. 插入操作 新节点s插入链表,s->next给p结点,s->prior给p->prior,然后,p->prior->next指向s,p->prior再指向s.顺序需要注意 s->next = p; s->prior =

  • C语言类的双向链表详解

    目录 前言 双向链表的定义 双向链表的创建 节点的创建 双向链表节点查找 双向链表的插入 双向链表的节点删除 双向链表的删除 总结 前言 链表(linked list)是一种这样的数据结构,其中的各对象按线性排列.数组的线性顺序是由数组下标决定的,然而于数组不同的是,链表的各顺序是由链表中的指针决定的. 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱.所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点.一般我们都构造双向循

  • C语言算法学习之双向链表详解

    目录 一.练习题目 二.算法思路 1.设计浏览器历史记录 2.扁平化多级双向链表 3.展平多级双向链表 4.二叉搜索树与双向链表 一.练习题目 题目链接 难度 1472. 设计浏览器历史记录 ★★★☆☆ 430. 扁平化多级双向链表 ★★★☆☆ 剑指 Offer II 028. 展平多级双向链表 ★★★☆☆ 剑指 Offer 36. 二叉搜索树与双向链表 ★★★★☆ 二.算法思路 1.设计浏览器历史记录 1.这是一个模拟题: 2.初始化生成一个头结点,记录一个当前结点: 3.向前 和 向后 是两

  • Java中双向链表详解及实例

    Java中双向链表详解及实例 写在前面: 双向链表是一种对称结构,它克服了单链表上指针单向性的缺点,其中每一个节点即可向前引用,也可向后引用,这样可以更方便的插入.删除数据元素. 由于双向链表需要同时维护两个方向的指针,因此添加节点.删除节点时指针维护成本更大:但双向链表具有两个方向的指针,因此可以向两个方向搜索节点,因此双向链表在搜索节点.删除指定索引处节点时具有较好的性能. Java语言实现双向链表: package com.ietree.basic.datastructure.dublin

  • spring的几个重要类和接口(详解)

    1. datasource接口是javax.sql包下的接口,不是spring,是javax.sql下的 datasource接口有个重要的方法getConnection()方法 Connection getConnection(String username, String password) throws SQLException; 那些spring支持的数据库连接池,都是实现了Datasource接口 比如下面是阿里的DruidDatasource数据库连接池源码,它就是实现了dataso

  • C语言 全局变量和局部变量详解及实例

    C语言 全局变量和局部变量详解 核心内容: 1.局部变量和全局变量 变量按照作用域分为:全局变量和局部变量 全局变量的作用域:从定义位置开始到下面整个程序结束. 局部变量的作用域:在一个函数内部定义的变量只能在本函数内部进行使用. OK,上面的效果用Java语言实现一下: public class App1 { public static int k = 10;//相当于全局变量 public static void main(String[] args) { int i = 10;//局部变量

  • JVM内存管理之JAVA语言的内存管理详解

    引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓狂的内存溢出和泄露的问题. 可怕的事情还不只如此,有些使用其它语言开发的程序员,给JAVA程序员扣上了一个"不懂内存"的帽子,这着实有点让人难以接受.毕竟JAVA当中没有malloc和delete.没有析构函数.没有指针,刚开始接触JAVA的程序员们又怎么可能接触内存这一部分呢,更何况有不

  • Python面向对象总结及类与正则表达式详解

    Python3 面向对象 -------------------------------------------------------------------------------- 一丶面向对象技术简介 •类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. •方法:类中定义的函数. •类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在函数体之外.类变量通常不作为实例变量使用. •数据成员:类变量或者实例变

  • 把JSON数据格式转换为Python的类对象方法详解(两种方法)

    JOSN字符串转换为自定义类实例对象 有时候我们有这种需求就是把一个JSON字符串转换为一个具体的Python类的实例,比如你接收到这样一个JSON字符串如下: {"Name": "Tom", "Sex": "Male", "BloodType": "A", "Hobbies": ["篮球", "足球"]} 我需要把这个转换为具

  • java语言注解基础概念详解

    1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃: 2.RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期: 3.RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在: 这3个生命周期分别对应于:Java源文件(.java文件)--->.class文件--->内存中的字节码.

  • Python数据结构之双向链表详解

    目录 0. 学习目标 1. 双向链表简介 1.1 双向链表介绍 1.2 双向链表结点类 1.3 双向链表优缺点 2. 双向链表实现 2.1 双向链表的初始化 2.2 获取双向链表长度 2.3 读取指定位置元素 2.4 查找指定元素 2.5 在指定位置插入新元素 2.6 删除指定位置元素 2.7 其它一些有用的操作 3. 双向链表应用 3.1 双向链表应用示例 3.2 利用双向链表基本操作实现复杂操作 0. 学习目标 单链表只有一个指向直接后继的指针来表示结点间的逻辑关系,因此可以方便的从任一结点

随机推荐