C语言-数据结构之顺序表

本文详细介绍了顺序表的定义,包括静态和动态两种形式,以及其接口的实现,如初始化、销毁、打印、扩容检查、增加(尾插、头插、指定位置)、删除(尾删、头删、指定位置)和查找功能。重点展示了如何在SeqList.h和SeqList.c文件中实现这些功能。
摘要由CSDN通过智能技术生成
一.顺序表定义

目录

一.顺序表定义

1.线性表

2.顺序表的定义和分类

二.接口的实现

1.准备工作及其注意事项

2.顺序表的基本功能接口

2.1 顺序表的初始化

2.2 顺序表的销毁

2.3 顺序表的打印

3.顺序表的扩容检查接口

4.顺序表的增加功能接口

4.1 尾插接口

4.2 头插接口

4.3 指定位置插入接口

5.顺序表的删除功能接口

5.1 尾删接口

5.2头删接口

5.3指定位置删除接口

6.顺序表的查找实现接口

三.总代码概览

SeqList.h文件

SeqList.c文件


1.线性表
线性表( linear list )是n个具有相同特性的数据元素的有限序列, 线性表是⼀种在实际中⼴泛使
⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。
简单来说顺序表是线性表的一种,而且逻辑和物理都是线性结构
2.顺序表的定义和分类

顺序表的底层是数组,通过增加一些增删查找等接口实现

2.1 静态顺序表

静态顺序表(这里拿里面存储的整形举例)
typedef int SLDataType;
#define N 100
typedef struct SeqList
{
    SLDatatype arr[N];
    int size;//size是有效数据的个数
}SL;

解释一下为什么要把存储的类型变为SLDataType
这么做是为了方便以后修改
还有把数组存储的数据容量便于修改

2.2 动态顺序表

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}SL;//这里我们定义了一个结构体,其实这就是一个动态的顺序表

因为动态顺序表的结构更加灵活,所以我们下面的接口都是通过动态顺序表实现的

二.接口的实现
1.准备工作及其注意事项

我们需要创建3个文件

我先来解释一下这三个文件的作用,头文件SeqList.h是来声明接口以及定义顺序表

源文件SeqList.c是用来具体实现接口,源文件test.c用于接口的测试工作

注意事项几条小点
1.不管是任意一种操作我们在处理之前都要判段  assert(ps->arr) ;
2.在进行扩容的时候别忘记了  要把容量变成新开出来的那个 
3.进行插入操作之后  要把size++;  在进行删除操作的时候要进行size--;
4.进行删除操作的时候  除了要判断第一种断言之外,还要在判断 assert(ps->size) 
5.进行指定位置插入或者删除的时候,要进行判断pos的范围问题

小拓展:
1.尝试用memmove函数覆盖数据 
2.for循环的使用方法其实只看头尾即可 
3.尝试用while循环代替for循环实现
4.进行移动的时候方向问题的判断就是是否会有重叠  

2.顺序表的基本功能接口
2.1 顺序表的初始化
void SLInit(SL* ps)
{
	assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
2.2 顺序表的销毁
void SLDestroy(SL* ps)
{
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
2.3 顺序表的打印
void SLPrint(SL* ps)
{
	assert(ps);
	for (int i = 0;i < ps->size;++i)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}
3.顺序表的扩容检查接口

这个接口在进行增加元素的时候,需要用到,因为不确定空间是否足够

void SLCheckCapacity(SL* ps)
{
	assert(ps);
	int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
	if (ps->capacity == ps->size)
	{
		SLDataType* ptr = (SLDataType*)realloc(ps->arr, sizeof(SLDataType) * newCapacity);
		if (ptr == NULL)
		{
			perror("realloc");
			exit(1);
		}
		ps->arr = ptr;
		ps->capacity = newCapacity;
	}
}
4.顺序表的增加功能接口
4.1 尾插接口
void SLPushBack(SL* ps,int x)
{
	assert(ps);
	SLCheckCapacity(ps);//判断以下是否需要扩容
	ps->arr[ps->size] = x;//经过判断是否扩容之后,直接插入arr[size]的位置
}
4.2 头插接口

我们给三种实现方式,循环实现的时候,从头部遍历还是尾部遍历要看元素是否有重叠

//01(for循环实现)
void SLPushFront01(SL* ps, int 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++;
}
//02(while循环实现)
void SLPushFront02(SL* ps, int x)
{
	assert(ps);
	SLCheckCapacity(ps);//判断以下是否需要扩容
	int begin = ps->size;
	while (begin > 0) 
	{
		ps->arr[begin] = ps->arr[begin - 1];
		begin--;
	}
	ps->arr[0] = x;
	ps->size++;
}
//03(内存操作函数memmove实现)
void SLPushFront03(SL* ps, int x)
{
	assert(ps);
	SLCheckCapacity(ps);//判断以下是否需要扩容
	memmove((ps->arr) + 1, ps->arr, sizeof(SLDataType) * ps->size);
	ps->arr[0] = x;
	ps->size++;
}
4.3 指定位置插入接口

这个与上面的头插类似

//01for循环实现
void SLInsert01(SL* ps, int pos, int x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size;i > pos;--i)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}
//02while循环实现
void SLInsert02(SL* ps, int pos,int x)
{
	assert(ps);
	int begin = ps->size;
	while (begin > pos)
	{
		ps->arr[begin] = ps->arr[begin - 1];
		begin--;
	}
	ps->arr[pos] = x;
	ps->size++;
}
//03memmove内存操作函数实现
void SLInsert03(SL* ps, int pos, int x)
{
	assert(ps);
	memmove(ps->arr + pos, ps->arr + pos + 1, sizeof(SLDataType) * (ps->size - pos));
	ps->arr[pos] = x;
	ps->size++;
}
5.顺序表的删除功能接口
5.1 尾删接口
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}
5.2头删接口
//01for循环实现
void SLPopFront01(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--;
}
//02while循环实现
void SLPopFront02(SL* ps)
{
	assert(ps);
	assert(ps->size);
	int begin = 0;
	while (begin < ps->size - 1)
	{
		ps->arr[begin] = ps->arr[begin + 1];
	}
	ps->size--;
}
//03memmove内存操作函数实现
void SLPopFront03(SL* ps)
{
	assert(ps);
	assert(ps->size);
	memmove(ps->arr, ps->arr + 1, sizeof(SLDataType) * (ps->size - 1));
	ps->size--;
}
5.3指定位置删除接口
//01for循环实现
void SLErase01(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	for (int i = pos;i < ps->size-1;++i)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
//02while循环实现
void SLErase02(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	int begin = pos;
	while (begin < pos - 1)
	{
		ps->arr[begin] = ps->arr[begin + 1];
		begin++;
	}
	ps->size--;
}
//03memmove内存操作函数实现
void SLErase03(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	memmove(ps ->arr, ps->arr + 1, sizeof(SLDataType) * (ps->size - pos - 1));
	ps->size--;
}
6.顺序表的查找实现接口
int SLFind(SL* ps, int x)
{
	for (int i = 0;i < ps->size;++i)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}
三.总代码概览
SeqList.h文件
#pragma once
#include<memory.h>
//这里的头文件进行的顺序表的声明
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}SL;//这里我们定义了一个结构体,其实这就是一个动态的顺序表

void SLInit(SL* ps);//顺序表的初始化
void SLPrint(SL* ps);//顺序表的打印
void SLDestroy(SL* ps);//顺序表的销毁

void SLCheckCapacity(SL* ps);//顺序表的扩容检查(扩容的原则,以及扩容的方法)

void SLPushBack(SL* ps,int x);//顺序表的尾插
//顺序表的头插
void SLPushFront01(SL* ps, int x);
void SLPushFront02(SL* ps, int x);
void SLPushFront03(SL* ps, int x);
//顺序表的指定位置插入(这里的指定位置我们指的是下标前面)
void SLInsert01(SL* ps, int pos, int x);
void SLInsert02(SL* ps, int pos, int x);
void SLInsert03(SL* ps, int pos, int x);

void SLPopBack(SL* ps);//顺序表的尾删
void SLPopFront(SL* ps);//顺手表的头删
void SLErase(SL* ps,int pos);//顺序表的指定位置删除

SeqList.c文件
#include<stdio.h>
#include<assert.h>
#include<memory.h>
#include"SeqList.h"
//这里的源文件我们进行的头文件中的函数的具体实现
//也就是封装相关的函数

//1.顺序表的初始化
void SLInit(SL* ps)
{
	assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
//2.顺序表的打印
void SLPrint(SL* ps)
{
	assert(ps);
	for (int i = 0;i < ps->size;++i)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}
//3.顺序表的销毁
void SLDestroy(SL* ps)
{
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

//4.顺序表的扩容检查(扩容的原则,以及扩容的方法)
void SLCheckCapacity(SL* ps)
{
	assert(ps);
	int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
	if (ps->capacity == ps->size)
	{
		SLDataType* ptr = (SLDataType*)realloc(ps->arr, sizeof(SLDataType) * newCapacity);
		if (ptr == NULL)
		{
			perror("realloc");
			exit(1);
		}
		ps->arr = ptr;
		ps->capacity = newCapacity;
	}
}

//5.顺序表的尾插
void SLPushBack(SL* ps,int x)
{
	assert(ps);
	SLCheckCapacity(ps);//判断以下是否需要扩容
	ps->arr[ps->size] = x;//经过判断是否扩容之后,直接插入arr[size]的位置
}
//6.顺序表的头插
//01(for循环实现)
void SLPushFront01(SL* ps, int 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++;
}
//02(while循环实现)
void SLPushFront02(SL* ps, int x)
{
	assert(ps);
	SLCheckCapacity(ps);//判断以下是否需要扩容
	int begin = ps->size;
	while (begin > 0) 
	{
		ps->arr[begin] = ps->arr[begin - 1];
		begin--;
	}
	ps->arr[0] = x;
	ps->size++;
}
//03(内存操作函数memmove实现)
void SLPushFront03(SL* ps, int x)
{
	assert(ps);
	SLCheckCapacity(ps);//判断以下是否需要扩容
	memmove((ps->arr) + 1, ps->arr, sizeof(SLDataType) * ps->size);
	ps->arr[0] = x;
	ps->size++;
}
//7.顺序表的指定位置插入
//01for循环实现
void SLInsert01(SL* ps, int pos, int x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size;i > pos;--i)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}
//02while循环实现
void SLInsert02(SL* ps, int pos,int x)
{
	assert(ps);
	int begin = ps->size;
	while (begin > pos)
	{
		ps->arr[begin] = ps->arr[begin - 1];
		begin--;
	}
	ps->arr[pos] = x;
	ps->size++;
}
//03memmove内存操作函数实现
void SLInsert03(SL* ps, int pos, int x)
{
	assert(ps);
	memmove(ps->arr + pos, ps->arr + pos + 1, sizeof(SLDataType) * (ps->size - pos));
	ps->arr[pos] = x;
	ps->size++;
}

//8.顺序表的头删
//01for循环实现
void SLPopFront01(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--;
}
//02while循环实现
void SLPopFront02(SL* ps)
{
	assert(ps);
	assert(ps->size);
	int begin = 0;
	while (begin < ps->size - 1)
	{
		ps->arr[begin] = ps->arr[begin + 1];
	}
	ps->size--;
}
//03memmove内存操作函数实现
void SLPopFront03(SL* ps)
{
	assert(ps);
	assert(ps->size);
	memmove(ps->arr, ps->arr + 1, sizeof(SLDataType) * (ps->size - 1));
	ps->size--;
}
//9.顺序表的尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}
//10.指定位置删除
//01for循环实现
void SLErase01(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	for (int i = pos;i < ps->size-1;++i)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
//02while循环实现
void SLErase02(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	int begin = pos;
	while (begin < pos - 1)
	{
		ps->arr[begin] = ps->arr[begin + 1];
		begin++;
	}
	ps->size--;
}
//03memmove内存操作函数实现
void SLErase03(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	memmove(ps ->arr, ps->arr + 1, sizeof(SLDataType) * (ps->size - pos - 1));
	ps->size--;
}

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

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值