顺序表详解

一、顺序表的定义

二、顺序表的编写

1. 顺序表的初始化和删除

2.顺序表的打印

3.顺序表的增删

4.顺序表的查改

三、顺序表的总代码

一、顺序表的定义

       顺序表是线性表的一种,它是用一段物理地址连续的存储单元依次存储数据元素的线性结构,顺序表的底层逻辑其实是数组,所以顺序表一般用数组存储,并且是在数组上完成增删查改。

顺序表分为静态顺序表和动态顺序表,静态顺序表里面的元素个数是固定的,如果元素个数给小了会导致其余数据丢失,如果元素个数给大了会导致过剩,浪费空间,而动态顺序表就很好的解决了这个问题。

首先我们思考一个顺序表,它的底层结构是数组,所以说我们肯定要定义一个数组,其次我们还需要定义一个size来表示顺序表中有效的数字个数,另外还需要一个capacity来表示顺序表容量空间的大小,这时候我们就需要一个结构体,将这三个包含起来。

现在我们来尝试写代码,首先定义一个头文件seq.h,它的作用是表达顺序表的结构以及声明顺序表的方法;接着还要一个源文件seq.c,它的作用是实现顺序表的方法,另外一个源文件是test.c,它用来测试我们的代码,我们可以将所有的预处理指令放在seq.h里面,这样子的话两个源文件只需要引用 

#include “seq.h”

现在我们在头文件里面表达顺序表的结构

我们发现这个代码是不完美的,首先我们可以将结构体重命名,利用typedef将它重命名为SL,这样子更方便使用;其次,我们发现这个顺序表只能用于int结构,所以说我们可以将int结构也使用typedef重命名,这样子就不再局限于int,改进代码如下:

二、顺序表的编写

1. 顺序表的初始化和删除

我们要初始顺序表,可以自己编写一个函数,SLInit,那我们要将顺序表传入这个函数,那么要使用传址调用,因为如果使用传值调用,函数调用完之后,形参会被释放,返回主函数之后,我们发现顺序表没有变化,因此要用传址调用。

初始化将这些置为空和0,注意这里是传地址,所以结构体调用不能用.符号,要用-> 

下一步我们进行顺序表的销毁,使用SLDestroy函数:

注意:这里首先判断arr空间是否为空,如果不是,要先用free函数free掉。

2.顺序表的打印

顺序表的打印很简答,只需要遍历函数,并且这里没有修改数据,所以并不需要使用传址调用,我们使用SLPrint函数:

3.顺序表的增删

顺序表的增加有头插和尾插,删除同样也有头删和尾删

我们先来写头插和尾差,尾插相对容易一点,但是我们需要一个前置函数checkcapacity,我们如果判断size==capacity,那就代表没有空间了,就需要扩容,那就让capacity*2,但是一开始size和capacity都是0,所以我们要判断,如果一开始是0,就给他4的空间,否则就让capacity*2,这里可以使用三目操作符,另外扩容是额外开辟空间,所以用realloc,具体代码如下:

前置函数完成,现在开始对顺序表进行尾插和头插:

顺序表的插入完成以后,我们来实现顺序表的头删和尾删

尾删很简单,直接让size--就好了,头删稍微复杂一点,需要让第二位开始每一个元素往前移一位:

头删如下:

4.顺序表在指定位置的查改

这里主要使用三个函数,SLInsert用于在指定位置插入数据,所以要调用顺序表,给定位置pos,插入的数据x;SLErase用于删去指定位置的数据SLFind用于找到指定位置的数据。

首先是SLInsert函数:

SLErase函数:

SLFind函数:

这里我们要在test.c文件里写一下代码接受一下SLFind函数的返回值:

三、顺序表的总代码

1.seq.h

#pragma once

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLdata;
typedef struct seqlist
{
	SLdata* arr;
	int size;
	int capacity;
}SL;

void SLInit(SL * ps);
void SLDestroy(SL* ps);
void SLPushBack(SL* ps, SLdata x);
void SLPushFront(SL* ps, SLdata x);
void SLprint(SL s);
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
void SLInsert(SL* ps, int pos, SLdata x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLdata x);

2.seq.c 

#include"seq.h"

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 SLPrint(SL s)
{
	for (int i = 0;i < s.size;i++)
	{
		printf("%d ", s.arr[i]);
	}
	printf("\n");
}

void checkcapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity = 0 ? 4 : 2 * ps->capacity;
		//三目操作符来扩容空间,为了防止代码错误,先使用newcapacity接收
		SLdata* tmp = (SLdata*)realloc(ps->arr, newcapacity * sizeof(SLdata));
		//这里使用临时变量tmp来接受扩容后的数组,进行验证再赋值给ps->arr
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		else
		{
			//验证完毕没有问题,进行赋值
			ps->arr = tmp;
			ps->capacity = newcapacity;
		}
		
	}
}

void SLPushBack(SL* ps, SLdata x)
{
	assert(ps);
	//断言防止顺序表为空或者非法输入
	checkcapacity(ps);
	//给顺序表扩容
	ps->arr[ps->size++] = x;
	//将x插在顺序表尾部,记得要让ps->size++
}

void SLPushFront(SL* ps, SLdata x)
{
	assert(ps);
	//断言防止顺序表为空或者非法输入
	checkcapacity(ps);
	//给顺序表扩容
	for (int i = ps->size;i > 0;i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	//将x插在顺序表头部,利用循环让每一个元素往后移一位
	ps->arr[0] = x;
	ps->size++;
	//记得要让ps->size++
}

void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	//检测顺序表是否为空
	ps->size--;
	//将最后一个位置的元素删掉
}

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--;
	//删掉一个元素,size减少1
}

3.test.c 

#include "seq.h"


void test01()
{
	SL s1;
	SLInit(&s1);
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushBack(&s1, 5);
	SLprint(s1);
	int find = SLFind(&s1, 4);
	if (find < 0)
	{
		printf("没有找到\n");
	}
	else
	{
		printf("找到了,下标是%d\n", find);
	}
	SLDestroy(&s1);
}

int main()
{
	test01();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值