顺序表专题

一、顺序表的概念及结构

(一)线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

案例:蔬菜分为绿叶类、瓜类、菌菇类。线性表指的是具有部分相同特性的一类数据结构的集合。

如何理解逻辑结构和物理结构?

二、顺序表分类

(一)顺序表和数组的区别

顺序表的底层结构是数组,对数组的封装,实现了常用的增删查改等接口。

(二)顺序表分类

1.静态顺序表

概念:使用定长数组储存元素

静态顺序表缺陷:空间给少了不够用,给多了造成空间浪费。

2.动态顺序表

可以按需申请空间,可增容。

三、顺序表的实现

(一)头文件与源文件的创建

1.Seqlish.h

首先,我们要创建一个头文件Seqlist.h。在这个头文件里面,我们主要来实现函数的声明,把所有的头文件和函数集中到同一个头文件中。

2.Seqlist.c

然后,我们需要创建一个源文件Seqlist.h。在这个源文件里面,我们主要来实现顺序表函数的定义。

3.test.c

最后,我们还应该创建一个源文件test.c。在这个源文件里面,我们主要来实现顺序表的测试。

(二)定义顺序表的结构

我们先在Seqlist.h的头文件中:

cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>



typedef int SLDataType;//对整型重命名
//动态顺序表
typedef struct SeqList
{
	SLDataType* arr;
	SLDataType size;//有效数据的个数
	SLDataType capacity;//空间大小
}SL;

(三)顺序表的初始化

在Seqlist.c的源文件中:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.h"



//顺序表的初始化
void SLInit(SL* ps)
{	
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

在Seqlist.h的头文件中:

cpp 复制代码
//顺序表初始化
void SLInit(SL* ps);

在test.c的源文件中:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.h"

void SLTest01()
{
	SL sl;
	SLInit(&sl);
}

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

(四)顺序表的销毁

在Seqlist.c的源文件中:

cpp 复制代码
//顺序表的销毁
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");
}

在Seqlist.h的头文件中:

cpp 复制代码
void SLPrint(SL ps);//顺序表的打印
void SLDestroy(SL* ps);//顺序表的销毁

在test.c的源文件中:

cpp 复制代码
void SLTest01()
{
	SL sl;
	SLInit(&sl);
	SLDestroy(&sl);
}

(五)头插的实现

在Seqlist.c的源文件中:

cpp 复制代码
void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		//申请空间
		//三目表达式
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//空间申请成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

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];//arr[1]=arr[0];
	}
	ps->arr[0] = x;
	ps->size++;
}

在Seqlist.h的头文件中:

cpp 复制代码
void SLPushFront(SL* ps, SLDataType x);

在test.c的源文件中:

cpp 复制代码
void SLTest01()
{
	SL sl;
	SLInit(&sl);
    //测试头插
    SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	SLDestroy(&sl);
}

(六)尾插的实现

在Seqlist.c的源文件中:

cpp 复制代码
void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		//申请空间
		//三目表达式
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity*2;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//空间申请成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	/*温柔的解决条件*/
	//if (ps == NULL)
	//{
	//	return;
	assert(ps);//等价于assert(ps != NULL)
	//}
	//插入数据之前先看空间够不够
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
	/*ps->arr[ps->size] = x;
	++ps->size;*/
}

在Seqlist.h的头文件中:

cpp 复制代码
void SLPushBack(SL* ps, SLDataType x);

在test.c的源文件中:

cpp 复制代码
void SLTest01()
{
	SL sl;
	SLInit(&sl);
	//增删查改操作
	
	//测试尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl,4);
	SLDestroy(&sl);
}

(七)尾删的实现

在Seqlist.c的源文件中

cpp 复制代码
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	//ps->arr[ps->size-1] = -1;
	--ps->size;
}

在Seqlist.h的头文件中:

cpp 复制代码
void SLPopBack(SL* ps);

在test.c的源文件中:

cpp 复制代码
void SLTest01()
{
	SL sl;
	SLInit(&sl);
	//测试头删
	SLPopBack(&sl);
	SLPrint(sl);//1 2 3
	SLPopBack(&sl);
	SLPrint(sl);//1 2 
	SLPopBack(&sl);
	SLPrint(sl);//1
	SLPopBack(&sl);
	//SLPopBack(&sl);//size为0,不能继续删除;
	SLDestroy(&sl);
}

(八)头删的实现

在Seqlist.c的源文件中

cpp 复制代码
//头删
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];
		//arr[size-2] = arr[size-1]
	}
	ps->size--;
}

在Seqlist.h的头文件中:

cpp 复制代码
void SLPopFront(SL* ps);

在test.c的源文件中:

cpp 复制代码
void SLTest01()
{
	SL sl;
	SLInit(&sl);
	////测试头删
	//SLPopFront(&sl);
	//SLPrint(sl);//2 3 4
	//SLPopFront(&sl);
	//SLPrint(sl);//3 4
	SLDestroy(&sl);
}

(九)顺序表的整体实现代码

1.Seqlist.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.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 SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		//申请空间
		//三目表达式
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity*2;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//空间申请成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	/*温柔的解决条件*/
	//if (ps == NULL)
	//{
	//	return;
	assert(ps);//等价于assert(ps != NULL)
	//}
	//插入数据之前先看空间够不够
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
	/*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];//arr[1]=arr[0];
	}
	ps->arr[0] = x;
	ps->size++;
}
//顺序表的打印
void SLPrint(SL s)
{
	for (int i = 0; i < s.size; i++)
	{
		printf(" %d", s.arr[i]);
	}
	printf("\n");
}
//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	//ps->arr[ps->size-1] = -1;
	--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];
		//arr[size-2] = arr[size-1]
	}
	ps->size--;
}

2.Seqlist.h

cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//定义顺序表的结构
#define N 100
//静态顺序表
//struct SeqList
//{
//	int arr[N];
//	int size;//有效数据个数
//};

typedef int SLDataType;//对整型重命名
//动态顺序表
typedef struct SeqList
{
	SLDataType* arr;
	SLDataType size;//有效数据的个数
	SLDataType capacity;//空间大小
}SL;
//typedef struct Seqlist SL;
// 
//顺序表初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLPrint(SL ps);
void SLDestroy(SL* ps);
//头部插入删除 尾部插入删除
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

3.test.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.h"

void SLTest01()
{
	SL sl;
	SLInit(&sl);
	//增删查改操作
	
	//测试尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl,4);
	/*SLPushBack(NULL,5);*/
	SLPrint(sl);
	//SLPushFront(&sl, 5);
	//SLPushFront(&sl, 6);

	////测试头删
	//SLPopFront(&sl);
	//SLPrint(sl);//2 3 4
	//SLPopFront(&sl);
	//SLPrint(sl);//3 4

	//测试尾删
	SLPopBack(&sl);
	SLPrint(sl);//1 2 3
	SLPopBack(&sl);
	SLPrint(sl);//1 2 
	SLPopBack(&sl);
	SLPrint(sl);//1
	SLPopBack(&sl);
	//SLPopBack(&sl);//size为0,不能继续删除;
	SLDestroy(&sl);
}

int main()
{
	SLTest01();
	return 0; 
}
相关推荐
qeen8743 分钟前
【数据结构】自平衡二叉搜索树各种旋转算法原理解析及AVL树的C++实现
数据结构·c++·算法
程序员与背包客_CoderZ1 小时前
Linux D-Bus通信协议详解:从入门到C/C++编码实战
linux·服务器·c语言·c++·嵌入式硬件·嵌入式软件·dbus
冻柠檬飞冰走茶2 小时前
PTA基础编程题目集 7-35有理数均值(C++语言实现)
开发语言·数据结构·c++·算法·均值算法
嵌入式阿蔡2 小时前
HAL库 vs LL库 vs 寄存器:到底用哪个?
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
Yyyyyy~3 小时前
【C】C语言常见概念
c语言
Nil2083 小时前
leetcode 189轮转数组
数据结构·算法·leetcode
嵌入式阿蔡4 小时前
CAN总线入门:从协议帧到STM32实战
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
依然鸣4 小时前
PTA团体程序设计天梯赛L1真题讲解L1-085-088
数据结构·c++·经验分享·算法·深度优先·pat考试
Brilliantwxx5 小时前
【算法从零到千】【51-54】逆序对(分治+递归算法)
数据结构·算法·排序算法
LONGZETECH5 小时前
无人机组装调试实训高损耗痛点分析与虚拟仿真教学落地方案
c语言·开发语言·架构·无人机