[一篇读懂]C语言九讲:线性表应用

news2024/12/26 9:20:04

[一篇读懂]C语言九讲:线性表应用

  • 1. 与408关联解析及本节内容介绍
    • 1 与408关联解析
    • 2 本节内容介绍
  • 2. 线性表的顺序表示原理解析
    • 1 线性表
      • 线性表的定义
      • 线性表的特点
    • 2 线性表的顺序表示
      • 顺序表的定义
      • 顺序表优缺点
      • 顺序表插入操作
      • 顺序表删除操作
      • 动态分配
  • 3. 顺序表的初始化及插入操作实战
  • 4. 顺序表的删除及查询实战
  • 5. 线性表的链式表示
    • 1 单链表
      • 单链表的定义
      • 头结点
      • 链表的优缺点
    • 2 单链表插入操作
    • 3 单链表删除操作
    • 4 单链表查找操作
  • 总结
    • 2
    • 2.1
    • 2.2
    • 3.1
    • 5.1


1. 与408关联解析及本节内容介绍

1 与408关联解析

【2010年顺序表】
42. (13分)设将n (n>1)个整数存放到一维数组R中。试设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p (0<p<n)个位置,即将R中的数据由 ( X 0 , X 1 , … , X n − 1 ) (X_0,X_1,…, X_{n-1}) (X0,X1,,Xn1)变换为 ( X p , X p + 1 , … , X n − 1 , X 0 , X 1 , … , X p − 1 ) (X_p,X_{p+1},…,X_{n-1},X_0,X_1,…,X_{p-1}) (Xp,Xp+1,,Xn1,X0,X1,,Xp1)。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C、C++或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。

【2012年链表】
42. 假定采用带头结点的单链表保存单词,当两个单词有相同的后级时,则可共享相同的后缀存储空间,例如,“loading”和“being”的存储映像如下图所示。
1
设str1和 str2分别指向两个单词所在单链表的头结点,链表结点结构为data | next,请设计一个时间上尽可能高效的算法,找出由str1和str2所指向两个链表共同后缀的起始位置(如图中字符i所在结点的位置p)。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度。

  • 顺序表结合排序。
  • 链表本身。

2 本节内容介绍

本节分为四小节讲解。

  • 第一小节主要针对顺序表的原理进行解析。
  • 第二小节和第三小节主要讲解顺序表的初始化、插入,删除、查找进行实战。
  • 第四小节主要针对链表的原理进行解析。

2. 线性表的顺序表示原理解析

  • 一切数据结构 - 增删查改

1 线性表

线性表的定义

由n (n≥0)个相同类型的元素组成的有序集合。
L = ( a 1 , a 2 , … , a i − 1 , a i , a i + 1 , … , a n ) L=(a_1,a_2,…, a_{i-1},a_i,a_{i+1},…, a_n) L=(a1,a2,,ai1,ai,ai+1,,an)

  • 线性表中元素个数n,称为线性表的长度。当n=0时,为空表。
  • a 1 a_1 a1是唯一的“第一个”数据元素, a n a_n an是唯一的“最后一个”数据元素。
  • a i − 1 a_{i-1} ai1 a i a_i ai的直接前驱 a i + 1 a_{i+1} ai+1 a i a_i ai的直接后继

线性表的特点

  • 表中元素的个数是有限的。
  • 表中元素的数据类型都相同。意味着每一个元素占用相同大小的空间
  • 表中元素具有逻辑上的顺序性,在序列中各元素排序有其先后顺序

注意:
本小节描述的是线性表的逻辑结构,是独立于存储结构的!

2 线性表的顺序表示

简称:顺序表

顺序表的定义

1

  • 顺序表逻辑上相邻的两个元素在物理位置上也相邻。

顺序表的定义:

#define Maxsize 50 //定义线性表的长度
typedef struct 
{
	ElemType data[Maxsize] ; //顺序表的元素
	int len; //顺序表的当前长度
}SqList; //顺序表的类型定义

顺序表优缺点

优点:

  • 可以随机存取(根据表头元素地址和元素序号)表中任意一个元素。
  • 存储密度高,每个结点只存储数据元素。

缺点:

  • 插入和删除操作需要移动大量元素。
  • 线性表变化较大时,难以确定存储空间的容量。
  • 存储分配需要一整段连续的存储空间,不够灵活。

顺序表插入操作

插入

  • 最好情况:在表尾插入元素,不需要移动元素,时间复杂度为O(1)。
  • 最坏情况:在表头插入元素,所有元素依次后移,时间复杂度为O(n)。
  • 平均情况:在插入位置概率均等的情况下,平均移动元素的次数为n/2,时间复杂度为O(n)。

代码片段:

//判断插入位置i是否合法(满足1≤i≤len+1 )
//判断存储空间是否已满(即插入x后是否会超出数组长度)
for(int j = L.len; j >= i; j--) //将最后一个元素到第i个元素依次后移一位
	L.data[j] = L.data[j-1] ;
L.data[i-l] = x; //空出的位置i处放入x
L.len++; //线性表长度加1

顺序表删除操作

删除

  • 最好情况:删除表尾元素,不需要移动元素,时间复杂度为O(1)。
  • 最坏情况:删除表头元素,之后的所有元素依次前移,时间复杂度为O(n)。
  • 平均情况:在删除位置概率均等的情况下,平均移动元素的次数为(n-1)/2,时间复杂度为O(n)。

代码片段:

//判断删除位置i是否合法(满足1≤i≤len)
e = L.data[i-1] ; //将被删除的元素赋值给e
for(int j = i; j < L.len; j++) //将删除位置后的元素依次前移
	L.data[j-1] = L.data[j];
L.len--; //线性表长度减1
  • 注意:插入和删除时,i的合法范围是不一样的。

动态分配

  • 动态分配的数组仍属于顺序存储结构。
#define Initsize 100 //表长度的初始定义
typedef struct {
	ElemType *data; //指示动态分配数组的指针
	int MaxSize,length; //数组的最大容量和当前个数
}SeqList; //动态分配数组顺序表的类型定义

指针指向哪?

C的初始动态分配语句为:

L.data = (ElemType*)malloc(sizeof(ElemType) *Initsize);

C++的初始动态分配语句为:

L.data = new ElemType[Initsize];

3. 顺序表的初始化及插入操作实战

  • 业界命名规范(变量名,或者函数名):
  1. 下划线命名法 list_insert - 不同单词用下划线隔开。
  2. 驼峰命名法 ListInsert - 每个单词的首字母大写。
#include <stdio.h>

#define MaxSize 50
typedef int ElemType; //顺序表存储其他类型元素时,可以快速完成代码修改
//静态分配
typedef struct
{
	ElemType data[MaxSize];
	int length; //当前顺序表中有多少个元素
}SqList;

动态分配
//#define InitSize 100
//typedef struct
//{
//	ElemType *data;
//	int capacity; //动态数组的最大容量
//	int length;
//}SeqList;

//顺序表的插入,因为L会改变,因此这里要用引用,i是插入的位置
bool ListInsert(SqList &L, int i, ElemType element)
{
	//判断i是否合法
	if (i < 1 || i > L.length + 1)
	{
		return false;//未插入成功返回false
	}
	//如果存储空间满了,不能插入
	if (L.length == MaxSize)
	{
		return false;//未插入成功返回false
	}
	//把后面的元素依次往后移动,空出位置,来放要插入的元素
	for (int j = L.length; j >= i; j--)
	{
		L.data[j] = L.data[j - 1];
	}
	L.data[i - 1] = element; //放入要插入的元素
	L.length++;//顺序表长度要加1
	return true;//插入成功返回true
}

//打印顺序表
void PrintList(SqList L) //不需要改变顺序表L的内容,不需要引用
{
	int i;
	for (i = 0; i < L.length; i++)
	{
		printf("%3d", L.data[i]);//为了打印到同一行,不用换行
	}
	printf("\n");
}


//顺序表的初始化及插入操作实战
int main()
{
	SqList L; //定义一个顺序表,变量L
	bool ret; //ret用来查看函数的返回值,布尔型是True,或者False
	ElemType del; //要删除的元素
	//首先手动在顺序表中赋值 - 放置元素
	L.data[0] = 1;
	L.data[1] = 2; 
	L.data[2] = 3;
	L.length = 3;//设置长度
	ret=ListInsert(L,2,60);//大驼峰命名法
	if (ret) //等价于if (true == ret)
	{
		printf("insert SqList success\n");
		PrintList(L);
	}
	else
	{
		printf("insert SqList failed\n");
	}

	return 0;

}

运行结果:
在这里插入图片描述
成功在第二个位置插入了60。


4. 顺序表的删除及查询实战

#include <stdio.h>

#define MaxSize 50
typedef int ElemType; 

typedef struct
{
	ElemType data[MaxSize];
	int length; 
}SqList;

bool ListInsert(SqList &L, int i, ElemType element)
{
	if (i < 1 || i > L.length + 1)
	{
		return false;
	}
	if (L.length == MaxSize)
	{
		return false;
	}
	for (int j = L.length; j >= i; j--)
	{
		L.data[j] = L.data[j - 1];
	}
	L.data[i - 1] = element;
	L.length++;
	return true;
}


void PrintList(SqList L) 
{
	int i;
	for (i = 0; i < L.length; i++)
	{
		printf("%3d", L.data[i]);
	}
	printf("\n");
}

//删除数据表中的元素,因为L会改变,因此这里要用引用,i是删除的位置,e是为了获取被删除的元素的值
bool ListDelete(SqList &L,int i, ElemType &e)
{
	//判断删除的元素的位置是否合法
	if (i < 1 || i > L.length)
	{
		return false;//一旦走到return函数就结束了
	}
	e = L.data[i - 1];//首先保存要删除元素的值
	int j;
	for (j = i; j < L.length; j++)
	{
		L.data[j - 1] = L.data[j];
	}
	L.length--;//顺序表长度减1
	return true;
}

//查找某个元素的位置,找到了会返回对应位置,没找到就返回0
int LocateElem(SqList L, ElemType element)
{
	int i;
	for (i = 0; i < L.length; i++)
	{
		if (element == L.data[i])
		{
			return i + 1;//因为i是数组的下标,加1以后才是顺序表的下标
		}
	}
	return 0;//循环结束没找到
}

//顺序表的删除和查找操作实战
int main()
{
	SqList L; //定义一个顺序表,变量L
	bool ret; //ret用来查看函数的返回值,布尔型是True,或者False
	//首先手动在顺序表中赋值 - 放置元素
	L.data[0] = 1;
	L.data[1] = 2;
	L.data[2] = 3;
	L.length = 3;//设置长度
	ret = ListInsert(L, 2, 60);
	if (ret) 
	{
		printf("insert SqList success\n");
		PrintList(L);
	}
	else
	{
		printf("insert SqList failed\n");
	}

	printf("---------------------------------------------\n");

	ElemType del; 删除的元素存入del内
	ret = ListDelete(L, 1, del);

	if (ret) //等价于if (true == ret)
	{
		printf("delete SqList success\n");
		printf("del element = %d\n", del);
		PrintList(L);//顺序表打印
	}
	else
	{
		printf("delete SqList failed\n");
	}

		int pos;//存储元素位置
	pos = LocateElem(L, 60);
	if (pos)
	{
		printf("find this element\n");
		printf("element pos = %d\n", pos);
	}
	else
	{
		printf("don't find this element\n");
	}
	return 0;
}

运行结果:
1

  • 注意:
    1
    出现这种情况时,是因为顺序表长度没有减1。

5. 线性表的链式表示

顺序表有一些缺点:

  • 插入和删除操作移动大量元素。
  • 数组的大小不好确定。
  • 占用一大段连续的存储空间,造成很多碎片。

1 单链表

单链表的定义

1

  • 链表中逻辑上相邻的两个元素在物理位置上不相邻。
  • 单链表节点的定义:
typedef struct LNode //单链表结点类型
{
	ElemType data; //数据域
	struct LNode *next; //指针域
//当结构体中用到结构体本身时,名字无法省略
}LNode, *LinkList;

链表结点:
1

  • 当指针域为NULL时结尾。

头结点

头结点

  • 头指针:链表中第一个结点的存储位置,用来标识单链表。

  • 头结点:在单链表第一个结点之前附加的一个结点,为了操作上的方便。

  • 若链表有头结点,则头指针永远指向头结点,不论链表是否为空,头指针均不为空,头指针是链表的必须元素,其标识一个链表。

  • 头结点是为了操作的方便而设立的,其数据域一般为空,或者存放链表的长度。有头结点后,对在第一结点前插入和删除第一结点的操作就统一了,不需要频繁重置头指针。但头结点不是必须的

链表的优缺点

优点:

  • 插入和删除操作不需要移动元素,只需要修改指针。
  • 不需要大量的连续存储空间。

缺点:

  • 单链表附加指针域,也存在浪费存储空间的缺点。
  • 查找操作时需要从表头开始遍历,依次查找,不能随机存取。

2 单链表插入操作

  • 创建新结点代码:
 q = (LNode*)malloc(sizeof(LNode))
 q -> data = x;
  • 表头/中间插入元素的代码:
q -> next = p -> next;
p -> next = q;
  • 表尾插入元素的代码:
p -> next=q;
q -> next = NULL;

11

3 单链表删除操作

  • 表头/中间/表尾删除元素的代码:
p = GetElem(L,i-1);//查找删除位置的前驱节点
q = p -> next;
p -> next = q -> next;//结点q断链
free(q);//必须

1

4 单链表查找操作

1

  • 按序号查找结点值的算法如下:
LNode *p = L -> next;
int j=1;
while (p && j < i)
{
	p = p -> next;
	j++;
}
return p;
  • 按值查找结点值的算法如下:
LNode *p = L -> next;
while (p != NULL && p -> data != e) 
{
	p = p -> next;
}
return p;


总结

2

  • 一切数据结构 - 增删查改

2.1

  • a i − 1 a_{i-1} ai1 a i a_i ai的直接前驱 a i + 1 a_{i+1} ai+1 a i a_i ai的直接后继
  • 表中元素的个数是有限的。
  • 表中元素的数据类型都相同。意味着每一个元素占用相同大小的空间
  • 表中元素具有逻辑上的顺序性,在序列中各元素排序有其先后顺序

2.2

  • 顺序表逻辑上相邻的两个元素在物理位置上也相邻。

顺序表优点:

  • 可以随机存取(根据表头元素地址和元素序号)表中任意一个元素。
  • 存储密度高,每个结点只存储数据元素。

顺序表缺点:

  • 插入和删除操作需要移动大量元素。
  • 线性表变化较大时,难以确定存储空间的容量。
  • 存储分配需要一整段连续的存储空间,不够灵活。
  • 动态分配的数组仍属于顺序存储结构。

3.1

  • 业界命名规范(变量名,或者函数名):
  1. 下划线命名法 list_insert - 不同单词用下划线隔开。
  2. 驼峰命名法 ListInsert - 每个单词的首字母大写。

5.1

  • 链表中逻辑上相邻的两个元素在物理位置上不相邻。

  • 头指针:链表中第一个结点的存储位置,用来标识单链表。

  • 头结点:在单链表第一个结点之前附加的一个结点,为了操作上的方便。

  • 若链表有头结点,则头指针永远指向头结点,不论链表是否为空,头指针均不为空,头指针是链表的必须元素,其标识一个链表。

  • 头结点是为了操作的方便而设立的,其数据域一般为空,或者存放链表的长度。有头结点后,对在第一结点前插入和删除第一结点的操作就统一了,不需要频繁重置头指针。但头结点不是必须的

链表的优点:

  • 插入和删除操作不需要移动元素,只需要修改指针。
  • 不需要大量的连续存储空间。

链表的缺点:

  • 单链表附加指针域,也存在浪费存储空间的缺点。
  • 查找操作时需要从表头开始遍历,依次查找,不能随机存取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/21006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务系列之单体架构

随笔 终于迎来了“微服务、云原生”系列文章&#xff0c;这个系列的文章的更新速度博主无法保证能够每个星期一篇&#xff0c;因为这个系列的难度比以往系列都要高&#xff08;以往的系列就没有保证一个星期一更&#xff09;。但是长时间不去写文章&#xff0c;自己可能会慢慢…

Keepalived+LVS部署

目录 一、环境准备 二、实验拓扑 三、部署LVS DR环境 四、LVS服务器配置keepalived 1、安装keepalived 2、修改lvs1服务器keepalived配置 3、修改lvs2服务器keepalived配置 五、客户端测试 1、负责均衡测试 2、LVS服务器高可用测试 一、环境准备 准备4台centos服务器…

学习日记(单元测试、反射、注解、动态代理)

文章目录学习日记&#xff08;单元测试、反射、注解、动态代理&#xff09;一、单元测试1. 单元测试实践2. JUnit 常用注解二、反射1. 反射获取类对象2. 反射获取构造器对象3. 反射获取成员变量对象4. 反射获取成员方法对象三、反射的作用举例1. 绕过编译阶段为集合添加数据2. …

基于生物地理学的优化算法(BBO)用于训练多层感知器(MLP)【多种算法进行比较】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

java中的BigDecimal使用

文章目录1、什么是BigDecimal&#xff1f;2、为什么使用BigDecimal&#xff1f;3、如何使用BigDecimal&#xff1f;&#xff08;1&#xff09;BigDecimal初始化赋值&#xff08;2&#xff09;加减乘除运算&#xff08;3&#xff09;BigDecimal保留两位小数及舍入模式&#xff0…

WFP实现侧边栏导航菜单

菜单导航功能实现&#xff0c;常规的管理系统应该常用&#xff0c;左侧显示菜单条目&#xff0c;点击菜单&#xff0c;右侧切换不同的业务用户控件。 常用菜单可以采用TreeView树形控件特定样式实现 &#xff0c;本文介绍的是使用ExpanderListView的组合形式实现的导航菜单&am…

算法day24|理论基础77

详细布置 理论基础 什么是回溯法&#xff1a;递归函数下面通常有回溯法 它使用的地方&#xff1a;组合&#xff0c;切割&#xff0c;子集&#xff0c;排列&#xff0c;棋盘问题&#xff08;N皇后&#xff0c;解数独&#xff09; 回溯算法的模板: void backtracking(参数)&…

微型计算机基础

微型计算机常用术语 位&#xff08;bit&#xff09;&#xff1a;计算机所能表示的最基本&#xff0c;最小的数据单元。1个二进制位有两种状态0和1 通常情况下0表示低电平&#xff08;接地&#xff09;&#xff0c;1表示高电平接电源&#xff08;VCC&#xff09; 字节&#xff0…

MATLAB 矩阵处理及多项式计算

一、实验目的 &#xff08;1&#xff09;掌握生成特殊矩阵以及矩阵处理的方法 &#xff08;2&#xff09;掌握数据统计和分析的方法 &#xff08;3&#xff09;掌握多项式的常用计算 二、实验原理与实验设备 原理&#xff1a;计算机编程相关知识技能和MATLAB软件编译环境 …

c++——map和set的封装

注&#xff1a;该封装基于前面博客已实现红黑树&#xff0c;map和set封装并不难&#xff0c;主要还是对红黑树的理解 目录 一. 改造红黑树 1. 改变节点的定义&#xff0c;使用更高维度的泛型 2. 红黑树追加迭代器的实现 1. 红黑树迭代器的构造函数和基本框架 2. begin()和e…

2.4、编码与调制

2.4、编码与调制 在计算机网络中。计算机需要处理和传输用户的文字&#xff0c;图片&#xff0c;音频和视频。它们可以统称为消息。 数据是运送消息的实体。 计算机中的网卡将比特 000 和 111&#xff0c;变换成相应的电信号发送到网线。 也就是说&#xff0c;信号是数据的…

[附源码]java毕业设计网络学习平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

LeetCode力扣刷题——更加复杂的数据结构

更加复杂的数据结构 一、引言 目前为止&#xff0c;我们接触了大量的数据结构&#xff0c;包括利用指针实现的三剑客和 C 自带的 STL 等。 对于一些题目&#xff0c;我们不仅需要利用多个数据结果解决问题&#xff0c;还需要把这些数据结构进行嵌套和联 动&#xff0c;进行更为…

五.STM32F030C8T6 MCU开发之RTC模块基础例程

五.STM32F030C8T6 MCU开发之RTC模块基础例程 文章目录五.STM32F030C8T6 MCU开发之RTC模块基础例程0.总体功能概述1.RTC硬件介绍1.1日历的功能1.2 闹钟输出1.3 入侵检测1.4 时间戳事件检测2.RTC软件配置2.1.RTC 模块初始化配置2.2 RTC 开始时间配置2.2.1RTC 年月日 时分秒配置2.…

_linux 进程间通信(管道)

文章目录1. 进程间通信目的2. 进程间通信发展3. 进程间通信分类4. 管道1. 进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多个进程之间共享同样的资源。通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#x…

【English】十大词性之介词

介词 文章目录介词前言一、方位介词1.1 某地1.2 里里外外1.3 上上下下1.4 前前后后1.5 ....中间1.6 ...穿越1.7 ...树上1.8 在...墙上1.9 旁边(距离远近区分)二、时间介词三、方式介词四、易混淆介词4.1 制成4.2 交通工具4.3 除了总结前言 介词是表示名词、代词与句子中其它词…

02Java线程模型

1. 操作系统线程 无论使用何种编程语言编写多线程程序&#xff0c;最终都是通过调用操作系统的线程来执行任务。线程是CPU调度的最小执行单元。 线程有多种实现方式&#xff0c;常见的有&#xff1a;内核线程、用户线程、混合线程。 不同线程模型的主要区别在于线程的调度方不…

【Ubuntu】配置ubuntu网络

配置ubuntu网络 一、三种虚拟网络介绍二、 配置ubuntu系统使用桥接模式连接外网三、通过NAT模式让ubuntu系统连接外网四、常见问题1.解决ubuntu系统没有网络图标一、三种虚拟网络介绍 VMnet0 : 桥接模式,选中桥接模式之后,可以将VMnet0桥接到对应的物理网卡之上, 默认选中自…

uniapp公共新闻模块components案例

uniapp公共新闻模块components案例 简介&#xff1a;本文使用uniapp的公共新闻模块讲解components案例。 效果展示&#xff1a; 第一步 创建公共模块 第二步 编写组件 <template><view class"newsbox"><view class"pic"><ima…

动态路由协议 OSPF 工作过程 之 状态机维度

状态机 &#xff1a; # 什么是状态机呢 &#xff1f; 状态机 &#xff1a; 就是 OSPF 路由间的邻居关系所在的不同阶段 不同的关系 就是 不同的状态机 OSPF 的状态机 &#xff1a; # 我们用 思科 的PPT 来介绍 OSPF 的状态机 # 里面所有黄颜色方框里 标定的就是 状态机…