数据结构-顺序表专题

发布于:2025-02-28 ⋅ 阅读:(147) ⋅ 点赞:(0)

大家好!这里是摆子,今天给大家带来的是C语言数据结构开端-顺序表专题,主要介绍了数据结构和动态顺序表的实现,快来看看吧!记得一键三连哦!

1.数据结构的概念

1.1什么是数据结构?

数据结构是计算机存储、组织数据的⽅式。

分开看,由“数据”和“结构”两词组合而成。例如农户养羊🐑,每一只羊都是一个数据,但是面临庞大的羊群,想要找到草原上名叫“咩咩”的⽺很难,但是从⽺圈⾥找到1号⽺就很简单,⽺圈这样的结构有效将⽺群组织起来。
数据结构反映数据的内部构成,即数据由那部分构成,以什么⽅式构成,以及数据元素之间呈现的结构。

总结:
1)能够存储数据(如顺序表、链表等结构)
2)存储的数据能够⽅便查找

1.2为什么需要数据结构?

正如上文所说,若没有妥善的管理方式,要想在草原上找到一只叫“麦麦”的羊很难。
同理,程序中如果不对数据进⾏管理,可能会导致数据丢失、操作数据困难、野指针等情况。通过数据结构,能够有效将数据组织和管理在⼀起。按照我们的⽅式任意对数据进⾏增删改查等操作。

也许你们已经想到了,数组就是最基础的数据结构。
在这里插入图片描述

1.3有了数组,为什么还要学习其他的数据结构?

假设数据量⾮常庞⼤,频繁的获取数组有效数据个数会影响程序执⾏效率。
结论:最基础的数据结构能够提供的操作已经不能完全满⾜复杂算法实现。

做个类比:普通餐馆和米其林。都有一个炒土豆丝,普通餐馆起的菜名叫“炒土豆丝”,而米其林起的名字叫“豪华金丝”。他们所用的原料有区别么?显然没有,区别是米其林会通过精美的摆盘,让菜变得看起来更加高档。
数组就是普通餐馆,其他更复杂的数据结构就是米其林,后者提供了更多更复杂的操作,来让管理变得方便,解决复杂算法。

2.顺序表的概念和结构

2.1线性表的概念

线性表指的是具有相同特性的数据结构的集合。

线性表是⼀种在实际中⼴泛使⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串… 例如:球类分为足球,篮球,排球等。

2.2两者关联

线性表指的是具有相同特性的数据结构的集合。
1.物理结构:不一定连续
2.逻辑结构:连续

顺序表是线性表的一种。
1.物理结构:连续
2.逻辑结构:连续

3.顺序表的分类

顺序表的底层结构是数组,对数组的封装,实现了常⽤的增删改查等接⼝。

顺序表分为:静态顺序表和动态顺序表。

3.1静态顺序表

概念:使用定长数组存储元素。
定义:

//静态顺序表的定义
struct SeqList
{
int arr[N];//定长数组
int size;//有效数据个数
};

3.2动态顺序表

概念:按需申请空间。
定义:

typedef int SLDataType;
//动态顺序表
typedef struct SeqList
{
SLDataType* arr;
int size;//有效数据个数
int capacity;//空间大小
}SL;

3.3哪个更好呢?

静态顺序表:数组大小给小了,空间不够用;数组大小给大了,空间浪费;
动态顺序表:按需申请空间,不浪费,够用。
因此,动态顺序表更好啦!

4.动态顺序表的实现

4.1定义顺序表结构

在这里插入图片描述

4.2初始化/销毁

在这里插入图片描述注意:初始化时,函数传参要传地址

销毁:
在这里插入图片描述
注意:释放空间后,还要置为空!

4.3尾插

尾插是封装的第一个功能,其中也有很多坑,将这个掌握好了,后边写剩下的功能就如履平地了。一起来看看如何实现 尾插 吧!

在这里插入图片描述
在这里插入图片描述
代码解释:
1.断言检查 :
assert(ps):确保传入的指针 ps 不为 NULL。如果 ps 为 NULL,程序会终止并报错。

2.空间检查与扩容:
在这里插入图片描述

3.所得知识
在这里插入图片描述
4.代码优化
通过将扩容逻辑封装到 SLCheckCapacity 函数中,SLPushBack 函数的逻辑更加清晰,且 SLCheckCapacity 可以在其他地方复用。

void SLCheckCapacity(SL*ps)
{
	//插入数据之前先判断空间够不够
	if (ps->size == ps->capacity)
	{
		//申请空间
		//malloc calloc realloc  增容realloc ,增容通常是成倍数的增加,一般2,3倍
		//三目表达式 真or假 真:默认给4  假:2倍扩容
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));//要申请多大的空间
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//空间申请成功 
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

5.测试功能
养成好习惯,每写好一个功能就立马测试一下,不要堆积测试,最后一堆报错,岂不是炸了吗。
在这里插入图片描述
发现当插入空的时候,报错。反推完善代码,插入之前应该检查确保传入的指针ps不为NULL。即1.断言检查。

4.3头插

在这里插入图片描述

在这里插入图片描述
扩容逻辑已封装为void SLCheckCapacity(SL*ps)函数,插入数据前,直接套用即可
在这里插入图片描述
插入数据前,判断是否为NULL;
插入数据后,记得ps->size++

//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	//整体数组后移一位
	for (int i = ps->size; i>0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//arr[1]=arr[0] 
	}
	ps->arr[0] = x;  //插
	ps->size++;
}

4.4尾删/头删

在这里插入图片描述

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	--ps->size;
}

在这里插入图片描述

//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//数据整体前移一位
	for (int i = 0; i<ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//ps->arr[size-2]=ps->arr[size-1]

	}
	ps->size--;
}

4.5完整代码

SeqList.h

#pragma once
//定义顺序表结构

#define N 100
#include<stdio.h>
#include<stdlib.h>//动态申请内存的头文件
#include<assert.h>
静态顺序表
//struct SeqList
//{
//	int arr[N];//定长数组
//	int size;//有效数据个数
//};

typedef int SLDataType;
//动态顺序表
typedef struct SeqList
{
	SLDataType* arr;
	int size;//有效数据个数 
	int capacity;//空间大小
}SL;//2.

//typedef struct SeqList SL;//1.

//顺序表初始化
void SLInit(SL *ps);
//顺序表销毁
void SLDestroy(SL*ps);
void SLPrint(SL s);
//头部插⼊删除 / 尾部插⼊删除
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);

void SLPopBack(SL* ps);
void SLPopFront(SL* ps);


//指定位置之前插⼊/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

SeqList.c

#include "SeqList.h"
//顺序表初始化
void SLInit(SL *ps)
{
	ps->arr = NULL;  
	ps->size = ps->capacity= 0;
}

//顺序表的销毁
void SLDestroy(SL* ps)
{
	if (ps->arr) 
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

void SLCheckCapacity(SL*ps)
{
	//插入数据之前先判断空间够不够
	if (ps->size == ps->capacity)
	{
		//申请空间
		//malloc calloc realloc  增容realloc ,增容通常是成倍数的增加,一般2,3倍
		//三目表达式 真or假 真:默认给4  假:2倍扩容
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));//要申请多大的空间
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//空间申请成功 
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);//等价于assert(ps!=NULL)
	//ps->arr[ps->size] = x;
	//++ps->size;
	
	//插入数据之前先判断空间够不够
	if (ps->size == ps->capacity)
	{
		//申请空间
		//malloc calloc realloc  动态增容realloc ,增容通常是成倍数的增加,一般2,3倍
		//三目表达式 真or假 真:默认给4  假:2倍扩容  realloc:申请失败返回null
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		//ps->arr = (SLDataType*)realloc(ps->arr, newCapacity  * sizeof(SLDataType));//要申请多大的空间
		SLDataType * tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));//要申请多大的空间
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//空间申请成功 
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	
	ps->arr[ps->size++] = x;


}

//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	//整体数组后移一位
	for (int i = ps->size; i>0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//arr[1]=arr[0] 
	}
	ps->arr[0] = x;  //插
	ps->size++;
}

//打印
void SLPrint(SL s)
{
	for (int i = 0; i < s.size; i++)
	{
		printf("%d ", s.arr[i]);
	}
	printf("\n");
}

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	--ps->size;

}
//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//数据整体前移一位
	for (int i = 0; i<ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//ps->arr[size-2]=ps->arr[size-1]

	}
	ps->size--;
}

test.c

#include"SeqList.h"

void SLTest01()
{
	SL s1;
	SLInit(&s1);//传地址 
	//增删差改操作	
	//测试尾插
	SLPushBack(&s1,1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	//SLPushBack(NULL, 5);//assert(ps)
	SLPrint(s1);

	SLPushFront(&s1, 5);
	SLPushFront(&s1, 6);

	//测试头删
	SLPopFront(&s1);
	SLPrint(s1);
	SLPopFront(&s1); 
	SLPrint(s1);

	SLDestroy(&s1);
}

int main()
{
	SLTest01(); 
	return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到