讲解如何用C语言实现顺序表这一数据结构

注意:此处我讲解顺序表中画图将下标以指针指向的形式画了出来,在看到下面图片中以指针形式呈现的下标读者不要见怪,只是为了方便理解。

顺序表是一个结构体,如图所示:

​
#pragma once
#include <stdio.h>
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capicity;
}SeqList;

​

由于我们不知道顺序表里要存储的是什么类型的值,所以我们需要typedef一下我们要用的类型,以下讲解均用顺序表存储整型变量来进行讲解。

首先顺序表中的arr指针是用来指向我们要动态开辟的数组的指针,size代表顺序表底层数组存储的有效数据个数,capicity代表我们数组已经开辟好的、可供使用的容量。

以下为我们要实现的顺序表中的各项接口,放到下图以便展示:

// 顺序表初始化
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, int pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, int pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
// 顺序表打印
void SeqListPrint(SeqList* psl);

这里特别说明一下,为什么我们传的参数都是结构体指针?

答:因为我们要去改变的是我们传过去的结构体本身,而不是只用函数里面临时拷贝的结构体,改变函数里临时拷贝的结构体本身是没有任何意义的,传址调用可以改变我们传过去的结构体(也就是我们在main函数里定义的那个顺序表结构体)。

// 顺序表初始化
void SeqListInit(SeqList* psl)
{
	psl->arr = (SLDataType*)malloc(4 * sizeof(SLDataType));
	psl->size = 0;
	psl->capicity = 4;
}

上图为顺序表的初始化方法,我这里的初始化方法采用的是先开辟4个存储整型的空间,然后将有效数据个数size=0,容量capicity=4。

// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl)
{
	if (psl->size == psl->capicity)
	{
		int newcapicity = 2 * psl->capicity;
		psl->arr = (SLDataType*)realloc(psl->arr, newcapicity * sizeof(SLDataType));
		psl->capicity = newcapicity;
	}
}

上图为顺序表的增容方法(只要检查到我们的有效数据个数和容量相等,我们就要扩容,之后的插入数据我们会用到),我们增容使用realloc函数进行增容,这里增容采用的是2倍扩容(由前辈们广泛实验得到2倍扩容是较好的增容方式)。

接下来是我们顺序表中尾插逻辑的讲解:

// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x)
{
	CheckCapacity(psl);
	psl->arr[psl->size] = x;
	psl->size++;
}

上图为我们顺序表尾插的代码。

1.在我们插入数据之前都要检查容量是否足够我们去插入数据。

2.我们在尾插的时候是在下标为size的位置进行尾插的。

3.插入之后,有效数据个数应该+1。

// 顺序表尾删
void SeqListPopBack(SeqList* psl)
{
	psl->size--;
}

尾删逻辑很简单,只要我们把有效数据个数-1,我们就访问不到尾部的那个数据了。

以下为我们顺序表头插的讲解

首先,在顺序表头插的时候需要我们检查容量够不够,我们再去挪动数据,把之前的所有数据都向后挪动一位。

// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x)
{
	CheckCapacity(psl);
	int end = psl->size;
	while (end >= 1)
	{
		psl->arr[end] = psl->arr[end - 1];//arr[1]=arr[0]
		end--;
	}
	psl->arr[0] = x;
	psl->size++;
}

以上为顺序表头插逻辑的代码,首先我们先记录一下当前的size下标以便挪动数据,我用一张图帮助大家理解这里的逻辑(我们这里采用从后往前向后挪动数据以免先前数据被覆盖掉):

挪动完数据以后,我们就可以在下标为0的起始位置插入我们的数据了。

在这里教大家一个小技巧:如果你实在确认不了你循环的结束条件是什么的时候,你就在你的逻辑中加上自己停止循环条件的注释,以便自己确认循环结束条件。

下面是我们头删逻辑的讲解(以下为逻辑图):

头删整体逻辑就是:

1.将数据从前往后向前挪动数据

2.将有效数据个数size -1。

// 顺序表头删
void SeqListPopFront(SeqList* psl)
{
	int src = 0;
	while (src <= psl->size - 2)
	{
		psl->arr[src] = psl->arr[src + 1];//arr[size-2]=arr[size-1]
		src++;
	}
	psl->size--;
}

下面是我们顺序表查找数据的讲解(在这里只讲解查找到第一个符合值的下标):

我们要通过src下标来遍历这个数组查找。

// 顺序表查找,如果找不到我们就返回size下标
int SeqListFind(SeqList* psl, SLDataType x)
{
	int src = 0;
	while (src < psl->size)
	{
		if (psl->arr[src] == x)
		{
			return src;
		}
		src++;
	}
	printf("抱歉,没有找到此数据\n");
	return src;
}

以上为代码实现,逻辑为:

1.如果找到该数据,则返回这个位置的下标

2.找不到则返回size

以下为在指定的pos下标位置插入数据的讲解,其中包含了我们上面讲到的挪动数据的知识

这里我们还要采用的就是从后往前向后挪动数据的方法,最后在pos位置插入我们想要插入的数据。

由于我们这里的逻辑和头插的逻辑基本一致,所以这里不做过多讲解,直接代码奉上:

// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, int pos, SLDataType x)
{
	CheckCapacity(psl);
	int end = psl->size;
	while (end >= pos + 1)
	{
		psl->arr[end] = psl->arr[end - 1];//arr[pos+1]=arr[pos]
		end--;
	}
	psl->arr[pos] = x;
	psl->size++;
}

以下为在指定的pos下标位置删除数据的讲解,其中也包含了我们上面讲到的挪动数据的知识

此处采用的是从前往后向前挪动数据的方法。

由于我们这里的逻辑和头删的逻辑基本一致,所以这里不做过多讲解,直接代码奉上:

// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, int pos)
{
	int src = pos;
	while (src <= psl->size - 2)
	{
		psl->arr[src] = psl->arr[src + 1];//arr[size-2]=arr[size-1]
		src++;
	}
	psl->size--;

}

下面是销毁顺序表的代码:

// 顺序表销毁
void SeqListDestory(SeqList* psl)
{
	psl->size = psl->capicity = 0;
	free(psl->arr);

}

本质就是将psl->arr所指向的数组空间释放掉。

下面是打印顺序表中数据的代码:

// 顺序表打印
void SeqListPrint(SeqList* psl)
{
	int src = 0;
	while (src < psl->size)
	{
		printf("%d ", psl->arr[src]);
		src++;
	}
}

打印顺序表本质上就是在遍历底层的数组。

至此,我们的利用C语言对顺序表的实现就算是讲解完毕了,后续本管家还会持续更新C语言数据结构部分的讲解,展开庖丁解牛般地讲解,感谢观看!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值