数据结构-线性表(链表)(c++版)

2023-11-07

 

目录

1,单链表的基本概念与特点

2, 单链表的特点

3,单链表的结构定义及其方法的实现

3.1,单链表结构的定义

3.2,方法的基本实现

3.3,单链表的插入删除操作讲解

3.4,单链表的删除算法

 3.5,单链表的顺序访问与尾递归

3.6,尾插法建立单链表(递归方法实现)

3.7,头插法建立单链表(递归实现)

3.8,非递归算法实现链表的头插法和尾插法


1,单链表的基本概念与特点

单链表也叫作线性链表,是线性表的链式存储表示,,使用单链表进行存储,各个元素可以相继存储,也可以不相继存储,不过它为每个元素附加了一个指针,并且形成一个一个的节点。通过节点中的链接指针,把各个元素按照其逻辑顺序依次连接起来。因此,每个节点中包含两个域,一个指针域一个数据域,分别是next和data两个域。data用来存放各个节点中的数据,而next用来记录该链表中下一个节点开始存储地址的指针。链表的第一个节点可以通过头指针First找到,其他节点的地址则在其前驱节点的next域中,链表的最后一个节点没有后继,所以再其next域中存放空指针,因此在单链表中访问中间节点,必须通过头结点依次寻找访问。如图即是一个单链表。

2, 单链表的特点

(1)单链表中的数据元素的逻辑顺序可能不一致,一般通过单链表指针将各个元素按照线性表的逻辑顺序链接起来。

(2)单链表的长度可以扩充,对单链表的遍历或者查找只能从头指针的首元节点开始,跟随链接指针逐个进行访问,不能如同顺序表那样直接访问某一个节点。

(3)当进行删除或者插入运算时,只需修改相关节点的指针域即可。

(4)由于链表的每个节点多了一个指针域,因此比起顺序表需要的空间也更多。

3,单链表的结构定义及其方法的实现

3.1,单链表结构的定义

//单链表节点定义
typedef int DataType;
typedef struct node
{
	DataType data;//数据域
	struct node *next;//指针域
}LinkNode,*LinkList;

3.2,方法的基本实现

在这里有一个小小的注意点,我们在建立单链表的时候,常常为了删除或者插入算法的实现方便一点,常常在链表的头加上一个头结点,目的也就是让插入或者删除操作算法统一。如果我们不加头结点,那么在删除第一个节点或者在第一个节点前面插入一个元素时,往往要在这里进行特殊处理,如果加上头结点,则就避免了不必要的麻烦,简化了删除插入操作,所以在建立单链表的时候加上一个头结点是很有必要的。(如下图就是带头结点的单链表空和非空时的状态)

 

//初始化单链表,建立只有头结点的空链表
void initlist(LinkList &list)
{
	list = (LinkNode*)malloc(sizeof(LinkNode));//创建一个头结点
	list->next= nullptr;//置空操作
}
//清空单链表,仅仅保留单链表的头结点
void clearList(LinkList &list)
{
	LinkNode *q;
	while (list->next != nullptr)
	{
		q = list->next;
		list->next = q->next;
		free(q);
	}
}
//计算单链表的长度,返回单链表的长度
int get_LinkList_length(LinkList &list)
{
	int count = 0;
	LinkNode *q = list->next;
	while (q != nullptr)
	{
		q = q->next;
		count++;
	}
	return count;
}
//在单链表中查找x匹配的元素,返回该节点的地址
LinkNode *Linklist_Search(LinkList &list,DataType x)
{
	LinkNode *p = list->next;
	while (p != nullptr&&p->data != x)
		p = p->next;
	return p;
}
//对链表第i个节点定位,成功返回第i个节点的地址
LinkNode *Locate(LinkList &list, DataType i)
{
	if (i < 0)
		return NULL;
	LinkNode *p = list;
	int k = 0;
	while (p != NULL && k < i)//循环查找第i个节点,k作为节点计数
	{
		p = p->next;
		k++;
	}
	return p;
}
//将新元素x插入到第i个节点,带头结点的单链表的插入算法
bool inSert(LinkList &list, int i, DataType x)
{
	LinkNode *p = Locate(list, i - 1);
	if (p == NULL)
		return false;
	LinkNode *newNode = (LinkNode*)malloc(sizeof(LinkNode));//建立新节点
	newNode->data = x;
	newNode->next = p->next;
	p->next = newNode;
	return true;
}

//删除单链表第i个元素,并用x返回其值,带头节点的单链表的删除算法
bool Remove(LinkList &list, int i, DataType x)
{
	LinkNode *p = Locate(list, i - 1);//定位到第i-1个元素
	if (p == nullptr&&p->next == nullptr)
		return false;
	LinkNode *q = p->next;//q保存被删除节点的节点
	p->next = q->next;//p指向第i+1个节点
	x = q->data;
	free(q);
	return true;
}
//输出带头节点的单链表
void printList(LinkList &list)
{
	LinkNode *p;
	for (p = list->next; p != nullptr; p = p->next)
		printf("%d", p->data);
		printf("\n");
}

3.3,单链表的插入删除操作讲解

注:上面两个单链表的删除插入算法是带头节点的,在这里分析的删除或者插入算法是不带头结点的算法,基本思路都是一样的,只是为了让大家分清楚带头结点的单链表优势在哪里,所以在这里实现了不带头结点的删除插入算法,本人在学习这里时也犯了很多错误,所以在这里把删除与插入算法做详细分析。

单链表的插入有三种情况,如果在非空单链表的第i个位置插入一个新元素,分别讨论如下:

(1)若i=1,则新插入节点newNode在首元结点前,这时必须修改链表的头指针first,插入时要修改指针为:

newNode->next=first,first=newNode

(2)若果1<i<=n,则插入位置在中间,此时首先让一个辅助节点p指向第i-1个位置,在吧新节点newNode插入p节点所指的后一个节点,新节点的后面连接到原来的第i个节点。此时需要修改的指针为:

newNode->next=p->next,p->next=newNode

(3)当i>n时,新节点应追加在表尾,这时先令检测指针p指向表的最后一个节点。修改指针为:

newNode->next=p->next,p->next=newNode
//将新元素x插入到链表第i个位置,如果i给的太大,则直接插入到链表尾
bool inSert(LinkList &list, int i, DataType x)
{
	if (list == nullptr || i == 1)//插入到空链表或者非空表首元节点前
	{
		LinkNode *newNode = (LinkNode*)malloc(sizeof(LinkNode));//建立新节点
		newNode->data = x;
		newNode->next = list;//新节点成为首元
		list = newNode;
	}
	else//插入到链表中间或者尾部
	{
		LinkNode *p = list, *pr;
		int k = 1;
		while (p != nullptr&&k < i - 1)//从首元节点开始检测,寻找第i-1个节点
		{
			pr = p;
			p = p->next;
			k++;
		}
		if (p == nullptr&&list != nullptr)
			p = pr;//链表太短,即i太大,p指向表尾
		LinkNode *newNode = (LinkNode*)malloc(sizeof(LinkNode));
		newNode->data = x;
		newNode->next = p->next;//插入到p节点后面
		p->next = newNode;

	}
	return true;
}

3.4,单链表的删除算法

单链表的删除算法有三种情况:

(1)删除链表的首元节点,这时首先用指针q保存首源节点的地址,再将链表的头指针first指向其下一个节点,使其成为新链表的首元节点,然后在删除q保存的原首元节点,修改指针为:

q=list,list=list-next;free(q)

(2)在链表结尾或者中间删除节点,先用指针q保存第i个节点的地址,再让第i-1个指针的next域指向第i+1个节点的地址,最后删除节点q保存节点的地址。(p指向第i-1个节点)修改指针如下:

q=p->next,p->next=q->next;free(q);
//删除单链表第i个元素,并用x返回其值
bool Remove(LinkList &list, int i, DataType x)
{
	LinkNode *p, *q;
	int k;
	if (i == 0)
		return false;
	else 
		if (i == 1)//删除首元节点表头退到下一个节点
		{
			q = list;
			list = list->next;
		}
		else
		{
			p = list;
			k = 1;
			while (p != nullptr&&k < i - 1)//循环找到第i-1个节点
			{
				p = p->next;
				k++;
			}
			if (p ==NULL && p->next == nullptr)//空表或者链表太短,即i值太大
			{
				return false;
			}
			q = p->next;//保存第i个节点的地址
			p->next = q->next;
		}
	x = q->data;
	free(q);
	return true;
}

 3.5,单链表的顺序访问与尾递归

所谓尾递归是是指在递归程序中只有一个递归语句并且它处于程序的最后,应为单链表只可以顺序访问并且属于递归的线性结构,所以基于单链表的许多算法都可以用递归实现。

//在以first为头结点的单链表中查找其值等于给定的x节点
LinkNode *Search(LinkNode *first, DataType x)
{
	if (first == NULL)
		return nullptr;
	else
		if (first->data == x)
			return first;
		else
			return Search(first->next, x);
}

//调用方式
LinkNode *p=Search(first->next,x)

3.6,尾插法建立单链表(递归方法实现)

所谓尾插法是指每次新节点都插到链表的表尾,这样插入的结果是各个节点中的数据的逻辑顺序与输入数据的顺序一致。

从一个空表开始,重复读取数字,执行两步操作:

(1)生成新节点,将读取的数字存入到data域中

(2)将该节点插入到链表的表尾,直到读入结束字符为止。


//尾递归发建立单链表,程序中设置了一个尾指针last,它总是指向新链表中的最后一个节点,
//新节点连接到它所指尾节点的后面,last设定为引用性指针,他要把新建的节点地址或空地址传到前一个节点next域中。
#include<stdio.h>
void insertRear(LinkNode *&last, DataType endTag)
{
	//endtag是约定输入序列的结束标志,可以任意设定
	DataType val;
	scanf("%d", &val);
	if (val == endTag)
		last = NULL;
	else
	{
		last = (LinkNode*)malloc(sizeof(LinkNode));//建立新节点
		last->data = val;
		insertRear(last->next, endTag);

	}
}
	int main()
	{
		LinkList l;
		initlist(l);
		DataType endTag;
		scanf("%d", &endTag);
		LinkNode *rear = l;
		insertRear(rear->next, endTag);
		printList(l);
	}

3.7,头插法建立单链表(递归实现)

所谓头插法是指每次插入的新节点总是作为首元节点插在链表的头结点之后,插入的结果是使得链表中各节点中的数据的逻辑顺序与输入数据的顺序刚好相反。

#include<stdio.h>
	void insertFront(LinkNode *&first, DataType endTag)
	{
		//endtag是约定输入序列的结束标志,可以任意设定
		DataType val;
		scanf("%d", &val);
		if (val == endTag)
			return;
			LinkNode *p = (LinkNode*)malloc(sizeof(LinkNode));//建立新节点
			p->next = first->next;
			first->next = p;
			insertFront(first, endTag);

		
	}
	int main()
	{
		LinkList l;
		initlist(l);
		DataType endTag;//约定输入结束标志
		scanf("%d", &endTag);
		LinkNode *rear = l;
		insertFront(l, endTag);
		printList(l);
	}

3.8,非递归算法实现链表的头插法和尾插法

//尾插法
void insertRear(LinkList &list)
	{
		//对一个单链表list,已初始化,从空链表开始,用尾插法建立单链表
		LinkNode *newNode, *last;
		DataType val, endTag;
		last = list;
		scanf("%d", endTag);//约定结束标志
		while (val != endTag)
		{
			newNode= (LinkNode*)malloc(sizeof(LinkNode));//建立新节点
			newNode->data = val;
			last->next = newNode;
			last = newNode;
                        scanf("%d", val);
		}
		last->next = nullptr;
	}
//头插法
	void insertFront(LinkList &list)
	{
		//对一个单链表list,已初始化,从空链表开始,用头插法建立单链表
		LinkNode *newNode, *last;
		DataType val, endTag;
		last = list;
		scanf("%d", endTag);
		while (val != endTag)
		{
			newNode = (LinkNode*)malloc(sizeof(LinkNode));//建立新节点
			newNode->data = val;
			newNode->next = list->next;//连接到头结点之后
			list->next = newNode;
			scanf("%d", val);
		}
	}

 


 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构-线性表(链表)(c++版) 的相关文章

  • skimage的简介

    skimage的简介 skimage即是Scikit Image 基于python脚本语言开发的数字图片处理包 比如PIL Pillow opencv scikit image等 PIL和Pillow只提供最基础的数字图像处理 功能有限 o

随机推荐

  • activiti 自定义函数解析juel表达式

    activiti是支持juel表达式的 这个也很好用 但实际过程中需要支持类方法及变量 原来项目中解析juel 这边有自定义一个方法的 代码如下 public String getStringByELAndFormData String e
  • 使用C语言编写Python扩展1——Hello World

    使用C语言编写Python扩展1 Hello World 时间 2014 04 12 18 01 10 龍昌博客 原文 http www xefan com archives 84082 html 主题 Python C语言 能够使用C语言
  • 设计模式复习之装饰器模式

    一 装饰器模式 摘录 装饰器模式又称为包装 Wrapper 模式 装饰器模式以多客户端透明的方式扩展对象的功能 是继承关系的一个替代方案 通常给对象添加功能 要么直接修改对象添加相应的功能 要么派生子类来扩展 抑或是使用对象组合的方式 显然
  • 如何用Python创建SQL数据库 ? 学会就非常完美~

    今日份知识你摄入了么 会写SQL很重要 能高效地查询数据库被认为是数据分析师 科学家最基本的技能之一 SQL不仅重要 而且非常常用 根据 2021年Stackoverflow开发者调查 SQL是最常用的五种编程语言之一 所以 我们应该多投入
  • STL实现排序

    使用sort函数对容器内的随机元素进行排序 sort RandomAccessIterator first RandomAccessIterator last Compare comp RandomAccessIterator first
  • Libevent 事件循环(1)

    事件的dispatch int event base loop struct event base base int flags 得到采用的事件模型 epoll epoll select const struct eventop evsel
  • 单元测试,报java.lang.NoClassDefFoundError:org/springframework/test/content/TestContesxtAnnotationUtils

    这里写目录标题 一级目录 1 问题 单元测试 报java lang NoClassDefFoundError org springframework test content TestContesxtAnnotationUtils spri
  • Message: element not interactable错误解决

    1 在定位之前先等待资源加载完毕 sleep 10 element driver find element by xpath input class form control and name username 2 定义隐式等待 drive
  • SQL中grant的用法

    GRANT 名称 GRANT 赋予一个用户 一个组或所有用户访问权限 语法 GRANT privilege ON object TO PUBLIC GROUP group username 输入 privilege 可能的权限有 SELEC
  • Python OpenCV 入门教程

    原文链接 本文只是调整了代码格式 一 Python OpenCV 入门 欢迎阅读系列教程 内容涵盖 OpenCV 它是一个图像和视频处理库 包含 C C Python 和 Java 的绑定 OpenCV 用于各种图像和视频分析 如面部识别和
  • SSIS包配置

    Integrartion Services 包实际上就是一个对象属性的集合 在前面我们开发的所有 Integration Services包 其中的变量 属性 比如 数据库链接 同步文件目录等 我们都直接在包中用一个常量的方式 赋给这些变量
  • 2022亚马逊云科技中国峰会召开 宣布多项举措赋能客户数字化探索与创新

    2022年10月13日 以 自由构建 探索无限 为主题的亚马逊云科技中国峰会于今天在线上召开 在本次为期2天的峰会上 亚马逊云科技发布了云计算技术趋势展望 宣布 连中外 襄百业 携伙伴 促绿色 四大战略举措 进一步利用亚马逊云科技全球优势和
  • [思考进阶]03 每一个成年人都应该掌握的学习技巧

    除了要提升自己的技术能力 思维的学习和成长也非常非常重要 特推出此 思考进阶 系列 进行刻意练习 从而提升自己的认知 这世间有两种人 一种被誉为天之骄子 拥有那种天才的创造能力 这种人极少 另外一种是平凡的普通人 努力地想成功 这种人很多
  • C语言:输出一组数的最大值与最小值

    C语言 输出一组数中的最大值或最小值 如果要输出多个数的最大值只需更改数组大小与循环的限制条件即可 这里以三个数为例 最大值 include
  • [STM32] 关于USART接收中断的BUG和注意事项

    今天在使用USART模块 遇到了一些问题并解决了 于是发贴共享 问题描述 在使用USART做串口通讯时 我只把接收中断打开 并设置抢占优先级为最低一个级别 而接收中断上一个优先级处理事情比较多 可能占用了2ms时间 当我使用9600波特率往
  • 【Jupyter】【Colab】【AutoGluon】测试

    环境 pip install autogluon 测试代码 AutoGluon官网 from autogluon tabular import TabularDataset TabularPredictor train data Tabul
  • 第七章 缺失数据

    文章目录 一 缺失值的统计和删除 1 缺失信息的统计 2 缺失信息的删除 二 缺失值的填充和插值 1 利用fillna进行填充 练一练 END 2 插值函数 NOTE 关于polynomial和spline插值的注意事项 END 三 Nul
  • 用canvas画出可爱的哆啦A梦

    用canvas画出可爱的哆啦A梦 本文就介绍了如何用canvas案例画出哆啦A梦的基础内容 提示 以下是本篇文章正文内容 下面案例可供参考 一 canvas是什么 HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图
  • seata1.3.0 系列学习(二、nacos+seata使用)

    上篇文章讲了如何安装seata 这篇文章主要讲如何使用 分布讲解什么情况回滚 不回滚 一 新建父级maven pom xml文件导入
  • 数据结构-线性表(链表)(c++版)

    目录 1 单链表的基本概念与特点 2 单链表的特点 3 单链表的结构定义及其方法的实现 3 1 单链表结构的定义 3 2 方法的基本实现 3 3 单链表的插入删除操作讲解 3 4 单链表的删除算法 3 5 单链表的顺序访问与尾递归 3 6