数据结构初开课 动态顺序表的实现

本次编译环境为vs2022


前言

在较为浅显的学完C语言后 就要开始我们数据结构的路了 本次顺序表需要的知识 有指针传地址 动态内存管理 结构体的使用这三大部分 其他的基础知识需要自备了

顺序表专题

一.了解顺序表

在写之前 我们需要了解顺序表其实有两种:
1.静态顺序表 里面的数据内容 是不会动态改变的 这就会造成有些人 创造的时候存在空间不够用 或者空间浪费的问题 没有最大程度的使用资源
2.动态顺序表 顾名思义就是可以动态改变内存 供我们更好的使用 让空间尽量减少浪费 有利于公司的最大收益率

二.静态顺序表的书写

首先是创造三个文件 如图所示
在这里插入图片描述
接下来书写我们的代码

typedef int SLDateType;
#define N 4
typedef struct Seqlist
{
	SLDateType arr[N];
	SLDateType size;
	SLDateType capacity;
}SL;

这便是简单的静态顺序表 通过宏来给定顺序表中的数组大小 即空间

三.动态顺序表的书写及实现

1.书写动态顺序表

typedef int SLDateType;
typedef struct Seqlist
{
	SLDateType *arr;
	SLDateType size;//数据个数
	SLDateType capacity;//空间大小
}SL;

这便是我们的动态顺序表 区别其实不大 主要是 删除宏的使用 改为用指针传递
让我们能用动态内存管理来实现扩容
后面我们将通过函数的一个个实现来完成动态顺序表的实现

2.顺序表的定义和销毁

定义即是给定结构体空间和大小 销毁则是要把开辟的动态空间还回去
所以这两步必不可少

1.定义

首先要在头文件中给到定义 后面到 11.19.c文件中去实现
给到实现代码

void SLInit(SL* ps)//定义
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

这里使用指针来接受 ps本质上是数组的地址传递 所以给到arr空指针 给到空间为0这是初始化想看到的结果

2.销毁

给到实现代码

void SLDestory(SL* ps)
{
	if (ps->arr != NULL)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

这里我们要看到 有个判断过程 就是要看 arr是否为空指针 不是的话 我们就要销毁释放 后给到初始化

3.顺序表的尾插头插 尾删头删

1.尾插 头插

尾插顾名思义就是 在顺序表的尾部插入 但在此之前我们需要给顺序表扩容 以免数据不够 所以一个扩容代码

扩容
SLstart(SL* ps)//扩容代码
{
	if (ps->capacity == ps->size)
	{
		//这里给到Newcapacity目的则是 因为capacity初始化为0 若 * 下去 0*n=0没有必要
		int Newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		//ps->arr = (SLDateType*)realloc(ps->arr, sizeof(SLDateType))//本质上是 ps->capacity * sizeof(SLDateType)* 2
		//这里最好给到一个临时变量tmp来接收 后面赋值给 arr 以免 这步错了 arr直接爆炸
		int* tmp = (SLDateType*)realloc(ps->arr, Newcapacity*sizeof(SLDateType));
		if (tmp == NULL)//判断临时变量 tmp是否可靠
		{
			perror("realloc fail");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = Newcapacity;//新空间的扩容就完成了
	}
}

这里扩容给到的就是个函数 后面会放到 头插尾插的代码中使用

一.尾插
void SLPushBack(SL* ps, SLDateType x)
{
	assert(ps);
	SLstart(ps);
	ps->arr[ps->size++] = x;
}

这里给到assert断言 使用前记得先包含 #include <stdio.h>
用来判断是否为空指针

二.头插
void SLPushFront(SL* ps, SLDateType x)
{
	assert(ps);
	SLstart(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i-1];
	}
	ps->arr[0] = x;
	ps->size++;
}

头插与尾插最主要还是头插的 for循环 size++是为了 每次循环给前面开辟一个空间

2.尾删 头删
一.尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;//只需要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->size--;

}




这里头删 用for循环 慢慢的把后面的一个个放到前面去 然后通过 size–删除
本质逻辑哈哈。

3.在指定位置插入 删除 以及查找函数
一.在指定位置插入

在指定位置插入相对于头插尾插 本质上是多一个 参数当作位置的下标来让我们插入

所以在定义函数时要多一个pos参数来当作位置

void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLstart(ps);
	//判断完空间够不够后 我们的目标是将pos下标的数组往后挪动给与位置给到x插入
	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);
	assert(pos >= 0 && pos < ps->size);
	SLstart(ps);
	for (int i = pos; i<ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
三.查找

查找函数其实就是通过给个一个数来进行循环查找 找不到就跳出 找到了就返回该数组的下标

int  SLFind(SL* ps, SLDateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			//找到了
			return i;
		}
	}
	//跳出循环就是没找到
	return -1;

}

最后的打印函数就不写了 直接把原码放给大家
测试会单独出一片更加好的各位。
第一个头文件 .h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//typedef int SLDateType;
//#define N 4
//typedef struct Seqlist
//{
//	SLDateType arr[N];
//	SLDateType size;
//	SLDateType capacity;
//}SL;

typedef int SLDateType;
typedef struct Seqlist
{
	SLDateType *arr;
	SLDateType size;//数据个数
	SLDateType capacity;//空间大小
}SL;
void SLPrint(ps);

void SLInit(SL* ps);//定义

void SLDestory(SL* ps);//销毁

void SLPushBack(SL* ps, SLDateType x);//尾插

void SLPushFront(SL* ps, SLDateType x);//头插

void SLPopBack(SL* ps);//尾删

void SLPopFront(SL* ps);//头删

void SLInsert(SL* ps,int pos,SLDateType x);//指定位置插入

void SLErase(SL* ps, int pos);//指定位置删除

int  SLFind(SL* ps,SLDateType x);

第一个.c文件

#define _CRT_SECURE_NO_WARNINGS 1

#include "11.19.h"
void SLInit(SL* ps)//定义
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

void SLDestory(SL* ps)
{
	if (ps->arr != NULL)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
SLstart(SL* ps)//扩容代码
{
	if (ps->capacity == ps->size)
	{
		//这里给到Newcapacity目的则是 因为capacity初始化为0 若 * 下去 0*n=0没有必要
		int Newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		//ps->arr = (SLDateType*)realloc(ps->arr, sizeof(SLDateType))//本质上是 ps->capacity * sizeof(SLDateType)* 2
		//这里最好给到一个临时变量tmp来接收 后面赋值给 arr 以免 这步错了 arr直接爆炸
		int* tmp = (SLDateType*)realloc(ps->arr, Newcapacity*sizeof(SLDateType));
		if (tmp == NULL)//判断临时变量 tmp是否可靠
		{
			perror("realloc fail");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = Newcapacity;//新空间的扩容就完成了
	}
}
void SLPushBack(SL* ps, SLDateType x)
{
	assert(ps);
	SLstart(ps);
	ps->arr[ps->size++] = x;
}
void SLPushFront(SL* ps, SLDateType x)
{
	assert(ps);
	SLstart(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);
	assert(ps->size);
	ps->size--;//只需要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->size--;

}
void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLstart(ps);
	//判断完空间够不够后 我们的目标是将pos下标的数组往后挪动给与位置给到x插入
	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);
	assert(pos >= 0 && pos < ps->size);
	SLstart(ps);
	for (int i = pos; i<ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
int SLFind(SL* ps, SLDateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;

}


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

测试代码各位可以慢慢增添删改来进行调试

#define _CRT_SECURE_NO_WARNINGS 1
#include "cs.h"
void SLTest01()
{
	SL sl;
	SLInit(&sl);
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 3);
	SLPrint(sl);
	//SLPushFront(&sl, 8);
	//SLPushFront(&sl, 0);
	SLPrint(sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	/*SLPopfront(&sl);
	SLPopfront(&sl);
	SLPopfront(&sl);*/
	SLPrint(sl);
	SLDestory(&sl);
}

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

在这里插入图片描述
这是我调试用的监视可能有人不一定能打出来

谢谢各位!!彦祖亦菲点个赞

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值