【数据结构】顺序表详解

系列文章目录

数据结构之顺序表
在这里插入图片描述



一、顺序表的介绍

1.1 概念

定义:顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储,在数组上完成数据的增删查改。
在存储方式上有静态存储动态存储
在这里插入图片描述


1.2 工作机制

以动态存储为例
在这里插入图片描述

增加元素
在这里插入图片描述

删除元素
在这里插入图片描述

查找元素
在这里插入图片描述

更改元素
在这里插入图片描述

———————————————————————————————

二、顺序表的实现

采用的编译器:VS2022
在这里插入图片描述

Seqlist.h

#pragma once

//创建一个线性表
//逻辑结构 - 线性结构
//存储结构 - 顺序结构

//之后用到的头文件
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//宏定义
#define DEFAULT_INT  10//数组初始化默认大小
#define ADD_INT  10//每次增容大小

//重命名数据类型,以方便之后改变存储的元素类型
//(假如想存储浮点形数据,就只用将下面的int改为float,省去了麻烦)
typedef int SLDateType;

//动态顺序表
typedef struct SeqList
{
	SLDateType *date;
	size_t size;//存储的数据个数
	size_t capacity;//能存储的数据最大个数
}SL;

//接口函数
void SeqListInit(SL* ps);//初始化 :开辟空间
void SeqListDestroy(SL* ps);//销毁:归还空间
void SeqListprint(SL* ps);//打印数组

//4大基础功能
//1. 增加功能
void SeqListPushBack(SL *ps, SLDateType x);//尾插
void SeqListPushFront(SL* ps, SLDateType x);//头插
void SeqListInsert(SL* ps, size_t pos, SLDateType x);//指定插

//2. 删除功能
void SeqListPopBack(SL* ps);//尾删
void SeqListPopFront(SL* ps);//头删
void SeqListErase(SL* ps, size_t pos);//指定删

//3. 查找功能
int SeqListFind(SL* ps, SLDateType x);

//4. 更改功能
void SeqListChange(SL* ps, SLDateType x, int pos);

//扩容 - 辅助功能
void CheckCapacity(SL* ps);

Seqlist.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Seqlist.h"

//初始化
void SeqListInit(SL* ps)
{
	//开辟动态内存空间
	ps->date = (SLDateType*)calloc(DEFAULT_INT, sizeof(SLDateType));
	assert(ps->date);
	ps->size = 0;
	ps->capacity = DEFAULT_INT;
}

//增加功能
//1.尾插
void SeqListPushBack(SL* ps, SLDateType x)
{
	assert(ps);
	CheckCapacity(ps);//检查容量
	ps->date[ps->size] = x;
	ps->size++;
}
//2.头插
void SeqListPushFront(SL* ps, SLDateType x)
{
	assert(ps);
	CheckCapacity(ps);
	//往后移
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->date[end + 1] = ps->date[end];
		end--;
	}
	ps->date[0] = x;
	ps->size++;
}
//3.随机插
void SeqListInsert(SL* ps, size_t pos, SLDateType x)
{
	assert(pos >= 1 && pos <= ps->size + 1);
	CheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos - 1)
	{
		ps->date[end + 1] = ps->date[end];
		end--;
	}
	ps->date[pos - 1] = x;
	ps->size++;
}

//删除功能
//1.尾删
void SeqListPopBack(SL* ps)
{
	if (ps->size == 0)
	{
		return;
	}
	ps->size--;
}
//2.头删
void SeqListPopFront(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->size - 1; i++)
	{
		ps->date[i] = ps->date[i + 1];
	}
	ps->size--;
}
//3.随机删
void SeqListErase(SL* ps, size_t pos)
{
	assert(pos >= 1 && pos <= ps->size + 1);
	int begin = pos - 1;
	while (begin <= ps->size)
	{
		ps->date[begin] = ps->date[begin + 1];
		begin++;
	}
	ps->size--;

}

//查找功能
int SeqListFind(SL* ps, SLDateType x)
{
	assert(ps);
	int pos = 0;
	for (pos = 0; pos < ps->size; pos++)
	{
		if (ps->date[pos] == x) {
			printf("找到了,下标为%d\n", pos);
			return pos;
		}
	}
	printf("未找到\n");
}
//更改功能
void SeqListChange(SL* ps, SLDateType x, int pos)
{
	assert(ps);
	if (ps->size >= pos + 1) {
		printf("更改成功\n");
		ps->date[pos] = x;
	}
	else {
		printf("pos超过范围\n");
	}
}

//销毁
void SeqListDestroy(SL* ps)
{
	free(ps->date);
	ps->date = NULL;
	ps->capacity = 0;
	ps->size = 0;
}

//打印
void SeqListprint(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->date[i]);
	}
}

//检查容量
void CheckCapacity(SL* ps)
{
	//扩容
	if (ps->capacity == ps->size - 1)
	{
		SLDateType *tmp = (SLDateType*)realloc(ps->date,
			(ps->capacity + ADD_INT) * sizeof(SLDateType));

		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		else
		{
			printf("realloc succee\n");
			ps->capacity += ADD_INT;
			ps->date = tmp;
		}
	}
}


test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Seqlist.h"

//测试接口函数
void TestSeqList(SL* s1)
{
	SeqListInit(s1);
	SeqListPushBack(s1, 1);
	SeqListPushBack(s1, 2);
	SeqListPushBack(s1, 3);
	SeqListPushBack(s1, 4);
	SeqListPushBack(s1, 5);
	SeqListFind(s1, 4);
	SeqListChange(s1, 9, 3);

	SeqListInsert(s1, 6, 9);
	SeqListErase(s1, 3);

	SeqListprint(s1);

	SeqListDestroy(s1);
}

int main(void)
{
	SL a = { 0 };
	TestSeqList(&a);

	return 0;
}

——————————————————————————————————————————

三、顺序表的优缺点

顺序表的优点
1 )无须增加额外的存储空间表示结点间的逻辑关
系。
2 )可以方便地随机存取表中任一结点。

顺序表的缺点:
1 )插入和删除运算不方便,通常须移动大量结
点,效率较低。
2 )难以进行连续的存储空间的预分配,尤其是当表变
化较大时。

### 数据结构顺序表的实现与操作详解 #### 什么是顺序表顺序表是一种线性数据结构,其特点是逻辑上的连续性和物理存储上的连续性一致。它通常使用数组来表示,在内存中占据一段连续的空间[^1]。 #### 动态顺序表的基本形式 以下是动态顺序表的一个基本定义方式: ```c typedef int SLDataType; typedef struct SeqList { SLDataType* arr; // 存储数据的数组指针 int size; // 当前有效数据的数量 int capacity; // 数组的最大容量 } SL; ``` 上述代码展示了如何在 C/C++ 中定义一个顺序表数据结构[^2]。 --- #### 初始化顺序表 初始化顺序表的操作主要是分配一块初始大小的内存空间给 `arr` 并设置 `size` 和 `capacity` 的初值。 ```c void InitSeqList(SL* p) { assert(p); p->arr = (SLDataType*)malloc(sizeof(SLDataType) * 4); // 初始容量设为4 if (!p->arr) exit(-1); p->size = 0; p->capacity = 4; } ``` 此函数会创建一个新的顺序表实例并为其分配初始资源[^2]。 --- #### 扩展顺序表容量 当向顺序表插入新元素而当前容量不足时,需要扩展顺序表的容量。 ```c void ResizeSeqList(SL* p) { assert(p); if (p->size >= p->capacity) { int newCapacity = p->capacity * 2; SLDataType* newArr = (SLDataType*)realloc(p->arr, sizeof(SLDataType) * newCapacity); if (!newArr) exit(-1); p->arr = newArr; p->capacity = newCapacity; } } ``` 这段代码实现了顺序表扩容的功能,每次将原容量翻倍以提高效率[^2]。 --- #### 尾部插入数据 尾部插入是指在顺序表的最后一端加入新的数据元素。 ```c void PushBackSeqList(SL* p, SLDataType data) { assert(p); ResizeSeqList(p); p->arr[p->size++] = data; } ``` 该方法先调用 `ResizeSeqList()` 来确保有足够的空间再执行实际的插入动作[^2]。 --- #### 头部插入数据 头部插入意味着把新元素放在顺序表的第一个位置上。 ```c void PushFrontSeqList(SL* p, SLDataType data) { assert(p); ResizeSeqList(p); for (int i = p->size - 1; i >= 0; --i) { p->arr[i + 1] = p->arr[i]; } p->arr[0] = data; ++p->size; } ``` 这里通过移动现有元素的位置腾出首部空间完成插入过程。 --- #### 删除最后一个元素 删除最后一位即减少顺序表的有效长度即可。 ```c void PopBackSeqList(SL* p) { assert(p && p->size > 0); --p->size; } ``` 这是最简单的删除操作之一[^2]。 --- #### 查找特定元素 查找某个具体数值是否存在以及它的索引号可以这样写: ```c int FindInSeqList(const SL* p, SLDataType data) { assert(p); for (int i = 0; i < p->size; ++i) { if (p->arr[i] == data) return i + 1; } return 0; } ``` 如果找到目标则返回其下标加一;未发现的话给出零作为标志[^4]。 --- #### 销毁顺序表 销毁顺序表需释放所占用的所有堆区资源。 ```c void DestroySeqList(SL* p) { assert(p); free(p->arr); p->arr = NULL; p->size = p->capacity = 0; } ``` 这一步骤非常重要以防造成内存泄漏问题[^2]。 ---
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值