首页 > 其他分享 >【数据结构】第二章——线性表(5)

【数据结构】第二章——线性表(5)

时间:2023-12-27 20:32:50浏览次数:26  
标签:插法 结点 单链 线性表 创建 元素 第二章 数据结构 指针

单链表的创建

【数据结构】第二章——线性表(5)_头插法

导言

大家好,很高兴又和大家见面啦!!! 在上个章节中,咱们介绍了单链表的基本概念,以及如果初始化带头结点的单链表与不带头结点的单链表,相信大家现在对这一块内容都是比较熟悉的了。下面我们先来一起回顾一下单链表的初始化,为了方便理解,这里我们还是通过数据域为整型且带有头结点的单链表来进行介绍;

一、单链表的初始化

在对单链表进行初始化之前,我们还是需要按照以下步骤一步一步执行:

  1. 定义单链表类型
  2. 定义指向单链表的头指针
  3. 初始化单链表

将这些步骤转化成C语言,如下所示:

//定义单链表类型
typedef struct LNode
{
	int data;//数据域
	struct LNode* next;//指针域
}LNode, * LinkList;
//单链表初始化
bool InitList(LinkList* L)
{
	//创建头结点
	*L = (LNode*)calloc(1, sizeof(LNode));
	//判断是否成功创建头结点
	if (!(*L))
		return false;
	(*L)->next = NULL;//初始化头结点
	return true;
}
int main()
{
	LinkList L;//定义指向单链表的头指针
	InitList(&L);//初始化单链表
	return 0;
}

现在咱们就成功的创建了单链表的头指针与头结点,并且为了防止头结点的指针域为野指针,我们这里对其初始化成了空指针。有了头指针和头结点后,我们现在就可以创建一个单链表了。

二、单链表的创建

我们在创建单链表时有两种创建方式——头插法创建单链表与尾插法创建单链表。下面我们通过图解来介绍一下这两种创建方式:

【数据结构】第二章——线性表(5)_链表_02

为了方便大家理解,这里我们将链表的第一个元素称为表头元素,链表的最后一个元素我们称为表尾元素,对应的头插法与尾插法我们就可以理解为新元素插入后的位置:

  • 在创建链表时,将新元素插入为表头元素,这种插入方法我们就称为头插法
  • 在创建链表时,将新元素插入为表尾元,这种插入方法我们就称为尾插法

从上图中,我们还可以看到,对于头插法而言,元素插入的顺序是逆序插入的,也就是头插法相当于对元素进行了逆置。

我们在创建链表前,链表都是一个空表,此时的头结点的指针域指向的是NULL,那我们应该如何通过C语言来实现这两种链表的创建方式呢?下面我们就来一一介绍一下;

2.1 采用头插法建立单链表

在上图中我们也有对头插法的步骤进行说明,我们在插入新的表头元素时,首先应该让新元素的指针域指向头结点的指针域指向的对象:

  • 对于空表来说,此时头指针的指针域指向的是NULL;
  • 对于已有元素的链表来说,头指针的指针域指向的是链表的表头元素;

对于单链表而言,它并不是一个能够进行随机存取的存储结构,所以我们要想得到链表中的某个元素,我们都是只能从头指针开始往后遍历直到找到该元素,因此,我们要想让新元素的指针域指向表头元素,我们只能通过头结点的指针域才能找到链表的表头元素,转化为C语言则是:

New_next->Head_next;//将新结点的指针域指向头结点的指针域所指向的元素
Head_next->New;//头结点的指针域指向新的元素

因此我们就可以得到头插法的基本格式:

//头插法的基本格式
LinkList List_HeadInsert(LinkList* L)//头插法建立单链表
{
	LNode* s;//指向新结点的指针
	ElemType x;//存放数据域信息的变量
	……;//获取数据信息
	while (x != EOF)//通过EOF给循环设置一个结束条件,也可以设置为其它内容
	{
		s = (LNode*)calloc(1, sizeof(LNode));//创建新的结点
		s->data = x;//将数据元素放入新结点的数据域中
		s->next = (*L)->next;//将头结点的指针域中存放的信息放入新结点的指针域中
		(*L)->next = s;//将新结点的地址存放进头结点的指针域中
		……;//获取新的数据元素
	}
	return(*L);//将创建好的单链表返回给函数
}

从这个基本格式中我们可以看到,要将一个新的结点插入链表中,那这个新结点的数据域和指针域的内容都是不能忽视的,所以大家一定不要忘记了将新结点的数据域中存放对应的数据元素。下面我们通过整型数据元素来尝试着使用头插法创建一个链表,如下所示:

【数据结构】第二章——线性表(5)_链表_03

可以看到,此时我们就很好的通过头插法创建了一个单链表,并且单链表的各个元素是逆置的,对应的代码如下所示:

//使用头插法创建单链表
LinkList List_HeadInsert(LinkList* L)//头插法建立单链表
{
	LNode* s;//指向新结点的指针
	int x;//存放数据域信息的变量
	scanf("%d", &x);//通过scanf来获取新结点数据域的元素,也可以通过其它方式
	while (x != 9999)//通过9999给循环设置一个结束条件,也可以设置为其它内容
	{
		s = (LNode*)calloc(1, sizeof(LNode));//创建新的结点
		s->data = x;//将数据元素放入新结点的数据域中
		s->next = (*L)->next;//将头结点的指针域中存放的信息放入新结点的指针域中
		(*L)->next = s;//将新结点的地址存放进头结点的指针域中
		scanf("%d", &x);//获取新的数据元素
	}
	return(*L);//将创建好的单链表返回给函数
}
//打印单链表
void Print_LinkList(LinkList L)
{
	LNode* s = L;//指向结点的指针
	LNode* r = L;//指向结点的指针
	printf("打印单链表的各个元素:>");
	for (int i = 0; r->next; i++)
	{
		s = r->next;//将r存放的下一个结点的信息赋值给指针s
		r = s;//指针r通过指针s找到下一个结点
		printf("%d ", r->data);
	}
	printf("\n");
}
int main(){
	LinkList L;//定义指向单链表的头指针
	if(InitList(&L));//初始化单链表
	{
		L = List_HeadInsert(&L);//创建单链表
		Print_LinkList(L);//打印单链表
	}
	return 0;
}

2.2 采用尾插法创建单链表

与头插法不同的是,尾插法是从空表开始依次将元素插入到单链表的表尾:

  • 当单链表为空表时,插入的第一个元素既是表头元素也是表尾元素;
  • 当单链表不为空表时,新的元素将会插入到表尾;

尾插法的实现与头插法相似,只不过此时的表尾指向的对象为NULL,我们每次要插入一个新的元素,就需要找到链表的表尾元素,因此这里我们需要借助表尾指针来完成,如下所示:

【数据结构】第二章——线性表(5)_头插法_04

当链表为空表时,表尾指针指向的是头结点,我们对其进行尾插法的步骤则是:

  1. 将新结点的指针域指向表尾指针的指针域指向的对象;
  2. 将表尾指针的指针域指向新结点;
  3. 新结点赋值给表尾指针;

从这个步骤中我们可以看到,其实尾插法与头插法的思路是一样的,只不过多了一个赋值操作,前面两步是在完成插入的步骤,最后一步是在完成表尾指针移动的过程,通过C语言表示出来则是:

New_next->Tail_next;//将新结点的指针域指向表尾结点的指针域所指向的元素
Tail_next->New;//表尾结点的指针域指向新的元素
Tail = New;//表尾指针指向新结点

因此我们就可以得到尾插法的基本格式:

//尾插法的基本格式
LinkList List_TailInsert(LinkList* L)
{
	LNode* s;//指向新结点的指针
	LNode* r;//指向表尾结点的指针
	ElemType x;//存放数据域信息的变量
	……;//获取数据信息
	while (x != EOF)//给循环设置一个结束条件,可以自行设置
	{
		s = (LNode*)calloc(1, sizeof(LNode));//创建新结点
		s->data = x;//将数据信息存放入新结点的数据域中
		s->next = r->next;//将表尾结点的指针域中存放的信息放入新结点的指针域中
		r->next = s;//将新结点的地址存放入表尾结点的指针域中
		r = s;//将表尾指针指向新结点,新结点成为新的表尾结点
		……;//获取新的数据元素
	}
	return(*L);
}

可以看到,尾插法相比于头插法其实就多了一个步骤,表尾指针的移动,之所以头插法不需要,是因为头结点是不会改变的,因此,尾插法从这种插入方式上其实与头插法是一样的,下面我们就通过尾插法来实现一下创建链表:

【数据结构】第二章——线性表(5)_结点_05

可以看到使用尾插法创建的单链表的元素是顺序排列的。因此当我们需要将元素逆置排列的话,我们可以通过头插法来实现,当我们需要将元素顺序排列的话,我们可以通过尾插法来实现。

2.3 单链表创建的时间复杂度

可以看到我们在创建单链表时,不管是头插法还是尾插法,循环中代码执行的次数与节点的个数是一致的,因此单链表创建的时间复杂度为O(n)。

对于不带头结点的单链表在创建时,对于首元素的处理逻辑与带头结点的单链表创建时首元素的处理逻辑是稍有差异的,有兴趣的朋友可以下去尝试着编写一下不带头结点的单链表通过头插法与尾插法的方式进行创建。

结语

咱们今天的内容到这里就结束了,希望大家在阅读完今天的内容后,能够掌握单链表创建的这两种方式。在下一篇内容中,我们会继续介绍单链表的其它基本操作,大家记得关注哦!

最后感谢各位的翻阅,咱们下一篇再见!!!

标签:插法,结点,单链,线性表,创建,元素,第二章,数据结构,指针
From: https://blog.51cto.com/u_16231477/9003766

相关文章

  • 【C语言数据结构】对Lua Table源码的一次劣质学习
    /*new_key*/KLcBoolKLcmCreateMapKeyValue(KLCMAP_PTRpTag,KLCTVALUE_PTRpKv){ KLcBoolkbRet =KL_FALSE; KLcBoolkbIsKvLegal =KL_FALSE; DWORDdwInsertPos =0; DWORDdwFreePos =0; DWORDdwCollisionPos =0; KLCTVALUE_PTRptMainNo......
  • 2017 - 951 数据结构
    题目一、单项选择题1.算法能识别出错误的输入数据并进行适当的处理和反应,称为算法的(①)。A.健壮性          B.正确性            C.并行性         D.时间复杂度2.从一个具有n个结点的单链表中查找其值等于x的结点时,在查找成功的......
  • 【数据结构】P4338 [ZJOI2018] 历史 题解
    P4338先考虑怎么安排崛起的先后顺序最优。但是发现好像没有一个很好的顺序去进行崛起,并且由于\(a_i\)的值域会很大,所以即使知道顺序应该也会难以进行维护。转换一下方向,正难则反。考虑每个点的贡献,但是颜色不同时只会算一次,所以要钦定是哪一个点造成的贡献。令当前考虑的点为......
  • 12.26《程序员的修炼之道》的第二章解读
    第二章的题目是《注重实效的方法》,该章节又分为七小节,每一小节都有一个原则,节节相扣,步步深入,为我们深入的介绍了一些注重实效的方法,我们只要在编程过程中记住这些基本原则,我们就能编写出更快、更好、更强健的代码,甚至可以让这些看起来很容易。  (7)第二章中的第七小节,为我们讲......
  • 《程序员的修炼之道》第二章读书笔记
    第2章《注重实效的途径》是《程序员的修炼之道》中的重要章节,它介绍了一些实践性的方法和技巧,帮助程序员在软件开发中提高效率和质量。在这一章中,作者首先强调了重复的危害。重复的代码和流程可能导致维护难度和出现错误的概率增加。因此,我们需要通过技术手段和工具来减少重复,如自......
  • 【线性表】链表
    本来要先讲数组的,介于之前已经总结过可变数组vector了,故不再开一个专题去介绍用法和原理。但是要提一嘴:数组作为数据结构可以高效地存储和查询给定索引(下标)的数据,其时间复杂度均为O(1),因为这个性质,数组可以用来模拟其他很多数据结构,但是如果要将整个数组进行移位操作,例如在中间插......
  • 【数据结构】第二章——线性表(4)
    线性表的链式表示导言大家好,很高兴又和大家见面啦!!!在前面的内容中我们介绍了线性表的第一种存储方式——顺序存储,相信大家经过前面的学习应该已经掌握了对顺序表的一些基本操作了。今天,我们将开始介绍线性表的第二种存储方式——链式存储。一、链式存储线性表中的数据元素在存储时,......
  • MySQL-索引数据结构
    BTreeB-树即B树。指的是BalanceTree,也就是平衡树,平衡树是一颗查找树,并且所有叶子节点位于同一层。每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点。所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中。B+Tree是B树的一种变形,它是基于B......
  • 数据结构
    数据结构概念a,分析问题,将实际问题抽象出一个人数学模型b,设计一个解决问题的模型c,编写代码,调试,测试得到最后结果什么是数据结构数据 客观事物用符号表示结构· 数据之间的存在的关系 数据结构:计算机存储和组织数据符号,相互之间的关系集合数据结构分类:逻辑结构:数据之间的关系(......
  • 数据结构之<堆>的介绍
    1.简介堆是一种特殊的数据结构,通常用于实现优先队列。堆是一个可以被看作近似完全二叉树的结构,并且具有一些特殊的性质,根据这些性质,堆被分为最大堆(或者大根堆,大顶堆)和最小堆两种。2.基本性质完全二叉树结构:堆必须是一棵完全二叉树,即除了最底层,其他层都是满的,而且最底层的节点都尽量......