数据结构之顺序表——静态顺序表(C语言版)

代码基于Vs2022 X86环境运行调试

数据结构是我们学习编程路上一个很重要的东西

“Algorithm+Data Structures=Programs”这是瑞士计算机科学家尼古拉斯·沃斯在1984年获得图灵奖的一句话 意思是 数据结构加算法=程序。可见数据结构有多么重要。作为入门第一个学习的数据结构,除了时间与空间复杂度,那就是顺序表了。

首先我们来介绍一下顺序表的概念:线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表一般可以分为:

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

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

首先来实现静态顺序表
先从头文件开始写

#pragma once
#define MAX_SIZE 10//定义线性表的长度
//包含头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SQDataType;//定义类型,将整数型重新定义成SQDataType类型,后期如果需要改动的话只需要改变一下int 类型,比如小数:typedef double SQDataType;
//定义结构体,重新命名为SL
typedef struct Sq
{
	SQDataType arr[MAX_SIZE];
	int size;
}SL;
//声明函数
void SeqListInit(SL* ps);

函数:

#include"SqList.h"
//初始化顺序表为0
void SeqListInit(SL* ps)
{
	for (int i = 0; i < MAX_SIZE; i++)
	{
		ps->arr[i] = 0;//初始化顺序表数组为0
	}
	ps->size=0;//初始化size=0
}

测试

#include"Sqlist.h"
void test()
{
	SL s;//定义一个结构体类型的变量s 
	SeqListInit(&s);
}
int main()
{
	test();
	return 0;
}

未初始化之前:
在这里插入图片描述
初始化之后
在这里插入图片描述
由此可见我们初始化函数是成功了的
下来我们开始完成接口函数
第一个:尾插函数

void SeqListPushBack(SL* ps, SQDataType x)
{
//首先判断顺序表是否已满,已满则打印已满然后退出程序
	if (ps->size == MAX_SIZE)
	{
		printf("顺序表已满\n");
		exit(1); // 使用非零值表示程序因错误而终止 
	}
	//重点解释一下,因为ps 是一个指向结构体SL的指针
	ps->arr[ps->size] = x;//所以ps->arr的意思是指向SL中arr数组的值,ps->size的意思是指向SL中size的值
	ps->size++;// 递增 ps 指向的结构体中的 size 成员 等效于  (*p).size++:这是首先解引用 p 指针以得到它所指向的结构体,然后访问该结构体中的 size 成员,并将其值递增 1。
}

再来调试一下看看

在这里插入图片描述
也是成功的没问题
第二个:头插函数

void SeqListPushFront(SL* ps, SQDataType x)
{
	if (ps->size >= MAX_SIZE)
	{
		printf("顺序表已满\n");
		exit(-1);
	}
	int end = ps->size - 1;//获得下标,准备移动数据
	//注意这里应该从后向前移动,不能从前向后移动(会覆盖数据)
	while (end >= 0)//后面有多少个数据就移动多少下
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[0] = x;//赋值
	ps->size++;//插入一个数据,size++;
}

测试:
在这里插入图片描述
插入成功,成功之后size也正确
第三个:尾删函数

void SeqListDeleteBack(SL* ps)
{	
	assert(ps->size > 0);//断言介绍可以参考其他文章
	ps->size--;//直接自减,简单粗暴
}

现在我们直接写一个打印函数来测试

void print(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d  ", ps->arr[i]);
	}
	printf("\n");
}

测试:进行尾删之前:
在这里插入图片描述
进行尾删之后
在这里插入图片描述
可以看到10已经成功的被删除了
第四个:头删函数

void SeqListDeleteFront(SL* ps)
{
	assert(ps->size > 0);
	//我们只需要把后面的数字往前统一挪动一下就可以覆盖掉数组索引为0上的元素了,然后再对数组的长度减一就行了
	int start = 0;
	while (start < ps->size)
	{
		ps->arr[start] = ps->arr[start+1];
		start++;
	}
	ps->size--;
}

进行头删前:
在这里插入图片描述
进行头删后:
在这里插入图片描述
5不见了,OK成功了。
第五个:给位置插入函数

void SqListInter(SL* ps, int pos,SQDataType x)
{
	assert(ps->size > 0);
	//回想一下上面的思路
	//可以想到:我们给出我们要插入的位置,插入位置后面的数统统后移就可以了最后对size++就可以了
	//下来我们实现一下这个函数
	int end =ps->size-1 ;
	while (end >=pos)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[pos] = x;
	ps->size++;
}

插入之前:
在这里插入图片描述

插入之后:
在这里插入图片描述
OK,成功在第二个数字后面插入了一个新数字
第六个:给位置删除函数

void SqListDelete(SL* ps, int pos)
{
	//回想一下上面的尾删
	//思路:直接覆盖,下来开始实现
	int start = pos;//由于我们是删元素,这里我们假设pos=2来解释,设置一个开始覆盖的位置为2;
	while (start <=ps->size)//我们需要一个循环来向前覆盖,我们start需要小于数组内元素个数的大小,例如上面,我们插入完的结果是6 8 5 5 3 2 这里我们要删除8,5向前覆盖,第二个五向前覆盖,3向前覆盖,2也向前覆盖,进行了四次循环,start从2开始到小于6结束也是4次循环,所以可以成功删除目标元素
	{
		ps->arr[start - 1] = ps->arr[start];
		start++;
	}
	ps->size--;
}

删除前
在这里插入图片描述

删除后
在这里插入图片描述
由此可见第二个元素8已经被删除了
第七个:查找数据:
查找结果:
在这里插入图片描述
整体代码:

头文件

#pragma once
#define MAX_SIZE 10

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SQDataType;
typedef struct Sq
{
	SQDataType arr[MAX_SIZE];
	int size;//顺序表元素有多少个
}SL;
void SeqListInit(SL* ps);//初始化
void SeqListPushBack(SL* ps, SQDataType x);//尾插
void SeqListPushFront(SL* ps, SQDataType x);//头插
void SeqListDeleteBack(SL* ps);//尾删
void SeqListDeleteFront(SL* ps);//头删
void SqListInter(SL* ps, int pos,SQDataType x);//给出位置删除
void SqListDelete(SL* ps, int pos);//给出位置删除
int SqListFind(SL* ps, int x);//查找
void print(SL* ps);//打印

函数

#include"SqList.h"
void print(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d  ", ps->arr[i]);
	}
	printf("\n");
}
void SeqListInit(SL* ps)
{
	for (int i = 0; i < MAX_SIZE; i++)
	{
		ps->arr[i] = 0;
	}
	ps->size = 0;
}
void SeqListPushBack(SL* ps, SQDataType x)
{
	if (ps->size == MAX_SIZE)
	{
		printf("顺序表已满\n");
		exit(-1);
	}
	ps->arr[ps->size] = x;
	ps->size++;
}
void SeqListPushFront(SL* ps, SQDataType x)
{
	if (ps->size >= MAX_SIZE)
	{
		printf("顺序表已满\n");
		exit(-1);
	}
	int end = ps->size - 1;//获得下标,准备移动数据
	//注意这里应该从后向前移动,不能从前向后移动(会覆盖数据)
	while (end >= 0)//后面有多少个数据就移动多少下
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[0] = x;//赋值
	ps->size++;//插入一个数据,size++;
}
void SeqListDeleteBack(SL* ps)
{	
	assert(ps->size > 0);
	ps->size--;
}
void SeqListDeleteFront(SL* ps)
{
	assert(ps->size > 0);
	//我们只需要把后面的数字往前统一挪动一下就可以覆盖掉数组索引为0上的元素了,然后再对数组的长度减一就行了
	int start = 0;
	while (start < ps->size)
	{
		ps->arr[start] = ps->arr[start+1];
		start++;
	}
	ps->size--;
}
void SqListInter(SL* ps, int pos,SQDataType x)
{
	assert(ps->size > 0);
	//回想一下上面的思路
	//可以想到:我们给出我们要插入的位置,插入位置后面的数统统后移就可以了最后对size++就可以了
	//下来我们实现一下这个函数
	int end =ps->size-1 ;
	while (end >=pos)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[pos] = x;
	ps->size++;
}
void SqListDelete(SL* ps, int pos)
{
	//回想一下上面的尾删
	//思路:直接覆盖,下来开始实现
	int start = pos;
	while (start <ps->size)
	{
		ps->arr[start - 1] = ps->arr[start];
		start++;
	}
	ps->size--;
}
int SqListFind(SL* ps, int x)
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}

主函数

#include"Sqlist.h"
void test()
{
	SL s;
	SeqListInit(&s);
	SeqListPushBack(&s, 5);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 10);
	SeqListPushFront(&s, 8);
	SeqListPushFront(&s, 6);
	SeqListPushFront(&s, 5);
	SeqListDeleteBack(&s);
	SeqListDeleteFront(&s);
	SqListInter(&s, 2, 5);
	SqListDelete(&s, 2);
	

	print(&s);
	int flag;
	printf("第%d个元素", flag = SqListFind(&s, 6)+1);
}
int main()
{
	test();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值