当前位置:   article > 正文

数据结构——顺序表的C语言代码实现_顺序表c语言代码

顺序表c语言代码

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

系列文章目录

数据结构——顺序表的C语言代码实现
数据结构——八种链表的C语言代码实现
数据结构——栈的C语言代码实现
数据结构——队列的C语言代码实现
数据结构——堆的C语言代码实现


前言

使用C语言实现顺序表,重点实现动态顺序表。加强模块化实现功能的能力,了解并熟练使用realloc(),assert()等函数。

一、基础知识

1.顺序表的概念(Sequential List)

鬼话:顺序表 就是把线性表中的所有元素按照其逻辑顺序,依次储存到从指定的储存位置开始的一块 连续 的储存空间中。
人话:自我理解,特殊的数组!即将连续的数据存储在数组中,注意连续性,不可跳跃式存储。

2.常用的接口函数

在进行数据结构的代码实现时,最常用的接口函数便是:增、删、查、改。
增:尾插、头插、指定位置插入;
删:尾删、头删、指定位置删除;
查:遍历查找;
改:先找后改;

3.realloc()函数使用细节

realloc()函数:
void* realloc (void* ptr, size_t size);
注意:
1.返回值是void*,实际使用中应合理使用强制类型转换;
2.size_t size 是字节数,即所需要开辟的空间大小,此处应和calloc()结合记忆,注意区别!
3.引用<stdlib.h>
戳此处,查看realloc函数标准形式
realloc()是C语言中最常用的扩容或缩容函数,其改变已开辟的内存空间大小的工作实质是:
在已有空间的末尾寻找空余的连续空间,若末尾的空余空间足够开辟,则便在此处进行开辟,返回的指针为原指针,即所开辟的空间的起始地址没有发生改变;若末尾的空余空间不足以开辟,则对已开辟空间所存储的内容进行拷贝,然后在内存的其它位置寻找足够大的连续空间进行开辟,而原有空间被系统释放,故此时该函数的返回值不再是原指针,即所开辟的空间的起始地址发生了改变;
但实际使用时,未避免引用过多指针,常使用以下方式进行操作:

(DataType*) ptr=(DataType*)realloc(p,sizeof(DataType)*size_t);
if(ptr!=NULL)
	p=ptr;
  • 1
  • 2
  • 3

4.assert( )函数

assert()函数:

void assert (int expression);
  • 1

戳此处,查看assert()函数标准形式
注意引用<assert.h>
条件为真,继续向下执行;
条件为假,终止程序。

二、代码实现

1.SepList.h

(1)引用函数库

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
  • 1
  • 2
  • 3

(2)定义动态顺序表

建议遵循命名规则,将动态数组命名为arr等名字,p总是带来误解,但我懒得改了。。。

typedef int SLDataType;
//便于更改所存储数据的类型
typedef struct SeqLIst
{
	SLDataType* p;
	int size;
	int capacity;
}SL;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(3)接口函数声明

注意在设计接口函数时应使用传址的参数

//初始顺序表
void SeqListInit(SL* ps);

//顺序表的尾插法
void SeqListPushBack(SL* ps, SLDataType n);

//顺序表的尾删法
void SeqListPopBack(SL* ps);

//顺序表的头插法
void SeqListPushFront(SL* ps, SLDataType n);

//顺序表的头删法
void SeqListPopFront(SL* ps);

//查找顺序表中的数据位置
int Find(SL* ps,SLDataType n);

//指定位置插入
void SeqListInsert(SL* ps, int location, SLDataType n);

//指定位置删除
void SeqListDelete(SL* ps, int location);

//检测顺序表容量是否足够
void CheckCapacity(SL* ps);

//接口函数测试函数
void PrintSeqList(SL* ps);

//删除顺序表
void DestroySeqList(SL* ps);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

2.SepList.c

此文件用于实现各接口函数。

(1)引用头文件

#include"SeqList.h"
  • 1

(2)初始顺序表

//初始顺序表
void SeqListInit(SL* ps)
{
	(*ps).p = NULL;
	ps->capacity = 0;
	ps->size = 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(3)检测顺序表容量是否足够

//检测顺序表容量是否足够
void CheckCapacity(SL* ps)
{
	//进行扩容,两种情况:1.没有开辟空间;2.容量用尽
	if (ps->size == ps->capacity)
	{
		int Newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* ptr = (SLDataType*)realloc(ps->p, sizeof(SLDataType) * Newcapacity);
		if (ptr != NULL)
			//扩容成功
			ps->p = ptr;
		else
		{
			printf("realloc fail !");
			//异常退出,终止程序,使用return的话,只是退出该函数
			exit(-1);
		}
		ps->capacity = Newcapacity;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

(4)顺序表的尾插法

//顺序表的尾插法
void SeqListPushBack(SL* ps, SLDataType n)
{
	CheckCapacity(ps);
	ps->p[ps->size] = n;
	ps->size += 1;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(5)顺序表的尾删法

<1>使用if判断的温和法
void SeqListPopBack(SL* ps)
{
	if(ps->size>0)
	ps->size--;
}
  • 1
  • 2
  • 3
  • 4
  • 5
<2>使用assert()断言的暴躁法

何为暴躁?
assert(条件)条件为假,直接终止函数!

void SeqListPopBack(SL* ps)
{
	assert(ps->size>0)
	ps->size--;
}
  • 1
  • 2
  • 3
  • 4
  • 5

(6)全部删除

//删除顺序表
void DestroySeqList(SL* ps)
{
	free(ps->p);
	//防止该指针成为野指针
	ps->p = NULL;
	ps->capacity = ps->size = 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(7)头插法

//顺序表的头插法
void SeqListPushFront(SL* ps, SLDataType n)
{
	CheckCapacity(ps);
	//用前值覆盖后值,实现整体后移,必须从后向前两两操作
	ps->size += 1;
	int end = ps->size - 1;
	while (end > 0)
	{
		//实现插入前的数组的整体后移
		ps->p[end] = ps->p[end - 1];
		end--;
	}
	ps->p[0] = n;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

(8)头删法

//顺序表的头删法
void SeqListPopFront(SL* ps)
{      
	assert(ps->size > 0);
	//将已有数组整体前移
	int head = 0;
	while (head < ps->size - 1)
	{
		ps->p[head] = ps->p[head + 1];
		head++;
	}
	ps->size--;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(9)查找某个数值的位置

int Find(SL* ps, SLDataType n)
{
	if (ps->size == 0)
	{
		printf("顺序表为空!\n");
		exit(-1);
	}
	int tem = 0;
	while (tem < ps->size)
	{
		if (ps->p[tem] == n)
		{
			return tem;
		}
		tem++;
	}
	printf("顺序表中没有该值!\n");
	return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

(10)指定位置插入

注意判断所要插入的位置,进而合理使用已有的接口函数,该程序设计中输入的位置是从1开始的!

//指定位置插入
void SeqListInsert(SL* ps, int location,SLDataType n)
{
	//因为输入的位置是从1开始数的
	int L = location - 1;
	//确保所要插入的位置合法
	assert(L>=0&&L<=ps->size);
	//确保顺序表不为空
	assert(ps->size > 0);
	CheckCapacity(ps);
	//如果插入位置在头部
	if (L == 0)
	{
		SeqListPushFront(ps, n);
	}
	//如果插入位置在尾部
	else if (L == ps->size)
	{
		SeqListPushBack(ps, n);
	}
	//如果插入位置在已有数组内部
	else
	{
		ps->size++;
		int temend = ps->size - 1;
		while (temend > L)
		{
			ps->p[temend] = ps->p[temend - 1];
			temend--;
		}
		ps->p[L] = n;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

(11)指定位置删除

//指定位置删除
void SeqListDelete(SL* ps, int location)
{
	int L = location - 1;
	//确保输入的位置合法
	assert(L>=0&&L<=ps->size-1);
	//确保顺序表不为空
	assert(ps->size > 0);
	if (L == 0)
	{
		SeqListPopFront(ps);
	}
	else if (L == ps->size - 1)
	{
		SeqListPopBack(ps);
	}
	else
	{
		int temend = L;
		while (temend < ps->size - 1)
		{
			ps->p[temend] = ps->p[temend+1];
			temend++;
		}
		ps->size -= 1;
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

(12)打印函数

//接口函数测试
void PrintSeqList(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->p[i]);
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.test.c

该文件用于存放主函数,本程序只研究如何代码实现顺序表,故多为测试语句,不具有参考价值。具体使用时,可在此处代码实现菜单功能!

(1)引用头文件

#include"SeqList.h"
  • 1

(2)各种测试函数

该处无参考价值,大家随意设置

void testSeqList()
{
	SL sl;
	SeqListInit(&sl);
	SeqListPushBack(&sl, 1);
	SeqListPushBack(&sl, 2);
	SeqListPushBack(&sl, 3);
	SeqListPushBack(&sl, 4);
	/*SeqListPopBack(&sl,5);
	SeqListPushFront(&sl, 0);*/
	//用来测试接口函数
	PrintSeqList(&sl);
	DestroySeqList(&sl);
}
void testSeqListPushFront()
{
	SL sl;
	SeqListInit(&sl);
	SeqListPushFront(&sl, 1);
 	SeqListPushFront(&sl, 2);
	SeqListPushFront(&sl, 3);
	SeqListPushFront(&sl, 4);
	SeqListPopFront(&sl);
	//int ret=Find(&sl, 2);
	 PrintSeqList(&sl);
	/* printf("\n");
	 printf("%d", ret);*/
	 SeqListDelete(&sl,3);
	 PrintSeqList(&sl);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

(3)主函数

亦无实际价值

int main()
{
	//testSeqList();
	testSeqListPushFront();
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

三、总结

数据结构的学习在于实际操作,大学课堂的教学偏向于理论学习,如若只是浅尝辄止地了解一些名词概念毫无作用,故特此逐一实现数据结构的C语言代码,进而鞭策自己迎难而上!
与君共勉!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/416609
推荐阅读
相关标签
  

闽ICP备14008679号