顺序表的实现

1.概念及结构

顺序表是用一段 物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。
顺序表一般可以分为:

1. 静态顺序表:使用定长数组存储元素

#define  N 7

 2. 动态顺序表:使用动态开辟的数组存储。

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致 N 定大了,空
间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间
大小,所以下面我们实现动态顺序表。

typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
  SLDataType* array;  // 指向动态开辟的数组
  size_t size ;       // 有效数据个数
  size_t capicity ;   // 容量空间的大小
}SeqList;
// 基本增删查改接口
// 顺序表初始化
void SeqListInit(SeqList* psl);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* psl);
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);
// 顺序表头删
void SeqListPopFront(SeqList* psl);
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x); 
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
// 顺序表打印
void SeqListPrint(SeqList* psl);

 

2.五大功能实现

2.1尾插

void SeqListPushBack(SL* ps1, SLDataType x)

assert(ps1);
CheckCapacity(ps1);
ps1->a[ps1->size] = x;
ps1->size++;

我们先进行断言 后检查一遍容量  都可行后 尾插可以直接放入之后的空间

直接将x放入下标为size即可

2.2头插 

 void SeqListPushFront(SL* ps1, SLDataType x)

 

void SeqListPushFront(SL* ps1, SLDataType x)
{
	assert(ps1);
	CheckCapacity(ps1);
	//挪动数据
	int end = ps1->size - 1;
	while (end >= 0)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}
	ps1->a[0] = x;
	ps1->size++;

}

 头部插入我们先进行断言和检查容量

逐步进行挪动 最后赋值到首元素地址并进行  size++

 

2.3尾删

 void SLPopBack(SL* ps1)

 

void SLPopBack(SL* ps1)
{
	assert(ps1);
	assert(ps1->size > 0);
	ps1->size--;
}

 思想:尾删我们直接将size--  这样他就没有访问原size的权限 哪怕原size的数据还存在 那他也访问不到了  

2.4头删

 void SLPopFront(SL* ps1)

 

void SLPopFront(SL* ps1)
{
	int begin = 1;
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];
		++begin;
	}
	ps1 ->size--;
}

 头删我们采用覆盖的方法 就是将下一个元素赋值给上一个元素 所以我们定义一个下标从1开始覆盖第一个元素 

2.5指哪删哪

void SLErase(SL* ps1, int pos)   pos是下标

 

void SLErase(SL* ps1, int pos)
{
	assert(ps1);
	assert(pos >= 0 && pos < ps1->size);
	int begin = pos + 1;
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];
		++begin;
	}
	ps1->size--;
}

首先我们要判断pos的判断条件  找到对应下标进行+1存为begin下标  判断循环

 

2.6指哪加哪 

void SLInsert(SL* ps1, int pos, SLDataType x)

void SLInsert(SL* ps1, int pos, SLDataType x)
{
	assert(ps1);
	assert(pos >= 0 && pos <= ps1->size);

	CheckCapacity(ps1);
	//挪动数据
	int end = ps1->size - 1;
	while (end >= pos)
	{
		ps1->a[end + 1] = ps1->a[end];
		--end;
	}
	ps1->a[pos] = x;
	ps1->size++;
}

 删不需要检查容量 而我们增加i据需要检查容量了

原理也是挪动数据  我们原理是把x赋值给下标为pos的值 然后其他依此向后挪动

 

 3. 接口实现

3.1自定义类型

我们首先进行头文件说明

typedef int SLDataType

这是为了我们后续在创建变量涉及到整形 浮点型转换时不必过于麻烦 

 typedef struct SeqList
{
    SLDateType* a;
    int size;
    int capacity;
}SL;

在这里我们创建了自定义结构体类型  定义了一个a指针  size表示数组长度  capacity表示数据容量

随后我们进行正式的函数实现

3.2顺序表的初始化 

void SLInit(SL* ps1);

我们在SeqList.h文件里声明函数

创建一个源文件来实现函数声明

void SLInit(SL* ps1)
{
	assert(ps1);
	ps1->a = NULL;
	ps1->size = 0;
	ps1->capacity = 0;
}

 在这里我们创建结构体指针

1:进行assert断言  ps1指针必须不为NULL,

2:对ps1->a进行赋空指针  

3.3 顺序表的销毁

void SLDestroy(SL* ps1)
{
	assert(ps1);
	if (ps1->a != NULL)
	{
		free(ps1->a);
		ps1->a = NULL;
		ps1->size = 0;
		ps1->capacity = 0;

	}
}

逻辑:

1.先进行断言

2.判断数据是否为空 因为如果容量不够 我们在内存中选择动态内容进行开辟  

开辟后需要释放空间 否则会内存泄露  所以我们先free  释放后要将a置空 其他赋值0

定义完顺序表的基本框架后 我们下面开始实现如何基本功能

3.4打印函数 

 

oid SLPrint(SL* ps1)
{
	assert(ps1);
	for (int i = 0; i < ps1->size; i++)
	{
		printf("%d", ps1->a[i]);
	}
}

这里没什么好说的  直接上代码

3.5检查容量

 void SLCheckCapacity(SL* ps1)
{
    assert(ps1);
    if (ps1->size == ps1->capacity)
    {
        int newcapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;
        SLDateType* tmp = (SLDateType*)realloc(ps1->a, sizeof(SLDateType) * newcapacity);
        if (tmp == NULL)
        {
            perror("realloc fail : ");
            return;
        }
        ps1->a = tmp;
        ps1->capacity = newcapacity;
    }
}

首先我们先进行断言

其次,我们为什么要检查容量 目的是什么?  

1. 我们如果不适用静态数组  如果我们可容纳10人的信息 而我们储存了11个信息 此时就会栈溢出

所以我们的目的就是为了动态自动扩容  

2.我们已经提到了目的是为了防止容量不够才进扩容 所以我们第一步是判断size 是否等于我们的capacity  如果相等 说明我们该扩容了  

3.精髓的一步: 将 capacity 赋值给 newcapacity  我们选择使用三目操作符

要考虑到如果容量是0呢?  所以当他为0时我们让他变为4  不为0我们让他进行*2操作

接下来我们要将原来的capacity动态开辟 我们使用realloc 我们创建一个指针来存放数据 以防止如果我们开辟内存失败 原指针也变为NULL

随后赋值给原指针

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hqxnb666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值