线性表之顺序表

本文详细介绍了顺序表的概念、静态顺序表和动态顺序表的实现,包括它们的结构、操作方法(如插入、删除、查找)以及空间管理。通过C语言代码示例展示了如何使用数组实现静态顺序表和动态调整大小的动态顺序表。
摘要由CSDN通过智能技术生成

我们今天学习顺序表,众所周知,顺序表分为静态顺序表和动态顺序表,让我们来看一下吧


目录

1.线性表

2.顺序表的实现

2.1静态顺序表的实现

2.2动态顺序表的实现


1.线性表

1.概念:线性表是个具有相同特性的数据元素的有限序列,它是一种在实际中广泛应用的数                据结构。

2.常见类型:顺序表、链表、栈、队列、字符串(我们之后都要逐个学习)

3.线性表在逻辑上是线性的,也就是说是连续的一条直线。但在物理结构上不一定连续。

4.线性表在物理结构上存储时,通常以数组和链式的结构形式存储。(我们下一篇博客学习链式结构)。

2.顺序表的实现

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

顺序表一般分为:

1.静态顺序表:使用定长数组存储,它的空间是固定的,用完就没有了,不推荐使用

2.动态顺序表:使用动态开辟的数组存储,只要电脑有空间,就可以无限realloc出来,推荐

接下来,让我们看看它们如何实现。

2.1静态顺序表的实现

我们一般认为静态顺序链表是无意义的,因为它的空间是固定的,用完就越界了,空间给少了不够用,给多了会造成空间的浪费,十分笨拙,但在这里我还是给大家实现了,上代码

SList.h文件

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

#define MAX_SIZE 10
typedef int SADataType;
//创建一个结构体用来表示顺序表
typedef struct SListNode
{
	SADataType a[MAX_SIZE];//数组,用来存放数据
	int size;//已存入数据的个数
}SLNode;
//初始化顺序表
void SListInit(SLNode* ps);
//在顺序表中头插入数据
void SListPushFront(SLNode* ps,SADataType x);
//在顺序表中尾插数据
void SListPushBack(SLNode* ps, SADataType x);
//打印顺序表
void SListPrint(SLNode* ps);
//顺序表的销毁
void SListDestory(SLNode* ps);
//在顺序表中头删数据
void SListPopFront(SLNode* ps);
//在顺序表中尾删数据
void SListPopBack(SLNode* ps);
//在顺序表中查找指定的数据
SADataType SListSearch(SLNode* ps, SADataType x);
//修改这个查找到的数据
void SListModify(SLNode* ps, SADataType pos, SADataType data);
//任意位置的插入,这个任意位置指的是被查找到的位置,即pos的位置
void SListInsert(SLNode* ps, SADataType pos, SADataType x);
//任意位置的删除
void SListErase(SLNode* ps, SADataType pos);

SList.c文件

#include"SList.h"


//初始化顺序表
void SListInit(SLNode* ps)
{
	ps->size = 0;
	memset(ps->a, 0,sizeof(SADataType)* MAX_SIZE);
}
//在顺序表中头插入数据
void SListPushFront(SLNode* ps, SADataType x)
{
	//判断顺序表是否已满,如果满了,直接退出程序
	//要头插,先把数组中的数据向后挪1,然后在头部插入,所以要判断尾部是否有空余的空间
	if (ps->size >= MAX_SIZE )
	{
		printf("SList is FULL!\n");
		return;
	}
	//没有满,开始插入数据
	int i = 0;
	//向后挪
	for (i = ps->size-1; i>=0; i--)
	{
		ps->a[i+1] = ps->a[i];
	}
	//空出头,开始插入
	ps->a[0] = x;
	ps->size++;
}
//在顺序表中尾插数据
void SListPushBack(SLNode* ps, SADataType x)
{
	//判断顺序表是否已满
	if (ps->size >= MAX_SIZE)
	{
		printf("SList is FULL!\n");
		return;
	}
	//开始插入数据
	ps->a[ps->size] = x;
	ps->size++;
}
//打印顺序表
void SListPrint(SLNode* ps)
{
	if (ps->size == 0)
	{
		printf("SList is NULL!\n");
		return;
	}
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf(" %d ", ps->a[i]);
	}
	printf("\n");
}
//顺序表的销毁
void SListDestory(SLNode* ps)
{
	if (ps->size == 0)
	{
		printf("SList is NULL!\n");
		return;
	}
	//直接置为0
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		ps->a[i] = 0;
	}
	ps->size = 0;
}
//在顺序表中头删数据
void SListPopFront(SLNode* ps)
{
	//删除数组中的数据,只需要覆盖就可以,让后面的数据向前覆盖
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;

}
//在顺序表中尾删数据
void SListPopBack(SLNode* ps)
{
	//尾删,直接让size--就可以
	ps->size--;
}
//在顺序表中查找指定的数据
SADataType SListSearch(SLNode* ps, SADataType x)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;//返回它的下标位置
		}
	}
	return 0;
}
//修改这个查找到的数据
void SListModify(SLNode* ps, SADataType pos, SADataType data)
{
	//在查找到的基础上,直接替换
	ps->a[pos] = data;
}
//任意位置的插入,这个任意位置指的是被查找到的位置,即pos的位置
void SListInsert(SLNode* ps, SADataType pos, SADataType x)
{
	if (ps->size >= MAX_SIZE)
	{
		printf("SList is FULL!\n");
		return;
	}
	//先把pos后挪一个空位出来,在插入数据
	int i = 0;
	for (i = ps->size-1; i >= pos; i--)
	{
		ps->a[i + 1] = ps->a[i];
	}
	ps->a[pos] = x;
	ps->size++;

}
//任意位置的删除
void SListErase(SLNode* ps, SADataType pos)
{
	//直接向前覆盖
	int i = 0;
	for (i = pos; i < ps->size; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

test.c文件

#include"SList.h"


void Test1()
{
	SLNode s;
	SListInit(&s);
	//尾插数据
	SListPushBack(&s, 4);
	SListPushBack(&s, 5);
	SListPushBack(&s, 6);
	SListPushBack(&s, 7);
	SListPushBack(&s, 8);
	SListPushBack(&s, 9);
	SListPrint(&s);
	//头插数据
	SListPushFront(&s, 3);
	SListPushFront(&s, 2);
	SListPushFront(&s, 1);
	SListPushFront(&s, 0);
	SListPrint(&s);
	//开始查找指定数据
	SADataType pos = SListSearch(&s, 7);
	if (pos==0)
	{
		printf("NOT Find!\n");
	}
	printf("The pos is %d \n", pos);
	SListModify(&s, pos, 77);
	SListPrint(&s);
	//开始头删尾删
	SListPopBack(&s);
	SListPopBack(&s);
	SListPopFront(&s);
	SListPrint(&s);
	//在pos后插入数据
	SListInsert(&s, pos, 8);
	SListInsert(&s, pos, 9);
	SListInsert(&s, pos, 10);
	SListPrint(&s);
	SListErase(&s,pos);
	SListErase(&s, pos);
	SListPrint(&s);
	SListDestory(&s);
	printf("SList is Destory!\n");

}
int main()
{
	Test1();
	return 0;
}

结果:大家可以自己对照着结果查看

2.2动态顺序表的实现

动态顺序表相比于静态的顺序表,它更加的灵活,空间大小不受限制,容量不够就增容,一般不会造成越界,有了静态表的基础,动态顺序表也直接上代码

SeqList.h文件

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int AnyDataT;//对它进行类型重定义,后续想更换别的类型也很方便

//创建一个结构体,用来存放顺序表的相关信息
typedef struct seqList
{
	AnyDataT* a;//写成指针,可以动态开辟内存,数组不可以,数组是静态的
	int size;//顺序表中总共的数据
	int capacity;//空间容量
}SL;

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

//检查容量,如果容量不够,我们动态开辟一块空间
void SeqListCheckCapacity(SL* ps);

//打印顺序表
void SeqListPrint(SL* ps);

//在顺序表头部插入一个数据
void seqListPushFront(SL* ps, AnyDataT x);

//在顺序表尾部插入一个数据
void seqListPushBack(SL* ps, AnyDataT x);

//删除顺序表头部的数据
void seqListPopFront(SL* ps);

//删除顺序表尾部的数据
void seqListPopBack(SL* ps);

//随机位置插入一个数据
void ranInsertSeqList(SL* ps,int pos,AnyDataT x);

//随机删除一个数据
void rDestorySeqList(SL* ps, int pos);

//查找顺序表中的数据
int seqListFind(SL* ps, AnyDataT x);
//修改顺序表中某一个位置的数据
//void modifySeqList(SL* ps, AnyDataT* x);
void modifySeqList(SL* ps, int pos, AnyDataT x);
//销毁顺序表
void destorySeqList(SL* ps);

SeqList.c文件

#include"SeqList.h"

//初始化顺序表
void InitSeqList(SL* ps)
{
	ps->a = NULL;//初始化指针置为空
	ps->size = 0;
	ps->capacity = 0;//初始化空间为0,后续我们动态开辟
}
//检查容量,如果容量不够,我们动态开辟一块空间
void SeqListCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * (ps->capacity);
		AnyDataT* tmp = (AnyDataT*)realloc(ps->a, sizeof(AnyDataT) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
}
//打印顺序表
void SeqListPrint(SL* ps)
{
	assert(ps->size > 0);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
//在顺序表头部插入一个数据
void seqListPushFront(SL* ps, AnyDataT x)
{
	SeqListCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}
//在顺序表尾部插入一个数据
void seqListPushBack(SL* ps, AnyDataT x)
{
	SeqListCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}
//删除顺序表头部的数据
void seqListPopFront(SL* ps)
{
	//先判断顺序表是否为空,为空则无法删除数据,我们直接用断言
	assert(ps->size > 0);
	int start = 1;//直接从下标1开始前挪
	while (start < ps->size)
	{
		ps->a[start-1] = ps->a[start];
		start++;
	}
	ps->size--;
}
//删除顺序表尾部的数据
void seqListPopBack(SL* ps)
{
	assert(ps->size > 0);
	ps->size--;
}
//随机位置插入一个数据,pos指下标
void ranInsertSeqList(SL* ps, int pos, AnyDataT x)
{
	assert(pos < ps->size);
	SeqListCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}
//随机删除一个数据
void rDestorySeqList(SL* ps, int pos)
{
	assert(pos < ps->size);
	int start = pos + 1;
	while (start < ps->size)
	{
		ps->a[start - 1] = ps->a[start];
		start++;
	}

	ps->size--;
}
//销毁顺序表
void destorySeqList(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}
//查找顺序表中的数据,我们诶个遍历
int seqListFind(SL* ps, AnyDataT x)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
			return ps->a[i];
	}
	printf("没有这个数据\n");
	return 0;
}


void modifySeqList(SL* ps, int pos, AnyDataT x)
{
	assert(pos < ps->size);
	ps->a[pos] = x;
}

test.c文件

#include"SeqList.h"

//实现动态顺序表,
//我们实现的顺序表,一次都只插入一个数据,若要插入多个,还需仔细分析容量问题

//加入枚举,给Switch case语句添加一个提示
enum SeqList
{
	ExitSeqlist,
	SeqListPushFront,
	SeqListPushBack,
	SeqListPopFront,
	SeqListPopBack,
	RanInsertSeqList,
	RanDestorySeqList,
	ModifySeqList,
	DestorySeqList,
	SeqListFind,
};


void menu()
{
	printf("******************************************************\n");
	printf("********          1.SeqListPushFront           *******\n");
	printf("********          2.SeqListPushBack            *******\n");
	printf("********          3.SeqListPopFront            *******\n");
	printf("********          4.SeqListPopBack             *******\n");
	printf("********          5.RanInsertSeqList           *******\n");
	printf("********          6.RanDestorySeqList          *******\n");
	printf("********          7.ModifySeqList              *******\n");
	printf("********          8.DestorySeqList             *******\n");
	printf("********          9.SeqListFind                *******\n");
	printf("********          0.ExitSeqlist                *******\n");
	printf("******************************************************\n");
}

int main()
{
	int input = 0;
	SL s;//创建一个结构体变量
	AnyDataT x = 0;
	int pos = 0;
    InitSeqList(&s);//初始化结构体

	do
	{
		menu();
		printf("请输入你要选择的操作:>");
		scanf("%d", &input);
		switch (input)
		{
		case SeqListPushFront:
			printf("输入你要在头部插入的数字:>");
			scanf("%d", &x);
			seqListPushFront(&s, x);
			SeqListPrint(&s);
			break;
		case SeqListPushBack:
			printf("输入你要在尾部插入的数字:>");
			scanf("%d", &x);
		    seqListPushBack(&s, x);
			SeqListPrint(&s);
			break;
		case SeqListPopFront:
			 seqListPopFront(&s);
			 SeqListPrint(&s);
			break;
		case SeqListPopBack:
			seqListPopBack(&s);
			SeqListPrint(&s);
			break;
		case RanInsertSeqList:
			printf("请输入要插入的下标位置和数据:>");
			scanf("%d%d", &pos, &x);
			ranInsertSeqList(&s, pos, x);
			SeqListPrint(&s);
			break;
		case RanDestorySeqList:
			printf("请输入要删除数据的下标位置:>");
			scanf("%d", &pos);
			rDestorySeqList(&s,pos);
			SeqListPrint(&s);
			break;
		case ModifySeqList:
			printf("请输入要修改位置的下标和修改后的数据:>");
			scanf("%d%d", &pos, &x);
			modifySeqList(&s,pos,x);
			SeqListPrint(&s);
			break;
		case DestorySeqList:
			destorySeqList(&s);
			printf("顺序表已销毁\n");
			break;
		case SeqListFind:
			printf("请输入要查找的数据:>");
			scanf("%d", &x);
			int data=seqListFind(&s, x);
			printf("找到了%d这个数据\n", data);
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

结果:大家可以自己往里输入,我在这里做了一个简易的菜单呢,但在之后的链表实现中,为了测试方便,不会做菜单了,只做测试用例。


这就是我们这篇博客的所有内容了,下篇博客会带大家了解链表。

相信大家的品读,我们下期再见!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月亮夹馍干

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值