2021-06-27数据结构——线性表

数据结构——线性表

基本知识:
数据结构有三要素:逻辑结构、存储结构、运算
1、逻辑结构
逻辑结构
2、存储结构
存储结构
3、运算
运算
** 根据上面的基本知识,我们可以知道,任一个逻辑结构都有两种存储结构和四种基本运算。如:线性结构中的线性表就有顺序存储和链式存储两种存储结构,每一种结构里也对应着有四种基本的运算,增删改查。**

线性表

线性表,是N个具有相同数据类型的数据元素的有限序列
N为表长,当N=0时,该线性表为空。

例如
播放器的播放列表,线性表
班级花名册,线性表
班上人际关系,不是线性表

线性表——顺序存储(顺序表)

用一段地址是连续的存储单元,来存储线性表中的数据元素。

顺序表定义——静态分配空间

#define SIZE 100;			//宏定义SIZE为100,也就是在后面的程序中出现了SIZE都代表100,成为以一个常量。

typedef int data_t;			//typedef 为一个重命名关键字,将int数据类型,重命名为data_t,除了名字不同以外,功能都相同,好处在于,当我希望把我的所有int类型改为其他类型的时候,只需要更改这里的int
typedef struct list{
		data_t data[SIZE]//用固定大小的数组来存放数据,这就是静态分配,在‘栈区’开辟空间;
		int last;				//用来存放data[SIZE]数组里最后一个下标的值;
}seqlist; 						//因为用了typedef,所有后面需要用这个结构体的时候,直接用seqlist就行

顺序表定义——动态分配空间

#define SIZE 100;			//宏定义SIZE为100,也就是在后面的程序中出现了SIZE都代表100,成为以一个常量。

typedef int data_t;			//typedef 为一个重命名关键字,将int数据类型,重命名为data_t,除了名字不同以外,功能都相同,好处在于,当我希望把我的所有int类型改为其他类型的时候,只需要更改这里的int
typedef struct list{
		data_t data[SIZE]//用固定大小的数组来存放数据;
		int last;				//用来存放data[SIZE]数组里最后一个下标的值;
}seqlist; 						//因为用了typedef,所有后面需要用这个结构体的时候,直接用seqlist就行
seqlist *createSeqlist{			//初始化线性顺序表
		seqlist *seq=(seqlist *)malloc(sizeof(seqlist))	//使用malloc函数在‘堆区’开辟空间
}

顺序表的基本操作
1、初始化

seqlist *createSeqlist(){	//因为返回值是*seq所指地址,所有需要定义为一个指针函数
	seqlist *seq=(seqlist *)malloc(sizeof(seqlist));	//在堆区动态开辟空间
	if(NULL==seq)	//判断是否成功使用malloc函数在堆区开辟空间,这样写避免将比较运算符==误写为赋值运算符=
		return NULL;
	memset(seq->data,0,sizeof(seq->data));	//将seq->data所指的大小为sizeof(seq->data)空间清0
	seq->last=-1;	//将seq->last赋值为-1,就可以代表数组中最后一个数值的下标,seq->last+1则为长度
	return seq;

2、判断顺序表是否为空

int seqlist_is_empty(seqlist *seq){
	if( seq == NULL)	//同上
		return -1;

	return ((seq->last == -1)?1:0);	//使用三木运算符,当下标为-1时,也就是顺序表中没有值时,则返回1;若不唯一则证明顺序表不为空,则返回0
}

3、判断顺序表是否满

//和判断是否为空,异曲同工
int seqlist_is_full(){
	if(seq == NULL)
		return -1;

	return ( (seq->last+1 == SIZE )?1:0 );
}

4、求顺序表长度

int seqlist_length(seqlist *seq){
	if(seq == NULL)
		return -1;

	return seq->last+1;		//Seq->last代表顺序表的最后一个值的下标,最后一个值的下标+1则为长度
}

last+1=len

5、按位置插入内容

int insertSeqlistByPos(seqlist *seq,int pos,data_t data){
	if(seq == NULL)
		return -1;

	if(seqlist_is_full(seq) == 1)	//判断顺序表是否已经满了,如果满了则不能继续插入数据
		return -1;

	int len = seqlist_length(seq);	//定义一个变量接收顺序表的长度,判断所插入位置是否在可插入范围内

	if(pos < 0 || pos > len)
		return -1;

	int i;
	for(i = seq->last ; i>= pos; i--)	//如果在可插入范围内,则开始插入
	{
		seq->data[i+1]  = seq->data[i];		//顺序表中插入一个值,需要先将所查位置以及后面所有值一个一个往后挪出一个位置来,让给插入的值
	}

	seq->data[pos] = data;

	seq->last++;	//因为插入了一个值,整体往后挪了一位,所以数组最后一个指针也应该往后移一位
}

顺序表插入

6、按位置删除内容

int deleteSeqlistByPos(seqlist *seq, int pos)
{
	if(seq == NULL)
		return -1;

	if(seqlist_is_empty(seq)  == 1)
		return -1;

	int len = seqlist_length(seq);
	
	if(pos < 0 || pos > seq->last)
		return -1;


	int i;
	for(i=pos; i<seq->last; i++)
	{
		seq->data[i] = seq->data[i+1];
	}

	seq->last--;

}

顺序表删除

7、按位置查找内容

data_t findSeqlistByPos(seqlist *seq, int pos)
{
	if(NULL == seq)
		return -1;

	if( seqlist_is_empty(seq) == 1)
		return -1;

	int len = seqlist_length(seq);

	if(pos < 0 || pos > seq->last)
		return -1;

	return seq->data[pos];
}

8、按位置更改内容

int changeSeqlistByPos(seqlist *seq, int pos, data_t data)
{
	if(NULL == seq)
		return -1;

	if( seqlist_is_empty(seq) == 1)
		return -1;

	int len = seqlist_length(seq);

	if(pos < 0 || pos > seq->last)
		return -1;

	seq->data[pos] = data;
}

9、按内容查找下标

int findSeqlistByData(seqlist *seq, data_t data)
{
	if(NULL == seq)
		return -1;

	if(seqlist_is_empty(seq) == 1)
		return -1;
	
	int i;
	for(i=0 ; i<= seq->last; i++)
	{
		if( seq->data[i] == data)
		{
			return i;
		}
	}
}

10、按内容删除

int deleteSeqlistByData(seqlist *seq, data_t data)
{
	int pos = findSeqlistByData(seq, data);

	deleteSeqlistByPos(seq, pos);
}

11、按内容修改

int changeSeqlistByData(seqlist *seq, data_t old_data, data_t new_data)
{
	int pos = findSeqlistByData(seq, old_data);

	changeSeqlistByPos(seq, pos, new_data);
}

12、打印顺序表

void displaySeqlist(seqlist *seq)
{
	if(NULL == seq)
		return;

	if(seqlist_is_empty(seq) == 1)
		return;

	int i;
	for(i=0; i<=seq->last; i++)
	{
		printf("%d ", seq->data[i]);
	}

	puts("");
}

13、清空

void clearSeqlist(seqlist *seq)
{
	if(NULL == seq)
		return;
	
	seq->last = -1;
}

14、销毁

void destroySeqlist(seqlist **seq)
{
	free(*seq);

	*seq = NULL;
}

15、测试主函数

int main(int argc, const char *argv[])
{
	//静态分配, 定义一个结构体变量即可
	seqlist seq = { {0}, -1 };


#if 0
	seqlist *seq = createSeqlist();
	if(NULL == seq)
	{
		printf("malloc falied!\n");
		return -1;
	}
#endif
	int n = seqlist_is_empty(&seq);
	printf("line:%d n:%d\n", __LINE__, n);

	int m = seqlist_is_full(&seq);
	printf("line:%d m:%d\n", __LINE__, m);

	int len = seqlist_length(&seq);
	printf("line:%d len:%d\n", __LINE__, len);
	
	//按位置来插入数据元素
	int i = 0;
	while(i<10)
	{
		insertSeqlistByPos(&seq, i, i+1);
		i++;
	}

	len = seqlist_length(&seq);
	printf("line:%d len:%d\n", __LINE__, len);

	displaySeqlist(&seq);

	//按位置来删除数据元素
	deleteSeqlistByPos(&seq, 2);
	displaySeqlist(&seq);


	len = seqlist_length(&seq);
	printf("line:%d len:%d\n", __LINE__, len);


	//按位置来查找数据元素
	data_t data = findSeqlistByPos(&seq, 5);
	printf("data = %d\n", data);

	//按位置来修改数据元素
	changeSeqlistByPos(&seq, 1, 250);
	displaySeqlist(&seq);





	//按值来查找数据元素
	int pos = findSeqlistByData(&seq, 250);
	printf("line:%d pos = %d\n", __LINE__, pos);

	//按值来删除数据元素
	deleteSeqlistByData(&seq, 7);
	displaySeqlist(&seq);

	//按值来修改数据元素
	changeSeqlistByData(&seq, 10, 100);
	displaySeqlist(&seq);




	//清空顺序表
	clearSeqlist(&seq);
	displaySeqlist(&seq);

	len = seqlist_length(&seq);
	printf("line:%d len:%d\n", __LINE__, len);

	//销毁顺序表
	destroySeqlist(&seq);

	printf("%p\n", seq);

	return 0;
}

线性表——链式存储(链表)

四种链表

1、单链表

单链表
插入
单链表插入
删除
单链表删除

双链表

双链表
插入
双链表插入
删除
双链表删除

单向循环链表

单向循环链表
单向循环链表样子
插入、删除等同单链表一样,只是判断这个链表是否遍历完的条件变成了是否等于head

双向循环链表

双向循环链表
双向循环链表样子
插入、删除等同双向链表,只是判定是否遍历完成的条件从是否等于NULL变为了是否等于head

顺序表VS链表

顺序表
1、【支持随机访问】:因为顺序表的结构同数组的结构是一样的,可以利用下标来任意访问数据
2、【存储密度较高】:因为数组每个存储单元的密度为1,每个单元都是用来存储数据的,所以不存在浪费空间
3、【是一大片的连续的存储空间,分配空间和改变容量都不方便】
4、【插入和删除元素是,其后元素都要往后或往前移动,不方便】

链表
1、【不支持随机访问】:因为链表是采用链式存储结构,只能通过遍历,从头节点开始找,直到找到相应节点。
2、【存储密度较低】:因为链表的每个存储单元都需要存储非数据项,如还需分配一部分空间出来存储next/prior指针,所有会造成一部分空间的浪费,存储密度较低
3、【离散的小空间分配方便,改变容量也方便】
4、【插入和删除节点时只需改变节点的连接即可】

综合上述所言,顺序表和单链表各有各的优缺点,使用哪一种会好一些要结合具体的问题而言,不能一概而论。

比如:
在查询操作使用的比较频繁时,使用顺序表会好一些;
在插入、删除操作使用的比较频繁时,使用单链表会好一些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值