数据结构 02(线性:顺序表)

目录

线性表

顺序表

概念与结构

动态顺序表的实现

头文件的创建

顺序表初始化

顺序表的扩容

尾插功能

头插功能

尾删功能

头删功能

查找功能

任意位置前插入

任意位置前删除

销毁

动态顺序表整体呈现

SeqList.h

SeqList.c


线性表

线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表的逻辑结构一定是线性的,但物理结构不一定是线性的。

顺序表

概念与结构

**概念:**顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。

**结构:**顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口

**分类:**分为静态顺序表和动态顺序表(常用)。

动态顺序表的实现

头文件的创建

我们要在头文件中完成顺序表的创建和头文件与函数的声明。

cpp 复制代码
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}SL;

这是头文件的包含和顺序表的创建。

这是对函数的声明,以上函数我们都会讲到。

顺序表初始化

首先我们要在源文件中包含刚刚我们创建的头文件。

然后对顺序表进行初始化。

cpp 复制代码
void SLInit(SL* ps)//初始化
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

顺序表的扩容

现在我们的顺序表里面什么都没有,我们要扩大我们的空间。或者当我们的顺序表空间满了的时候,我们也要扩大我们的空间。

所以我们要先写好函数对顺序表进行扩容。

扩容函数中我们需要使用realloc函数额外申请空间。

注意:进行扩容操作时请用临时变量,防止发生问题造成不可逆的伤害。

cpp 复制代码
void SLCheckCapacity(SL* ps)//扩容
{
	if (ps->size == ps->capacity)
	{
		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;
	}
}

尾插功能

实现尾插功能很简单,size刚好是数组最后一个元素的后一个下标,确定指针的安全后直接令arr[size]等于x就完成了。

cpp 复制代码
void SLPushBack(SL* ps,SLDataType x)//尾插
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}

头插功能

头插功能比尾插复杂一点点,需要让数组中的元素整体后移一个位置,让arr[0]空缺起来实现x的插入。

cpp 复制代码
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];
	}
	ps->arr[0] = x;
	++ps->size;
}

尾删功能

尾删很简单,直接让size减一就好了。

cpp 复制代码
void SLPopBack(SL* ps)//尾删
{
	assert(ps && ps->size);
	--ps->size;
}

头删功能

头删也很简单,就让后面的元素把前面的元素一一覆盖就好了。

cpp 复制代码
void SLPopFront(SL* ps)//头删
{
	assert(ps && ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}

查找功能

遍历数组查找元素,找到返回下标,没找到返回-1。

cpp 复制代码
int SLFind(SL* ps, SLDataType x)//查找
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
			return i;
	}
	return -1;
}

任意位置前插入

这是建立在头插的基础上的,让pos后的元素一一往后移一个位置把pos空出来实现插入。

cpp 复制代码
void SLInsert(SL* ps, int pos, SLDataType x)//任意位置前插入
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	++ps->size;
}

任意位置前删除

和头删很相似,让pos后的元素一一往前移一个位置覆盖pos。

cpp 复制代码
void SLErase(SL* ps, int pos)//任意位置前删除
{
	assert(ps && ps->size);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}

销毁

结束后一定要进行函数的销毁操作。

cpp 复制代码
void SLDesTroy(SL* ps)//销毁
{
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

动态顺序表整体呈现

SeqList.h

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}SL;

void SLInit(SL* ps);
void SLDesTroy(SL* ps);
void SListPrint(SL s);
void SLCheckCapacity(SL* ps);
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);

SeqList.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"

void SLInit(SL* ps)//初始化
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

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

void SLCheckCapacity(SL* ps)//扩容
{
	if (ps->size == ps->capacity)
	{
		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);
	SLCheckCapacity(ps);
	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];
	}
	ps->arr[0] = x;
	++ps->size;
}

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

void SLPopFront(SL* ps)//头删
{
	assert(ps && ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}

int SLFind(SL* ps, SLDataType x)//查找
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
			return i;
	}
	return -1;
}

void SLInsert(SL* ps, int pos, SLDataType x)//任意位置前插入
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	++ps->size;
}

void SLErase(SL* ps, int pos)//任意位置前删除
{
	assert(ps && ps->size);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}

void SLDesTroy(SL* ps)//销毁
{
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
相关推荐
XX風13 分钟前
8.1 PFH&&FPFH
图像处理·算法
知南x14 分钟前
【Ascend C系列课程(高级)】(1) 算子调试+调优
c语言·开发语言
NEXT0626 分钟前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法
代码游侠1 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Gary Studio1 小时前
rk芯片驱动编写
linux·学习
mango_mangojuice1 小时前
Linux学习笔记(make/Makefile)1.23
java·linux·前端·笔记·学习
想进个大厂1 小时前
代码随想录day37动态规划part05
算法
sali-tec1 小时前
C# 基于OpenCv的视觉工作流-章22-Harris角点
图像处理·人工智能·opencv·算法·计算机视觉
子春一1 小时前
Flutter for OpenHarmony:构建一个 Flutter 四色猜谜游戏,深入解析密码逻辑、反馈算法与经典益智游戏重构
算法·flutter·游戏
lingggggaaaa1 小时前
安全工具篇&动态绕过&DumpLsass凭据&Certutil下载&变异替换&打乱源头特征
学习·安全·web安全·免杀对抗