数据结构 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;
}
相关推荐
秋难降22 分钟前
深入解析快速排序:原理、波动根源与优化之道
算法·排序算法·编程语言
睡不醒的kun29 分钟前
leetcode算法刷题的第二十一天
数据结构·c++·算法·leetcode·职场和发展·回溯算法·回归算法
小欣加油31 分钟前
leetcode 461 汉明距离
c++·算法·leetcode
淮北49433 分钟前
linux系统学习(15.启动管理)
运维·服务器·网络·c++·vscode·学习
diablobaal2 小时前
云计算学习100天-第31天
学习·云计算
solicitous2 小时前
整理python接口自动化相关——10、自动考虑点(待续)
python·学习·自动化
一起努力啊~3 小时前
算法题打卡力扣第169题:多数元素(easy)
算法·leetcode·哈希算法
大喵桑丶3 小时前
Nginx配置学习及多应用场景配置示例
运维·学习·nginx
水冗水孚3 小时前
通俗易懂地理解深度遍历DFS、和广度遍历BFS
javascript·算法