顺序表基础知识

2024-01-22 21:56:34 浏览数 (1)

1. 数据结构

数据结构是由“数据”和“结构”两词组合而来。

1.1 什么是数据

常见的数值1、2、3、4…、学校保存的身份信息(姓名、性别、年龄、学历等等)、网页肉眼可以看到的信息(文字、图片、视频等等),这些都是数据。

1.2 什么是结构

当我们想要使用大量同一类型的数据时,通过手动定义大量的独立的变量对于程序来说,可读性非常差,我们可以借助数组这样的数据结构将大量的数据组织在一起,结构也可以理解为组织数据的方式。

1.3 什么是数据结构

数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么方式构成,以及数据元素之间呈现的结构。 而最基础的数据结构就是数组。

2. 顺序表

顺序表是线性表的一种,那什么是线性表呢?

2.1 什么是线性表

线性表是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻辑上线性结构,也就说是连续的⼀条直线。 但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

2.2 顺序表分类

顺序表的最底层结构是数组,所以顺序表在逻辑结构上是线性的,在物理结构上也是线性的。 了解了线性表之后,那顺序表呢? 顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口。

2.2.1 静态顺序表

使用定长数组存储元素。

代码语言:javascript复制
//静态顺序表
struct Seqlist{
   int a[100];
   int size;
}

缺点: 空间初始时给小了,造成不够用; 空间初始给大了,造成了浪费。 在实际场景中,空间不够造成数据无法保存,就可能造成数据的丢失。

2.2.2 动态顺序表
代码语言:javascript复制
//动态顺序表
struct Seqlist{
   int* a;
   int size;//有效数据个数
   int capacity;//空间大小
}

3. 代码具体实现动态顺序表

在这里用三个文件SeqList.h、SeqList.c、test.c分别实现。 在顺序表中实现多次扩容,所以用realloc可以进行容量大小的调整。 插入时都需要判断空间容量是否足够?顾可以单独定义一个函数SLCheckCapacity,用来判断容量是否足够,若不够,则扩容。

代码语言:javascript复制
void SLCheckCapacity(SL* ps) {
	if (ps->size == ps->capacity) {
		//空间不足以再额外插入一个数据
		//扩容
		int newCapcity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapcity * sizeof(SLDataType));
		if (tmp == NULL) {
			perror("realloc fail!n");
			return 1;
		}
		ps->a = tmp;
		ps->capacity = newCapcity;
	}
}

尾部插入SLPushBack

代码语言:javascript复制
//尾插
void SLPushBack(SL* ps, SLDataType x) {
	//assert(ps != NULL);
	//暴力的方式
	assert(ps);
	//柔和方式
	//if (ps == NULL) {
	//	return;
	//}

	//1)空间足够,直接尾插
	//2)空间不够,扩容
	SLCheckCapacity(ps);
	//直接插入数据
	ps->a[ps->size  ] = x;
}

头部插入SLPushFront

代码语言:javascript复制
//头插
void SLPushFront(SL* ps, SLDataType x) {
	assert(ps);
	//判断空间是否足够,不够则扩容
	SLCheckCapacity(ps);
	//空间足够,历史数据后移一位
	for (size_t i = ps->size; i > 0 ; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size  ;
}

尾部删除SLPopBack

代码语言:javascript复制
void SLPopBack(SL* ps) {
	//判断顺序表是否为空
	assert(ps);
	assert(!SLIsEmpty(ps));
	//ps->a[ps->size - 1] = 0;
	ps->size--;
}

3.1 SeqList.h

代码语言:javascript复制
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;
	int size;  //顺序表中有效的数据个数
	int capacity;  //顺序表当前的空间大小
}SL;
//typedef struct SeqList SL;

//对顺序表进行初始化
void SLInit(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);

void SLPrint(SL* ps);
bool SLIsEmpty(SL* ps);

3.2 SeqList.c

代码语言:javascript复制
#include"SeqList.h"

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

void SLCheckCapacity(SL* ps) {
	if (ps->size == ps->capacity) {
		//空间不足以再额外插入一个数据
		//扩容
		int newCapcity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapcity * sizeof(SLDataType));
		if (tmp == NULL) {
			perror("realloc fail!n");
			return 1;
		}
		ps->a = tmp;
		ps->capacity = newCapcity;
	}
}

//尾插
void SLPushBack(SL* ps, SLDataType x) {
	//assert(ps != NULL);
	//暴力的方式
	assert(ps);
	//柔和方式
	//if (ps == NULL) {
	//	return;
	//}

	//1)空间足够,直接尾插
	//2)空间不够,扩容
	SLCheckCapacity(ps);
	//直接插入数据
	ps->a[ps->size  ] = x;
}
//头插
void SLPushFront(SL* ps, SLDataType x) {
	assert(ps);
	//判断空间是否足够,不够则扩容
	SLCheckCapacity(ps);
	//空间足够,历史数据后移一位
	for (size_t i = ps->size; i > 0 ; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size  ;
}
//尾删
void SLPopBack(SL* ps) {
	//判断顺序表是否为空
	assert(ps);
	assert(!SLIsEmpty(ps));
	//ps->a[ps->size - 1] = 0;
	ps->size--;
}
//void SLPopFront(SL* ps) {

//}
void SLPrint(SL* ps) {
	for (size_t i = 0; i < ps->size; i  )
	{
		printf("%d ", ps->a[i]);
	}
	printf("n");
}
bool SLIsEmpty(SL* ps) {
	assert(ps);
	//这样子是不对的,这里只能判断空间是否足够
	//return ps->size == ps->capacity;
	return ps->size == 0;
}

3.3 测试test.c

代码语言:javascript复制
#include"SeqList.h"

void SLtest() {
	SL sl;
	SLInit(&sl);
	//顺序表的具体操作
	//SLPushBack(&sl, 1);
	//SLPushBack(&sl, 2);
	//SLPushBack(&sl, 3);
	//SLPushBack(&sl, 4);//1 2 3 4
	//SLPrint(&sl);
	头插
	//SLPushFront(&sl, 5);//5 1 2 3 4
	//SLPushFront(&sl, 6);//6 5 1 2 3 4
	//SLPushFront(&sl, 7);//7 6 5 1 2 3 4
	//SLPrint(&sl);
	//尾删
	SLPopBack(&sl);
	SLPrint(&sl);
	SLPopBack(&sl);
	SLPrint(&sl);
	SLDestroy(&sl);
}

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

0 人点赞