IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构--顺序表通过C语言实现~ -> 正文阅读

[数据结构与算法]数据结构--顺序表通过C语言实现~

1.顺序表的概念

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

1.1 静态顺序表

//静态的顺序表
#define N 10
struct SeqList
{
	int a[N];
	int size;
};

静态顺序表的大小是给定的,不能再变的。不灵活。一般大小未知的不用静态顺序表。

1.2 动态顺序表

//动态的顺序表
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;
	int size;//存储数据个数
	int capacity;//存储空间大小
}SeqList;

而动态顺序表的大小是可以改变的,后期通过函数对空间大小进行修改。推荐使用动态顺序表,而且本篇文章就是讲的动态顺序表。

2.顺序表接口的实现

接下来开始实现顺序表,先将要用的到的函数封装到头文件中:

//动态的顺序表
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;//指向动态开辟的数组
	int size;//存储数据个数
	int capacity;//存储空间大小
}SeqList;

void SeqListInit(SeqList* ps1);//初始化顺序表
void SeqListDestroy(SeqList* ps1);//销毁顺序表

void CheckSeqList(SeqList* ps1);//检查空间是否足够,不够会增容
void PrintSeqList(SeqList* psl);//打印顺序表中的内容

void SeqListPushBack(SeqList* ps1, SLDataType x);//尾插
void SeqListPopBack(SeqList* ps1);//尾删

void SeqListPushFront(SeqList* ps1, SLDataType x);//头插
void SeqListPopFront(SeqList* ps1);//头删

//在pos位置插入x
void SeqListInsert(SeqList* ps1, size_t pos, size_t x);
//删除pos位置的数据
void SeqListErase(SeqList* ps1, size_t pos);
//查找数据
int FindSeqList(SeqList* ps1, size_t x);

接下来开始实现各种功能:

2.1 初始化、删除函数

//初始化顺序表
void SeqListInit(SeqList* ps1)
{
	ps1->size = 0;
	ps1->a = NULL;
	ps1->capacity = 0;
}

//删除顺序表
void SeqListDestroy(SeqList* ps1)
{
	assert(ps1);
	free(ps1->a);
	ps1->a = NULL;
	ps1->size = ps1->capacity = 0;

}
  • 在这里要注意,删除顺序表中要free掉指针,因为动态顺序表是动态开辟出的空间,而且在用free函数时可以检测整个运行过程中有没有数组越界的情况!free函数是有这个特点的。不同的环境对函数越界的情况检查方式是不太一样的。编译器对越界错误的检查是随机的,抽查的,也就是说出现了越界问题编译器也不一定会报错。在vs环境中,编译器对越界的检查是比较宽松的。但是不报错就不代表没有错,在学习关于线性表的知识时一定要注意数组越界问题。

?如下是在vs环境下数组越界情况:

?报错的情况

不报错的情况?

2.2 检查线性表是否有足够空间(如果不足扩容)

//检查空间大小

void CheckSeqList(SeqList* ps1)
{
	assert(ps1);
	if (ps1->size == ps1->capacity)
	{
		SLDataType* p = (SLDataType*)realloc(ps1->a, sizeof(SLDataType) * ps->capacity * 2);
		if (p == NULL)
		{
			printf("realloc failed\n");
			exit(-1);//如果开辟不成功 直接强行退出程序
		}
		else
		{
			ps1->a = p;
			ps1->capacity *=2 ;
		}
	}
}

这种方法实际上是不完善的,因为他没有考虑到如果顺序表初始capacity就是0的话怎么处理,如果还按照这种方式就是0*2,还是为0,没有起到如果容量不够扩容的作用。

//完善后的代码
void CheckSeqList(SeqList* ps1)
{
	assert(ps1);
	if (ps1->size == ps1->capacity)
	{
		int New_capacity = ps1->size == 0 ? 4 : ps1->capacity * 2;
		SLDataType* p = (SLDataType*)realloc(ps1->a, sizeof(SLDataType) * New_capacity);
		if (p == NULL)
		{
			printf("realloc failed\n");
			exit(-1);
		}
		else
		{
			ps1->a = p;
			ps1->capacity = New_capacity;
		}
	}
}

?2.3 插入类函数

//头插
void SeqListPushFront(SeqList* ps1, SLDataType x)
{
	assert(ps1);
	CheckSeqList(ps1);
	for (int i = ps1->size; i > 0 ; i--)
	{
		ps1->a[i] = ps1->a[i - 1];
	}
	ps1->a[0] = x;
	ps1->size++;
}

//尾插
void SeqListPushBack(SeqList* ps1, SLDataType x)
{
	assert(ps1);
	CheckSeqList(ps1);
	*(ps1->a + ps1->size) = x;
	ps1->size++;
}

//在pos位置插入x
void SeqListInsert(SeqList* ps1, size_t pos, size_t x)
{
	assert(ps1);
	CheckSeqList(ps1);

	if ((pos - 1) <= (ps1->size - 1))
	{
		for (int i = ps1->size; i > pos - 1; i--)
		{
			ps1->a[i] = ps1->a[i - 1];
		}
		ps1->a[pos - 1] = x;
		ps1->size++;
	}
	else
		printf("越界");

}

  1. 关于尾插和头插比较简单,就是要注意通过调用check函数判断线性表容量是否足够。而且头插实现的方式类似于memmove函数的实现:他们都是从从后向前插入的;(p1)
  2. 关于在pos位置插入要注意pos一定要小于size或者size-1(依据具体的函数写法而定),不要越界。实现方式也和头插一样,都是从后向前插;(p2)
  3. 特殊情况:当pos为0时就是头插,当pos为size时为尾插

?2.4 删除类函数

//头删
void SeqListPopFront(SeqList* ps1)
{
	assert(ps1);
	if (ps1->size > 0)
	{
		for (int i = 0; i < ps1->size - 1; i++)
		{
			ps1->a[i] = ps1->a[i + 1];
		}
		ps1->size--;
	}
}

//尾删
void SeqListPopBack(SeqList* ps1)
{
	assert(ps1);
	if (ps1->size > 0)
	{
		ps1->size--;
	}
}

//删除pos位置的数据
void SeqListErase(SeqList* ps1, size_t pos)
{
	assert(ps1);
	if (ps1->size > 0)
	{
		for (int i = pos-1; i < ps1->size-1; i++)
		{
			ps1->a[i] = ps1->a[i + 1];
		}
		ps1->size--;
	}
}
  1. 删除函数切记一点,一定要在顺序表数据含量size大于0的情况下删除数据,如果不注意的话很有可能造成程序出现bug;
  2. 头删和删除pos位置的数据函数的实现方式都是从前向后移;(p3)
  3. 特殊情况:当pos为0时就是头删,pos为size时为尾删。

?2.5 查找函数

int FindSeqList(SeqList* ps1,size_t x)
{
	assert(ps1);
	for (int i = 0; i < ps1->size; i++)
	{
		if (ps1->a[i] == x)
			return i;
	}
	return -1;
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-13 22:03:13  更:2022-03-13 22:03:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 13:52:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码