【数据结构】 顺序表

一、顺序表的基本概念与特点

  • 定义:顺序表是一种线性表的存储结构,采用连续的内存空间存储数据元素
  • 物理结构:逻辑上相邻的元素在物理内存中也相邻
  • 优点:1.空间利用率高;2.支持随机访问;3.尾插、尾删效率极高(时间复杂度O(1))
  • 缺点:1.头插、按位插入删除效率低;增容代价大

二、可扩容的顺序表的结构体设计

#define INIT_SIZE 10 //初始化时malloc购买的格子数量

//可扩容的顺序表的结构体设计
typedef int ELEM_TYPE;

typedef struct SeqList {
	ELEM_TYPE* elem;//用来接收malloc返回的数组首地址
	int length;//存放有效值个数
	int listsize;//存放数组总的格子数
}SeqList,*PSeqList;

三、各功能函数的声明

//1.初始化
void Init_SeqList(struct SeqList* psl);

//2.插入数据(存入)
bool Insert_SeqList_head(PSeqList psl, ELEM_TYPE val);//头插
bool Insert_SeqList_tail(PSeqList psl, ELEM_TYPE val);//尾插
bool Insert_SeqList_pos(PSeqList psl, ELEM_TYPE val,int pos);//按位置插入

//3.删除数据(取)
bool Del_SeqList_head(SeqList* psl);//头删
bool Del_SeqList_tail(SeqList* psl);//尾删
bool Del_SeqList_pos(SeqList* psl,int pos);//按位置删除;默认pos=0,则为头删
bool Del_SeqList_val(SeqList* psl, ELEM_TYPE val);//按值删除;只删除val出现的第一次的位置
bool Del_SeqList_ALL_val_1(struct SeqList* psl, ELEM_TYPE val);//按值删除;只删除val出现的所有位置1
bool Del_SeqList_ALL_val_2(struct SeqList* psl, ELEM_TYPE val);//按值删除;只删除val出现的所有位置2

//4.查找数据是否已经存在(若存在,则只需要返回下标即可  找不到返回-1)
int Search_SeqList(PSeqList psl, ELEM_TYPE val);

//5.判空
bool Is_Empty(PSeqList psl);

//6.判满
bool Is_Full(PSeqList psl);

//7.扩容函数(1.5 2)   默认用2倍扩容
void Increase(PSeqList psl);

//8.清空  (不释放已购买的内存)
void Clear(PSeqList psl);

//9.销毁  (需要释放malloc购买的内存的)
void Destroy(PSeqList psl);

//打印
void show(PSeqList psl);

三、顺序表功能的实现方式

0、头文件的引用

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>   // malloc  exit
#include "SeqList.h"
//#include <vld.h>//检测内存泄漏

1、初始化

//1.初始化
void Init_SeqList(struct SeqList* psl){
	//0.安全处理   每一个函数都要写的
	//assert(psl != NULL);
	assert(psl != nullptr);
	assert(nullptr != psl);
	if (nullptr == psl){
		exit(EXIT_FAILURE);
	}
	//1.对我们的 elem 用来去malloc 在堆区购买一块连续的空间
	psl->elem = (ELEM_TYPE*)malloc(INIT_SIZE * sizeof(ELEM_TYPE));
	if (NULL == psl->elem){
		exit(EXIT_FAILURE);
	}
	//2.对我们的 length 初始化为0
	psl->length = 0;
	//3.对我们的 listsize 初始化为 INITSIZE
	psl->listsize = INIT_SIZE;
}

2、插入

2.1头插

//头插
bool Insert_SeqList_head(PSeqList psl, ELEM_TYPE val) {
	assert(nullptr != psl);
	// 0.5判满,肯定有空余格子
	if (Is_Empty(psl))Increase(psl);
	//集体向后挪(尾巴先动)
	for (int i = psl->length-1; i >= 0; i--) {
		psl->elem[i + 1] = psl->elem[i];
	}
	//将val放入0号下标
	psl->elem[0] = val;
	//有效值个数+1
	psl->length++;
	return true;
}

2.2尾插

//尾插
bool Insert_SeqList_tail(PSeqList psl, ELEM_TYPE val) {
	assert(nullptr != psl);
	// 0.5判满
	if (Is_Empty(psl))Increase(psl);
	//找到尾巴
	psl->elem[psl->length] = val;
	//有效值个数+1
	psl->length++;
	return true;
}

2.3按位插入

//按位置插入;默认pos=0,则为头插
bool Insert_SeqList_pos(PSeqList psl, ELEM_TYPE val,int pos) {
	assert(nullptr != psl);
	assert(pos >= 0 && pos <= psl->length);
	// 0.5判满
	if (Is_Empty(psl))Increase(psl);
	//将插入位置之后的元素,统一向后挪动,把插入位置空出来
	for (int i = psl->length - 1; i >= pos; i--) {
		psl->elem[i + 1] = psl->elem[i];
	}
	psl->elem[pos] = val;
	//有效值个数+1
	psl->length++;
	return true;
}

3、删除

3.1头删

//头删
bool Del_SeqList_head(SeqList* psl) {
	assert(nullptr != psl);
	//0.5判空
	if (Is_Empty(psl))return false;
	//除了第一个元素之外,集体向前覆盖(尾巴先动)
	for (int i = 1; i <psl->length; i++) {
		psl->elem[i - 1] = psl->elem[i];
	}
	//有效值个数-1
	psl->length--;
	return true;
}

3.2尾删

//尾删
bool Del_SeqList_tail(SeqList* psl) {
	assert(nullptr != psl);
	//0.5判空
	if (Is_Empty(psl))return false;
	psl->length--;
	return true;
}

3.3按位置删除

//按位置删除;默认pos=0,则为头删
bool Del_SeqList_pos(SeqList* psl, int pos) {
	assert(nullptr != psl);
	assert(pos >= 0 && pos <= psl->length);
	// 0.5判空
	if (Is_Empty(psl))return false;
	//将删除位置之后的元素,统一向前挪动覆盖
	for (int i = pos + 1;i<= psl->length - 1; i++) {
		psl->elem[i - 1] = psl->elem[i];
	}
	psl->length--;
	return true;
}

3.4按值删除;只删除val出现的第一次的位置

//按值删除;只删除val出现的第一次的位置
bool Del_SeqList_val(SeqList* psl, ELEM_TYPE val) {
	assert(nullptr != psl);
	//0.5判空
	if (Is_Empty(psl))return false;
	//通过调用函数,查找val值在顺序表的位置
	int index = Search_SeqList(psl, val);
	if (index == -1)return false;
	return Del_SeqList_pos(psl, index);
}

3.5按值删除;只删除val出现的所有位置1

//按值删除;只删除val出现的所有位置1
bool Del_SeqList_ALL_val_1(struct SeqList* psl, ELEM_TYPE val) {
	int count = 0;
	for (int i = 0; i < psl->length; i++) {
		if (psl->elem[i] == val) {
			count++;
		}
	}
	for(int i=0;i<count;i++){
		int index = Search_SeqList(psl, val);
		Del_SeqList_pos(psl, index);
	}
	return true;
}

3.6按值删除;只删除val出现的所有位置2

//按值删除;只删除val出现的所有位置2
bool Del_SeqList_ALL_val_2(struct SeqList* psl, ELEM_TYPE val) {
	int qianfangkongxiangezishu = 0;
	for (int i = 0; i < psl->length; i++) {
		if (psl->elem[i] == val) 
			qianfangkongxiangezishu++;
		else 
			psl->elem[i - qianfangkongxiangezishu] = psl->elem[i];
	}
	psl->length = psl->length - qianfangkongxiangezishu;
	return true;
}

4、查找

//4.查找数据是否已经存在(若存在,则只需要返回下标即可  找不到返回-1)
int Search_SeqList(PSeqList psl, ELEM_TYPE val) {
	for (int i = 0; i < psl->length; i++) {
		if (psl->elem[i] == val) {
			return i;
		}
	}
	return -1;
}

5、判空

//5.判空
bool Is_Empty(PSeqList psl) {
	return psl->length == 0;
}

6、判满

//6.判满
bool Is_Full(PSeqList psl) {
	return psl->length == psl->listsize;
}

7、扩容

//7.扩容函数(1.5 2)   默认用2倍扩容
void Increase(PSeqList psl) {
	ELEM_TYPE* tmp = (ELEM_TYPE * )realloc(psl->elem, psl->listsize * sizeof(ELEM_TYPE) * 2);
	if (tmp != nullptr) {
		psl->elem = tmp;
	}
}

8、清空

//8.清空  (不释放已购买的内存)
void Clear(PSeqList psl) {
	//malloc申请空间先不释放,而是认为所有格子里都是无效值
	psl->length = 0;
}

9、销毁

//9.销毁  (需要释放malloc购买的内存的)
void Destroy(PSeqList psl) {
	free(psl->elem);
	psl->length = psl->listsize = 0;
}

10、打印

//打印
void show(PSeqList psl) {
	//assert
	for (int i = 0; i < psl->length; i++) {
		printf("%d ",psl->elem[i]);
	}
	printf("\n");
}

四、关键操作与时间复杂度分析

  • 插入操作:中间插入需移动后续元素,平均时间复杂度O(n)
  • 删除操作:类似插入,需向前移动元素,平均时间复杂度O(n)
  • 查找操作:按值查找O(n),按索引查找O(1)

五、顺序表的应用场景

  • 适用于元素数量稳定、频繁访问但较少修改的场景
  • 典型应用:数组排序、矩阵运算、哈希表底层实现

六、扩展内容:与其他结构的对比

  • 与链表的比较:内存连续性、操作效率差异
  • 与动态数组的关系:多数语言中动态数组(如C++的vector)基于顺序表实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易ლ拉罐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值