栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

线性表——顺序表

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

线性表——顺序表

线性表

概念:具有相同数据类型的n(n>0)个数据元素的有限序列,其中n为表长,当n=0时,为空表。若使用L命名线性表,其一边表示为
L = ( a 1 , a 2 , a 3 . . . a i , a i + 1 . . . a n ) L = (a_1,a_2,a_3...a_i,a_{i+1} ... a_n) L=(a1​,a2​,a3​...ai​,ai+1​...an​)
其中 a 1 a_1 a1​为表头, a n a_n an​为表尾
每个元素都有且仅有一个前驱和后继(除了表头和表尾)
ps: 区别数据元素和数据项。以链表为例,他的数据元素是节点。节点中有两个数据项。

线性表的特点
  • 表中元素有限
  • 表中元素有逻辑上的顺序性,其中元素有先后次序
  • 每个数据都是数据元素,每个元素都是单个元素
  • 表中元素的数据类型都相同,这意味着每个元素所占空间大小相同的存储空间
  • 表中元素具有抽象性,仅讨论元素之间的相邻关系
线性表的基本操作
InitList(L)   		  1.初始化表
Length(L)             2.求表长
LocateElement(L,b)    3.按位查找
GetElement(L,v)       4.按值查找
ListInsert(L,ind,v)   5.插入操作
ListDelete(L,ind)	  6.删除操作
PrintList(L)		  7.输出操作
Empty(L)			  8.判空操作
Delete(L)			  9.销毁操作
顺序表

线性表的顺序存储称为顺序表,用一组地址连续的存储单元依次存储线性表中的数据元素。即顺序表的两元素不仅逻辑相邻,物理位置也相邻。逻辑顺序与物理顺序相同
顺序表可以按照数组来理解。

顺序表特点
  1. 顺序表主要特点是随机访问,即通过首地址和元素序号可在时间O(1)内找到指定元素
  2. 顺序表的存储密度高,每个节点只存储数据元素
  3. 顺序表逻辑上相邻的元素物理上也相邻,所以插入和删除需要大量元素。
顺序表实现

我们使用C语言来实现,首先有两个准备知识,一个是结构体的使用,第二个我准备创建一个可动态分配空间的顺序表,所以我们需要使用stdlib.h头文件中的内存管理函数。
然后我们需要明确一个顺序表创建需要什么,以及有哪些操作方法。参照上面线性表的操作方式。

  1. 首先需要创造一个结构体作为顺序表,其中包括一维数组存放数据,还有当前表长度,以及容量上限(因为我们创建动态分配的)
  2. 其次我们需要有的操作有:初始化顺序表, 删除顺序表,另外对于数据有删除,和插入。以及为了我们方便检验还有一个输出。
#include 
#include     //申请内存空间

typedef struct List{
	int *data;   			// 数据
	int len,cmp;  			// 当前长度, 容量 
}list; 

在创建结构体中可以看到,在数组定义时,我是采用了指针而非数组。如果直接定义数组,那么就直接指定了数组长度,就变成了静态分配,而且对于结构体来说也比较占用空间。定义指针之后开辟空间就只是指针大小,小了很多,也可以通过内存管理适当调整数组容量。


//初始化顺序表 
list *InitList(){
	list *a = (list *)malloc(sizeof(list));
	a->data = (int *)malloc(sizeof(int) * 3);
	a->len = 0;
	a->cmp = 3;
	return a;
} 

初始化数组malloc()申请堆内存,可以看到data数组长度可以放3个int类型数据。同时记得初始化长度和容量的数值。


//删除顺序表 
int DeleteList(list *p){
	free(p->data);
	free(p);
	return 1;
}

有初始化就要有删除,但是要注意的是,不可以直接释放顺序表,因为在顺序表中的data数组也是申请的内存的空间,如果直接释放顺序表的结构体,那么就会找不到数组位置,但是它又是被占用的,造成内存泄漏。所以应该先释放数组,再释放顺序表。


//插入元素
int InsertData(list *p, int loc, int val){
	if(loc > p->len || loc < 0){  			//只允许在数据位置范围内插入 
		return -1;
	}
	
	if(p->len + 1 > p->cmp){				//当数据存储容量不够时进行扩容 
		p->cmp *= 2;
		p->data = (int *)realloc(p->data, sizeof(int) * p->cmp);
		printf("realloc done!n"); 
	}
	
	for(int t = p->len;t > loc;t--){
		p->data[t] = p->data[t - 1];
	}
	p->data[loc] = val;
	p->len++;
	return 1;	
} 

插入元素时,我们应该考虑两种情况:

  1. 插入的位置是否合法,比如我们只有三个元素,就不能插入位置6
  2. 当达到我们的数据上限时,要进行扩容操作

插入时,若是尾部直接插如就好,但是其他位置就应该是,先把该位置到末尾的元素整体向后挪一位,之后再写入数据。一个萝卜一个坑嘛,要插入一个新萝卜就要把他的坑里原来的萝卜依次往后放。


//删除元素
int DeleteData(list *p, int loc){
	if(p->len <= loc){
		return -1;
	}
	for(int i = loc - 1; i < p->len; i++){
		p->data[i] = p->data[i+1];
	}
	p->len--;
	return 1;
}

删除元素的时候,也是同样的道理,这颗萝卜拔出来,那么他的坑就需要后面的萝卜向前补上,当然可能会对代码有疑问就是整体向前挪一位,那么最后一个数据元素不就有两个了,不需要删除吗?不需要,因为我们的顺序表大小由len体现,超过len的元素不属于我们需要的范畴。


//输出当前顺序表 
void show(list *p){
	for(int i = 0;i < p->len; i++){
		printf("%d ",p->data[i]); 
	} 
	printf("n");
}

这个就是为了方便检验的输出函数,遍历数组输出。


int main(){
	//初始化数组
	list *p = InitList();
	
	int a,b,c;    //定义三个操作变量
	a = 0;
	while(a!=4){
		printf("输入您的操作指令:");
		scanf("%d %d",&a ,&b);    //a是指令,b是位置
		if(a == 1){         //a==1 插入操作
			scanf("%d", &c);// c插入值
			InsertData(p, b, c);
			show(p);
		}
		if(a == 2){  //a == 2 删除操作 
			DeleteData(p, b);
			//DeleteData
			show(p);
		}
		if(a == 3){   //  a==3  释放顺序表
			DeleteList(p);
		}
	}
}

在主函数测试上述代码效果。


这里可以看到都是正常运行,也有正常的扩容操作,另外可以看到再第四次操作的时候1 4 5,结果并没有变化,就是因为当时我的输入位置是非法的。

这就是基本顺序表的内容啦!!!

复习

线性表的顺序存储结构是一种随机存储结构,这是顺序表最主要的特点,可通过下标进行随机访问
另外顺序表存储密度高,他每个节点只存储数据元素
顺序表不仅仅是满足线性表的逻辑上相邻物理上也是相邻的,所以在进行删除,插入的时候需要大量移动元素

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/999732.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号