数据结构顺序表的初始化,头插,尾插,头删,尾删,指定位置删除,指定位置插入,查找,销毁(详解)

前言

数据结构是什么?
数据结构是两个词的集合
数据:是一系列的在杂乱无章的数据的集合
结构:是有条理,清晰的集合(例如目录)
数据结构就是一些有条理数据的集合
数据结构是计算机存储和组织数据的方式

顺序表的介绍

顺序表是线性表的一种
那么顺序表和线性表到底是什么呢?

线性表:具有相同特性数据结构的集合
例如:蔬菜:黄瓜,白菜,莲藕
相同特性:蔬菜
顺序表的底层是数组,但是在数组的基础上有增删查改等方法,就变成了数据结构

线性表有物理结构逻辑结构

线性表:
物理结构:不一定是连续的
逻辑结构:一定是连续的

物理结构:例如数组的下标一定是连续的
在这里插入图片描述

逻辑结构:例如商店门口排队的人,人排队的位置不一定是一条直线,但是在逻辑上是一条直线
在这里插入图片描述

顺序表的物理结构一定是连续的,
逻辑结构也一定是连续的
因为顺序表的底层是数组,数组的物理结构和逻辑结构一定是连续的

顺序表需要的基础有:
动态内存管理
指针
结构体

写顺序表先创建三个文件
一个测试文件(.c):测试顺序表的方法
一个顺序表的头文件(.h):顺序表的结构,声明顺序表的方法
一个顺序表的源文件(.c):实现顺序表的方法

静态顺序表

#define N 100
//100可以用N代替,后续可以方便修改数据

struct SeqList
{
   int arr[N];//定长的数组
   int size;//顺序表当前有效的数据个数
};

数组给大了,空间浪费
数组给小了,空间不够
静态顺序表的缺点还是比较多的

动态顺序表

struct SeqList
{
  int* arr;//指向顺序表的指针
  int size;//顺序表中有效数据个数
  int capacity;//顺序表的空间大小
}; 

动态顺序表可以动态增加顺序表的大小(动态增容)
防止了空间的大量浪费
也防止了空间的不足
所以下面我们来实现动态顺序表

一.顺序表的初始化

//SeqList.c
#include"SeqList.h"

//初始化顺序表
void SLInit(SL* ps)
{
	ps->arr = NULL;//将数组置为NULL
	ps->size = 0;//有效数据为0
	ps->capacity = 0;//空间大小为0
}

二.销毁

//SeqList.c
//销毁顺序表
void SLDestroy(SL* ps)
{
	//如果顺序表不为空,说明arr中还有动态申请的空间
	//要把动态申请的空间free掉
	if (ps->arr != NULL)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	//顺序表不用了,置为NULL
	ps->size = ps->capacity = 0;
	//销毁完有效元素和空间为0
}

扩容顺序表

后面需要使用到,所以提前说
在这里插入图片描述

所以要用realloc增容,而不是malloc

//二倍或三倍地扩容
//扩容顺序表
void SLCheck(SL* ps)
{
	assert(ps);
	if(ps->capacity == ps->size)
	//看看空间够不够
	{
		//三目操作符判断给4个空间,还是直接增容2倍
		int NewCapacity = ps->capacity == 0 ? 4 : 2 * (ps->capacity);
		DataType* tmp = realloc(ps->arr, sizeof(DataType) * NewCapacity);
		//用新的指针接收,防止增容失败
		if (tmp == NULL)
		{
			perror("realloc");
			return;//增容失败,提前返回
		}
		//增容成功
		ps->arr = tmp;
		ps->capacity = NewCapacity;
	}
}

打印顺序表

//打印顺序表
void SLPrint(SL s)
{
	for (int i = 0; i < s.size; i++)
	{
		printf("%d ", s.arr[i]);
	}
	printf("\n");
	//打印一行就换行
}

三.头插

在这里插入图片描述

//头插
void SLPushFront(SL* ps,DataType x)
{
	assert(ps);
	SLCheck(ps);
	//增容
	int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i-1];
		//最后一次: = 1 ,arr[1] = arr[0]
	}
	ps->arr[0] = x;
	// 0下标的位置,放入插入的元素
	(ps->size)++;
	//插入一个数据,有效元素加一
}

四.尾插

在这里插入图片描述

//尾插
void SLPushBack(SL* ps,DataType x)
{
	assert(ps);
	SLCheck(ps);
    //判断空间够不够
	ps->arr[ps->size] = x;
	// == arr[size] = x
	(ps->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];
		// arr[size-2] = arr[size-1]
	}
	(ps->size)--;
	//删除一个元素,有效元素少一个
}

六.尾删

在这里插入图片描述

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	//指向顺序表的指针不能为空指针
	//为NULL,停止运行
	//不为NULL,继续运行
	assert(ps->size);
	//顺序表不能为空
	(ps->size)--;
	//删除一个元素,有效元素少一个
}

七.指定位置之前(包括指定位置)的插入

在这里插入图片描述

//指定位置之前插入元素
//pop:下标
//x:要插入的元素
void SLInsert(SL* ps, int pop, DataType x)
{
	assert(ps);
	assert(pop >= 0 && pop <= ps->size);
	// pop == size就是尾插
	// pop < size 在中间插入
	// pop == 0 头插
	SLCheck(ps);
	for (int i = ps->size; i > pop; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
		// arr[pop+1] = arr[pop]
	}
	ps->arr[pop] = x;
	(ps->size)++;
}

八.指定位置数据的删除

在这里插入图片描述

//指定位置之前的删除
void SLEarse(SL* ps, int pop)
{
	assert(ps);
	assert(pop >= 0 && pop < ps->size);
	
	for(int i = pop;i < ps->size - 1;i++)
	{
		ps->arr[i] = ps->arr[i+1];
		//arr[size-2] = arr[size-1]
	}
	(ps->size)--;
	//删除一个元素,有效元素减一
}

九.查找

//查找
int SLCheck1(SL* ps, DataType x)
// x是要找的数据
{
	assert(ps);
	assert(ps->size > 0);
	//至少有一个元素才能够查找

	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
			//找到了,返回下标
		}
	}
	return -1;
}

全部的代码实现

// test.c文件

#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void SLtest()
{
	SL sl;
	SLInit(&sl);//传址调用
	//不能使用传值调用,因为这里sl并没有值
	//传址调用,改变指针指向的内容,给指向内容初始化
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPrint(sl);//2 1
	//SLPushBack(&sl, 12);
	//SLPopFront(&sl);
	//SLPopBack(&sl);
	//SLInsert(&sl, 2, 10);
	//SLEarse(&sl, 1);
	int find = SLCheck1(&sl, 2);
	if (find < 0)
	{
		printf("找不到\n");
	}
	else
	{
		printf("找到了,下标是:%d\n", find);
	}
	SLPrint(sl);
	SLDestroy(&sl);
}
int main()
{
	SLtest();

	return 0;
}
// SeqList.h文件

#pragma once

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

typedef int DataType;//顺序表可以使用多种数据类型

typedef struct SeqList
{
	DataType* arr;
	int size;//有效数据
	int capacity;//空间大小
}SL;//将struct SeqList 改名为SL,更为方便简洁

void SLInit(SL* p);//初始化

void SLDestroy(SL* sl);//销毁

void SLPushFront(SL* sl,DataType x);//头插

void SLPrint(SL sl);//打印顺序表

void SLPushBack(SL* sl, DataType x);//尾插

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

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

void SLInsert(SL* sl,int pop,DataType x);//指定位置之前的插入

void SLEarse(SL* sl, int pop);//指定位置之前的删除

int SLCheck1(SL* sl, DataType x);//查找
// SeqList.c文件


#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

//初始化顺序表
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = 0;//有效数据为0
	ps->capacity = 0;//空间大小为0
}

//销毁顺序表
void SLDestroy(SL* ps)
{
	//如果顺序表不为空,说明arr中还有动态申请的空间
	//要把动态申请的空间free掉
	if (ps->arr != NULL)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	//顺序表不用了,置为NULL
	ps->size = ps->capacity = 0;
	//销毁完有效元素和空间为0
}

//二倍或三倍地扩容
//扩容顺序表
void SLCheck(SL* ps)
{
	assert(ps);
	if(ps->capacity == ps->size)
	//看看空间够不够
	{
		//三目操作符判断给4个空间,还是直接增容2倍
		int NewCapacity = ps->capacity == 0 ? 4 : 2 * (ps->capacity);
		DataType* tmp = realloc(ps->arr, sizeof(DataType) * NewCapacity);
		//用新的指针接收,防止增容失败
		if (tmp == NULL)
		{
			perror("realloc");
			return;//增容失败,提前返回
		}
		//增容成功
		ps->arr = tmp;
		ps->capacity = NewCapacity;
	}
}
//头插
void SLPushFront(SL* ps,DataType x)
{
	assert(ps);
	SLCheck(ps);
	//增容
	int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i-1];
		//最后一次: = 1 ,arr[1] = arr[0]
	}
	ps->arr[0] = x;
	// 0下标的位置,放入插入的元素
	(ps->size)++;
	//插入一个数据,有效元素加一
}

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

//尾插
void SLPushBack(SL* ps,DataType x)
{
	assert(ps);
	SLCheck(ps);
    //判断空间够不够
	ps->arr[ps->size] = x;
	// == arr[size] = x
	(ps->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];
		// arr[size-2] = arr[size-1]
	}
	(ps->size)--;
	//删除一个元素,有效元素少一个
}

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	//指向顺序表的指针不能为空指针
	//为NULL,停止运行
	//不为NULL,继续运行
	assert(ps->size);
	//顺序表不能为空
	(ps->size)--;
	//删除一个元素,有效元素少一个
}

//指定位置之前插入元素
//pop:下标
//x:要插入的元素
void SLInsert(SL* ps, int pop, DataType x)
{
	assert(ps);
	assert(pop >= 0 && pop <= ps->size);
	// pop == size就是尾插
	// pop < size 在中间插入
	// pop == 0 头插
	SLCheck(ps);
	for (int i = ps->size; i > pop; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
		// arr[pop+1] = arr[pop]
	}
	ps->arr[pop] = x;
	(ps->size)++;
}

//指定位置之前的删除
void SLEarse(SL* ps, int pop)
{
	assert(ps);
	assert(pop >= 0 && pop < ps->size);
	
	for(int i = pop;i < ps->size - 1;i++)
	{
		ps->arr[i] = ps->arr[i+1];
		//arr[size-2] = arr[size-1]
	}
	(ps->size)--;
	//删除一个元素,有效元素减一
}

//查找
int SLCheck1(SL* ps, DataType x)
{
	assert(ps);
	assert(ps->size > 0);
	//至少有一个元素才能够查找

	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
			//找到了,返回下标
		}
	}
	return -1;
}

总结

总的来说顺序表的实现还是比较简单的
主要难的地方就是扩容,for循环的结束条件要想一下

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值