数据结构与算法:01——顺序表(C++描述)

数据结构与算法:01——顺序表(C++描述)

提示:本文章适合学习完指针与类与对象的C++学习者


前言

提示:顺序表解决的问题是什么?

顺序表能够实现储存和访问元素、动态扩展、插入和删除、排序和查找等操作。


一、顺序表介绍

顺序表是一种常见的数据结构,它是一种线性表,其中的元素按照一定的顺序排列。顺序表的实现是通过数组或类似的连续存储空间来存储元素。适用于需要快速访问和修改元素的场景,但不适用于频繁插入和删除元素的场景。

二、顺序表代码操作

1.顺序表结构

顺序表的结构图如下所示(示例):
在这里插入图片描述

可以看出顺序表的存储地址是连续的,并且通过指针可以实现数据的插入删除、自动扩容等操作,并且顺表由三部分组成:size容量、count元素个数、*data数据。

我们要实现顺序表的以下功能:

#include <iostream>
#include<ctime>
using namespace std;

class vector
{
public:
	// 初始化顺序表
	vector(int n)`;
	//判断顺序表是否为空
	bool is_Empty();
	//判断顺序表是否已满
	bool is_Full();
	//返回顺序表长度
	int Size();
	// 插入数据
	// 参数pos表示在pos位置插入val数值
	bool insert(int pos, int val) ;
	// 删除元素
	bool erase(int pos);
	// 遍历顺序表并显示元素
	void display();
	// 销毁顺序表
	void clear();
	private:
	//容量
	int size;
	//元素个数
	int count;
	//数据
	int* data;
	//顺序表扩容
	bool expand() 
	};

2.构造函数

示例代码如下所示:

// 初始化顺序表
	vector(int n)
	{
		// 顺序表的长度为n
		this->size = n;
		// 顺序表的元素个数为0
		this->count = 0;
		// 新建一个数据
		this->data = new int[size];
	}

这里的new int[size]类似于创建一个新的指针数组用于开辟一个size大小的内存空间,这样做的好处是,方便控制数组的内存大小,后面扩容操作会使用。

3.判断顺序表是否为空/是否已满/返回顺序表长度

判断顺序表是否为空的关键是搞清容量与元素个数的关系:

1、当元素个数为零时,顺序表为空。
2、当元素个数等于容量时,顺序表已满

下面是示例代码:

//判断顺序表是否为空
	bool is_Empty()
	{
		if(this->count == 0)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	//判断顺序表是否已满
	bool is_Full()
	{
		if(this->count == this->size)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	//返回顺序表长度
	int Size()
	{
		return this->count;
	}	

4.插入

插入操作的完成需要满足一下条件:

1、顺序表未满,或扩容成功。
2、插入位置在合理的范围内。

在此之前,我们先看看如何进行扩容:
扩容操作可以写在public下、也可以写在private下,取决于个人需求。

扩容操作的步骤是:
1、创建一个有2 * size大小的新容器newData
2、将原来data内的数据存入newData
3、将data原来的数据释放
4、令data等于newData 5、修改容量size,使其等于2 * size

下面是示例代码:

//顺序表扩容
	bool expand() {
		//显示提示信息,将原本的顺序表长度扩容到两倍
		cout << "expand vector from " << size << " to " << size * 2 << endl;
		//创建一个新的两倍长的数据容器
		int* newData = new int[size * 2];
		//判断newData是否创建成功
		if (newData == nullptr) {
			return false;
		}
		//将原本data内的数据写进newData里面
		for (int i = 0; i < count; i++) {
			newData[i] = data[i];
		}
		//释放原来data内的数据
		delete[] data;
		//将newData与data相等
		data = newData;
		//将size扩大到两倍
		size = size * 2;
		return true;
	}

下面是插入的示例代码:

	// 插入数据
	// 参数pos表示在pos位置插入val数值
	bool insert(int pos, int val) {
		//判断顺序表是否已满
		if (is_Full()) {
			if (!expand()) {
				//这个代码段检查向量是否已满,如果是,则调用expand()函数进行扩容。
				//否则,跳过扩容的步骤并直接执行插入元素的操作。因此,即使没有显式调用expand()函数,
				//向量也会自动扩容。
				return false;
			}
		}
		else if (pos < 0 || pos > count) {
			return false;
		}
		
		for (int i = count; i > pos; i--) {
			data[i] = data[i - 1];
		}
		
		data[pos] = val;
		count++;
		return true;
	}

下面的循环的原理是下表为 i 的元素被下标为 i - 1的元素取代。

		for (int i = count; i > pos; i--) {
			data[i] = data[i - 1];
		}

运行下面的代码,感受插入数据操作:

#include<iostream>
using namespace std;

int main()
{
	int a[10] = { 1,3,4,5,6 };
	for (int i = 5; i > 1; i--)
	{
		a[i] = a[i-1];
	}
	a[1] = 2;
	for (int i = 0; i < 6; i++)
	{
		cout << a[i] << " ";
	}
	return 0;
}

5、删除

删除操作需要满足的条件是:
1、顺序表不为空
2、删除的元素位置正确

下面是示例代码:

	// 删除元素
	bool erase(int pos)
	{
		if (pos < 0 || pos >= this->count)
		{
			return false;
		}
		else if(this->is_Empty())
		{
			return false;
		}
		else
		{
			for (int i = pos + 1; i < this->count; i++)
			{
				this->data[i - 1] = this->data[i];
			}
			this->count--;
			return true;
		}
	}

6、遍历

示例代码如下所示:

	// 遍历顺序表并显示元素
	void display()
	{
		if (this->count == 0)
		{
			return;
		}
		else
		{
			for (int i = 0; i < this->count; i++)
			{
				cout << this->data[i] << " ";
			}
			cout << endl;
		}
	}

7、销毁顺序表

	// 销毁顺序表
	void clear()
	{
		delete[] this->data;
		this->data = nullptr;
		this->size = 0;
		this->count = 0;
	}

三、完整代码

#include <iostream>
#include<ctime>
using namespace std;

class vector
{
public:
	// 初始化顺序表
	vector(int n)
	{
		// 顺序表的长度为n
		this->size = n;
		// 顺序表的元素个数为0
		this->count = 0;
		// 新建一个数据
		this->data = new int[size];
	}
	
	//判断顺序表是否为空
	bool is_Empty()
	{
		if(this->count == 0)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	//判断顺序表是否已满
	bool is_Full()
	{
		if(this->count == this->size)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	//返回顺序表长度
	int Size()
	{
		return this->count;
	}	
	
	// 插入数据
	// 参数pos表示在pos位置插入val数值
	bool insert(int pos, int val) {
		//判断顺序表是否已满
		if (is_Full()) {
			if (!expand()) {
				//这个代码段检查向量是否已满,如果是,则调用expand()函数进行扩容。
				//否则,跳过扩容的步骤并直接执行插入元素的操作。因此,即使没有显式调用expand()函数,
				//向量也会自动扩容。
				return false;
			}
		}
		else if (pos < 0 || pos > count) {
			return false;
		}
		
		for (int i = count; i > pos; i--) {
			data[i] = data[i - 1];
		}
		
		data[pos] = val;
		count++;
		return true;
	}
	
	// 删除元素
	bool erase(int pos)
	{
		if (pos < 0 || pos >= this->count)
		{
			return false;
		}
		else if(this->is_Empty())
		{
			return false;
		}
		else
		{
			for (int i = pos + 1; i < this->count; i++)
			{
				this->data[i - 1] = this->data[i];
			}
			this->count--;
			return true;
		}
	}
	
	// 遍历顺序表并显示元素
	void display()
	{
		if (this->count == 0)
		{
			return;
		}
		else
		{
			for (int i = 0; i < this->count; i++)
			{
				cout << this->data[i] << " ";
			}
			cout << endl;
		}
	}
	
	// 销毁顺序表
	void clear()
	{
		delete[] this->data;
		this->data = nullptr;
		this->size = 0;
		this->count = 0;
	}
	

private:
	int size;
	int count;
	int* data;
	
	//顺序表扩容
	bool expand() {
		//显示提示信息,将原本的顺序表长度扩容到两倍
		cout << "expand vector from " << size << " to " << size * 2 << endl;
		//创建一个新的两倍长的数据容器
		int* newData = new int[size * 2];
		//判断newData是否创建成功
		if (newData == nullptr) {
			return false;
		}
		//将原本data内的数据写进newData里面
		for (int i = 0; i < count; i++) {
			newData[i] = data[i];
		}
		//释放原来data内的数据
		delete[] data;
		//将newData与data相等
		data = newData;
		//将size扩大到两倍
		size = size * 2;
		return true;
	}
};

int main()
{
	srand(time(0));
	vector v(2);
	v.insert(0,1);
	v.insert(0,2);
	v.insert(0,3);
	v.insert(0,4);
	v.insert(0,5);
	v.insert(0,6);
	v.insert(0,7);
	v.insert(0,8);
	v.display();
	return 0;
}

总结

顺序表是一个高级的数组,能够实现很多数组实现不了的功能。

这是本系列的第一篇文章,希望获得你们的大拇指与五角星,点赞越多更新越快。(doge)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值