小猪的数据结构学习笔记(二)

小猪的数据结构学习笔记(二)

线性表中的顺序表

本节引言:

在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的

逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法

的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构——线性表;

而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石;

这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己

写得出来,给出的实现代码,自己要理解思路,自己写出来!写多了就有感觉了!多思考!!

另外附上学习数据结构的一个利器,数据结构演示动画,在本文结尾给出!

好了,废话就这么多!

本节学习路线图

路线图解析:

①抽象数据类型就那三要素:数据,数据之间的关系,和数据的操作

②线性表就是按一条线排列的数据集合,1对1,除了首元和尾元,其他元素都有直接前驱和直接后继

③顺序表有点像以前学习的数组,要小心注意表中的第i个元素是对应 i - 1那个位置的数据的!!!!

④基本存储结构要牢记,至于12个基本操作,除了插入和删除有点小难度,其他的都很简单,要自己将代码写多几遍哦!

⑤求并集的那个,也不是很难懂,自己拿笔画下图,想一想应该就懂了!去除表中的重复元素占时没想到什么好的方法,有好的欢迎提出!

正文:

一.抽象的数据类型

二.线性表中的顺序表

三.相关操作的代码实现与解析:

1.线性表的存储结构:

<span style="font-family:Microsoft YaHei;">#define MAXSIZE 20
#define INCREMENT  10
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
//定义一个int数据类型的别名
//这里因为演示采用int,实际使用的通常是复合的数据类型
typedef int ElemType;
typedef int Status;

typedef struct
{
	ElemType *elem;  //存储空间的起始地址
	int length; 	//表的当前长度
	int listsize;   //表的总共存储容量(sizeof(ElemType))
}SqList;</span>

2.构造空表

<span style="font-family:Microsoft YaHei;">//创建一个空表:
void InitList(Sqlist &L)
{
	L.elem = (ElemType *)malloc(MAXSIZE * sizeof(ElemType));
	if(!L.elem) exit(ERROR);
	L.length = 0;
	L.listsize = MAXSIZE;
} </span>

代码解析

:步骤:

①申请表的存储空间,将空间的其实地址赋值给elem,然后通过判断elem是否为空,从而知道内存是否分配成功

②将表的当前长度length设置为0,将表的大小listsize设置为MAXSIZE

3.将表置为空表

<span style="font-family:Microsoft YaHei;">//将表置为空表
void ClearList(SqList &L)
{
	L.length = 0;
} </span>

代码解析:

只需要将表的长度length设置为0就可以了,很简单吧

4.判断是否为空表

<span style="font-family:Microsoft YaHei;">//判断表是否为空表
 Status ListEmpty(SqList L)
 {
 	if(L.length == 0)return TRUE;
 	else return False;
 }</span>

代码分析:

同样只需要判断length的值是否为0就可以了,很简单

5.销毁表

<span style="font-family:Microsoft YaHei;">//销毁表
void DestroyList(SqList &L)
{
	free(L.elem);
	L.elem = NULL;
	L.length = 0;
	L.listsize = 0;
} </span>

代码分析:

步骤:

①调用free函数释放L,elem指向的内存空间的内存

②将L.elem赋值为NULL,即空指针

③将表的当前长度Length和表的最大长度listsize设置为0

6.获得表中的数据元素数目

<span style="font-family:Microsoft YaHei;">//获得当前表中元素的数目
int ListLength(SqList L)
{
	return L.length;
} </span>

代码分析:

直接返回当前长度length即可

7.获得表中第i个数据元素的值

<span style="font-family:Microsoft YaHei;">//获得表中第i个元素的值,通过e的值反映
Status GetElem(SqList L,int i,ElemType &e)
{
	if(i < 1|| i > L.length)
	return ERROR;
	e = *(l.elem + i - 1);
	return OK;
} </span>

代码分析:

①先判断第i个位置是否合法

②将对于位置的值赋值给e,另外减一是因为数组是下标是从0开始的!!

而我们看表是从1开始算的,所以需要减一

8.查找表中是否有满足要求的元素

<span style="font-family:Microsoft YaHei;">//返回表中第一个满足要求的元素的下标
//这里我们把要求假设为一个函数compare(int l_s,int e);
//参数依次为表中元素与需要进行关系比较的参数e
//第三个参数函数指针,旨锤向函数的指针
int LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType))
{
	int i = 1;
	ElemType *p = L.elem;
	while(i < L.length && !compare(*p++,e))
	i++;
	if(i <= L.length) return i;
	else return 0;
} </span>

代码分析:

步骤:

①定义变量i和指针p分别执行表中第1个元素和表的首地址

②循环调用compare()函数与表中的元素进行比较

③如果i <= length的话说明找到了,返回对应元素的序号

④否则返回0表示找不到

9.返回某个节点的前驱

<span style="font-family:Microsoft YaHei;">//返回某个节点的直接前驱
//第二和第三个参数分别为:指定的数据元素,before用来存储它的前驱的
Status PriorElem(SqList L,ElemType choose,ElemType &before)
{
	int i = 2;
	ElemType *p = L.elem + 1;
	while(i <= L.length && *p != choose)
	{
		p++;
		i++;
	}
	if(i > L.length)return ERROR;
	else
	{
		before = *--p;
		return OK;
	}
} </span>

代码分析:

①首元是没有前驱的,所以i从2,p从L.elem +1 开始算

②通过循环查看指定数据元素在表中的位置,如果i > L.length表示找不到,返回ERROR

③找到的话,通过*--p获取该元素前驱的值赋值给before变量

10.返回某个节点的后继

<span style="font-family:Microsoft YaHei;">//返回某个支点直接后继
//第二三个参数依次为:选定的数据元素的值,存储后继的变量
Status NextElem(SqList L,ElemType choose,ElemType &behind)
{
	int i = ;
	ElemType *p = L.elem;
	while(i < L.length && *p != choose)
	{
		p++;
		i++;
	}
	if(i == L.length)return ERROR;
	else
	{
		behind = * ++p;
		return OK;
	}
} </span>

代码分析:

①和上面的前驱差不多,要注意的是i == L.length就可以了,因为尾元没有后继,所以直接把尾元排除了!

11.往表中第i个位置插入元素

<span style="font-family:Microsoft YaHei;">//往表的第i个位置插入元素e
Status ListInsert(SqList &L,int i,ElemType e)
{
	ElemType *p,*q,*newbase;
	//插入位置为1-length,其他值不合法
	if(i<1||i>L.length + 1)return ERROR;
	//如果表满了的话,增加分配的空间
	if(L.length == L.listsize)
	{
		newbase = (ElemType)realloc(L.elem,(L.listsize + INCREMENT)*sizeof(ElemType));
		if(!newbase)exit(ERROR);
		L.elem = newbase;
		L.listsize += INCREMENT;
	}
	p = L.elem + i - 1;
	//向右移,先移动最后一个
	for(q = L.elem + L.length - 1;q >= q;--q)
	*(q + 1) = *q;
	//将e插入,表长+1
	*q = e;
	++L.length;
	return OK;
} </span>

代码解析:

12.删除表中第i个位置的元素

<span style="font-family:Microsoft YaHei;">//删除表中第i个位置的元素
Status ListDelete(SqList &L,int n,ElemType &e)
{
	ElemType *p,*q;
	//判断删除的位置是否合法
	if(i < 1 && i > L.length)return ERROR;
	//指向删除的位置,将值付给e
	p = L.elem + i - 1;
	e = *p;
	//指向尾元,由删除位置的后继元素开始前移
	q = L.elem + L.length - 1;
	for(++p;p <= q;p++)
	*(p - 1) = *p;
	L.length--;
	return OK;
}</span>

代码分析:

13.遍历顺序表所有元素

<span style="font-family:Microsoft YaHei;">//遍历线性表所有元素
void ListTraverse(SqList L,void(*visit)(ElemType&))
{
	int i = 1;
	ElemType *p = L.elem;
	for(i ==1;i <= L.length;i++)
	{
		visit(*p++);
		printf("\n");
	}
} </span>

代码解析:

代码很简单,就是从第一个元素开始,让指针后移,依次调用visit()函数

实现表中元素的遍历

14.应用小示例:

已知A,B两个顺序表中的元素是按从小到大排列的;现在要你求两个的并集C;

而且C中的元素也要按从小到大排序;不改变A和B中的数据!

是并集哦,就是C中不能有重复的元素

<span style="font-family:Microsoft YaHei;">void UnionList(SqList La,SqList Lb,SqList &Lc)
{
	//定义指向La,Lb表头表位的指针,以及指向Lc的指针
	ElemType *la,*la_end,*lb,*lb_end,*lc;
	la = La.elem;
	lb = La.elem;
	la_end = La.elem + La.length - 1;
	lb_end = Lb.elem + Lb.length - 1;
	//在这里为lc分配内存空间,大小为La.length + Lb.length
	Lc.listsize = Lc.length = La.length + La.length;
	lc = Lc.elem = (ElemType *)malloc(Lc.listsize * sizeof(ElemType));
	if(!Lc.elem)exit(ERROR);
	//将a,b中的元素进行合并
	//如果a,b中都有元素还没有合并
	while(la <= la_end && pb <= lb_end)
	{
		if(*la <= *lb)*lc++ = *la++;
		else *lc++ = *lb++;
	}
	//假如还有剩下的元素,要么是a,要么是b
	while(la <= la_end)*lc++ = *la++;
	while(lb <= lb_end)*lc++ = *lb++;

	//接着要将Lc中重复的元素删除掉
	ElemType *p,*q;
	p = Lc.elem;
	q = p;
	//使用两枚指针p,q,如果指针p没有指向末尾
	while(p != (Lc.length - 1))
	{
		//q指向p的后缀,比较两数的值
		if(*p != *(++q))
		{
			p++;
			q = p;
		}
		//相等的话,删除q指向的元素
		//再次进行比较,直到不重复为止
		else
		{
			while(*p == *q)
			ListDelete(Lc,(p - Lc.elem),e);
		}
	}
}</span>

ps:最后去除Lc中的重复元素的算法似乎有点累赘,如有高效点的算法,欢迎提出,万分感激啊!

本章小结:

①什么是抽象的数据类型ADT

②线性表的定义与线性表的特性

③顺序表:地址连续的存储单元一次存储的线性表

④顺序表的结构,三个基本属性

⑤顺序表的12个相关操作

⑥顺序表的使用小示例

学习资源下载:

本节代码打包:点击下载

数据结构演示工具:点击下载

小猪的数据结构学习笔记(二),布布扣,bubuko.com

时间: 2024-12-09 17:22:29

小猪的数据结构学习笔记(二)的相关文章

小猪的数据结构学习笔记(四)

小猪的数据结构学习笔记(四) 线性表之静态链表 --转载请注明出处:coder-pig 本章引言: 在二,三中中我们分别学习了顺序表中的线性表与单链表,线性表有点类似于 我们前面所学的数组,而单链表使用的最多的是指针,这里问个简单的问题, 如果是在以前没有指针的话,前辈先人们怎么实现单链表呢?大家思考下! 没有指针,那么用什么来代替呢?前辈先人们非常机智,想出了使用下标+游标的方式 来实现单链表的效果!也就是今天要讲的--静态链表! 当然你也可以直接跳过本章,因为有了单链表就没有必要用静态链表了

小猪的数据结构学习笔记(三)

小猪的数据结构学习笔记(三) 线性表之单链表 本章引言: 上一节中我们见识了第一个数据结构--线性表中的顺序表; 当你把操作的代码自己写几遍就会有点感觉了,如果现在让你写顺序表的 插入算法,你能够想出大概的代码么?如果可以,那么你就可以进入新的章节了; 否则,还是回头看看吧!在本节,我们将迎来线性表的链式表示--单链表 单链表和顺序表有什么优势和劣势呢?单链表的头插法和尾插法有什么不同呢? 请大家跟随笔者的脚步来解析线性表中的单链表把! 本节学习路线图 路线图解析: ①先要理解顺序表和单链表各自

小猪的数据结构学习笔记(五)

小猪的数据结构学习笔记(五) 线性表之--循环链表                           --转载请注明出处:coder-pig 循环链表知识点归纳: 相关代码实现: ①判断是否为空表: ②单循环链表的存储结构 其实和单链表的结构是一样的! /*定义循环链表的存储结构*/ typedef struct Cir_List { int data; struct Cir_List *next; }Lnode; ③初始化循环单链表 代码如下: //1.循环链表的初始化 //表示一个元素,如

C数据结构学习笔记二 循环和递归打印fibonacci函数

//循环方式实现 #include <stdio.h> int main(int argc, char *argv[]) { int f1=0,f2=1,f3; printf("%d ",f1); printf("%d ",f2); while(f1<15) { f3=f1+f2; printf("%d ",f3); f1=f2; f2=f3; } return 0; } //递归方式实现 #include <stdio.

【数据结构学习笔记(C#描述)】(二)算法分析

由上一章的内容可知软件质量的重要特征之一就是能够高效的利用资源(运行效率),因此我们就要考虑如何创建出能够高效利用CPU及内存的数据结构与算法.而算法分析的目的就是为了让我们能够认识到算法对于资源的利用效率. 我们要想分析算法的效率,就需要找到一个评价算法效率的标准及方法. 一般我们如果能快速的利用CPU就会更好的节省时间,因此在时间层面上我们的评价标准就是时间复杂度,而如果我们能够较好的利用内存的话我们将会节省更多的内存空间,因此在空间层面上我们的评价标准就是空间复杂度. 所谓时间复杂度和空间

APUE 学习笔记(二) 文件I/O

1. 文件I/O 对于内核而言,所有打开的文件都通过文件描述符引用,内核不区分文本文件和二进制文件 open函数:O_RDONLY  O_WRONLY  O_RDWR create函数: close函数:关闭一个文件时还会释放该进程加在该文件上的所有记录锁 lseek函数:显式地为一个打开的文件设置其偏移量 每个打开的文件都有一个与其相关联的 "当前文件偏移量",用以度量从文件开始处计算的字节数,通常,读.写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数 文件偏移量可以大于

Ajax学习笔记(二)

二.prototype库详解 1.prototype库的使用 //导入下载好的prototype.js文件 <script type="text/javascript" src="prototype.js"></script> //在自己的js中直接使用Prototype对象 <script type="text/javascript"> document.writeln("Prototype库的版本

数据结构学习笔记——绪论

数据结构学习笔记——绪论 为了更贴切的描述一种数据结构,通常采用二元组表示:(对于一种数据结构其逻辑结构唯一) B=(D,R)其中,B是一种数据结构,它由数据元素的集合D和D上二元关系的集合R所组成.即D={ di | 1 <= i<= n, n > 0}R={ rj | 1 <= j<= n, n > 0}D 上的一个关系r是序偶的集合,对于r中任一序偶<x,y>(x,y属于集合D),把x叫做偶序第一节点,把y叫做偶序第二结点,又称序偶的第 一结点为第二结

Caliburn.Micro学习笔记(二)----Actions

Caliburn.Micro学习笔记(二)----Actions 上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions,看一下Caliburn.Micro给我们提供了多强大的支持 我们还是从做例子开始 demo的源码下载在文章的最后 例子1.无参数方法调用 点击button把textBox输入的文本弹出来 如果textbox里没有文本button不可点,看一下效果图 看一下前台代码 <Stac