顺序表C语言

一、什么是顺序表

        顺序表是线性表的一种,线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。顺序表的底层是数组,顺序表在数组的基础上提供了增删查改等方法。顺序表的物理结构是连续的(顺序表底层是数组,数组的物理结构是连续的),逻辑结构也是连续的。

二、顺序表的分类

        顺序表分为静态顺序表和动态顺序表。静态顺序表的底层是定长数组,动态顺序表底层是动态开辟的数组。

静态顺序表:

动态顺序表:

       静态顺序表与动态顺序表相比,有不足的地方。静态顺序表的底层是定长数组,当空间给小了会不够用,当空间给大了就会造成空间浪费。而动态顺序表的空间是动态开辟的,可以根据需求调整空间大小。

三、动态顺序表的实现

        动态顺序表的实现主要需要2个文件,一个是头文件,一个是源文件,头文件用来实现动态顺序表的结构和声明增删查改等方法,源文件负责实现增删查改等方法。头文件的作用相当于一本书的目录,查看头文件可以知道我们在源文件实现了什么方法,以及查找源文件中对应的方法。

动态顺序表的头文件:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int SLDataType;

//实现动态顺序表的结构
typedef struct SeqList
{
	SLDataType* arr;
	int size;//记录当前顺序表有效的数据个数
	int capacity;//记录顺序表的空间大小
}SL;

//顺序表初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLDestroy(SL* ps);
//顺序表的打印
void SLPrint(SL s);

//头部插入删除/尾部插入删除
void SLPushBack(SL* ps, SLDataType x);//向顺序表ps里面插入一个SLDataType类型的数据x
void SLPushFront(SL* ps, SLDataType x);

void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//指定位置之前插入/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

动态顺序表的源文件:

#include"SeqList.h"

void SLPrint(SL s)
{
	for (int i = 0; i < s.size; i++)
	{
		printf("%d ", s.arr[i]);
	}
    printf("\n");
}

void SLCheckCapacity(SL * ps)
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//三目表达式
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);//直接退出程序,不再继续执行
		}
		//空间申请成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

void SLInit(SL* ps)
{
	ps->arr = NULL;//底层数组初始情况下没有任何数据,置为空
	ps->size = ps->capacity = 0;
}

void SLDestroy(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//顺序表的尾插
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);//顺序表传过来不能为空
	//插入数据要判断顺序表有没有空间以及空间够不够
	SLCheckCapacity(ps);
	//插入数据
	ps->arr[ps->size] = x;
	++ps->size;
}

//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > 0; i--)//头插要使原来数组的元素整体向后移动一个位置,空出第一个位置再插入元素
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	++ps->size;
	
}

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);//判断顺序表是否为空
	ps->size--;
}

//头删
//头删要使顺序表首元素之后的所有元素整体向前移动一个位置,再调整顺序表的有效数据个数。删除一个元素,顺序表的有效数据个数-1
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

//指定位置之前插入/删除数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);//插入的数据的位置的下标不能小于等于0,也不能越界

	SLCheckCapacity(ps);
//把下标为pos以及之后的所有元素整体向后移动一个位置,空出下标为pos的位置,再在指定位置插入数据
	for (int i = ps->size ; i > pos ; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	//把下标为pos之后的所有元素整体向前挪动一个位置
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;//找到该元素,返回对应的下标
		}
	}
//找不到,返回一个无效的下标
	return -1;
}

 以上是关于顺序表的一些内容,如有不对,欢迎指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值