嘿嘿,家人们,今天咱们来详细剖析数据结构中的顺序表,好啦,废话不多讲,开干!
目录
1:线性表
- 线性表是n个具有相同特性的数据元素的有限序列,线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串等等.
线性表在 逻辑上是线性结构 ,也就说是连续的一条直线。但是在 物理结构上并不一定是连续 的,线性表在物理上存储时,通常以数组和链式结构的形式存储

2:顺序表
2.1:概念以及结构
顺序表是用一段 物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储.在数组上完成数据的增删查改.
顺序表一般可以分为如下结构:
2.1.1:静态顺序表
静态顺序表的特点在于使用定长数组存储元素.
缺点:空间给少了不够⽤,给多了造成空间浪费.
#define N 7
//进行函数与结构体的声明
typedef int SLDataType;
//定义顺序表的结构
typedef struct SeqList
{
//存储数据
SLDataType array[N];
//记录有效数据
int size;
}SeqList;
2.1.2:动态顺序表
动态顺序表的特点在于使用动态开辟的数组进行存储.
2.2:接口实现
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致 N 定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,因此下面我们实现动态顺序表.
2.2.1:Sequence_List.h
我们在Sequence_List.h 这一头文件里面完成以下工作
- 顺序表的定义.
- 相关的函数接口的声明.
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
//进行函数与结构体的声明
typedef int SLDataType;
//定义顺序表的结构
typedef struct SeqList
{
//存储数据
int* array;
//记录有效数据
int size;
//记录容量
int capacity;
}SeqList;
//顺序表初始化
void SeqInit(SeqList* ps);
//检查容量
void SeqCheckcapacity(SeqList* ps);
//尾插入数据
void SeqPushback(SeqList* ps, SLDataType value);
//头插入数据
void SeqPushfront(SeqList* ps, SLDataType value);
//任意位置下标的插入
void SeqInsertPos(SeqList* ps, int position, SLDataType value);
//打印顺讯表
void SeqPrint(SeqList* ps);
//尾删数据
void SeqPopback(SeqList* ps);
//头删数据
void SeqPopfront(SeqList* ps);
//任意位置数据的删除
void SeqErasePos(SeqList* ps, int position);
//查找元素
int SeqFindelement(SeqList* ps, SLDataType value);
//销毁顺序表
void SeqDestory(SeqList* ps);
2.2.2:Sequence_List.c
2.2.2.1:初始化顺序表
第一步首先是初始化顺序表.
void SeqInit(SeqList * ps)
{
//防止空指针与野指针的传递
assert(ps);
ps->array = NULL;
ps->capacity = 0;
ps->size = 0;
}
2.2.2.2:检查容量
我们实现的是一个动态增长的顺序表,那么因此就需要就要检查容量,容量不够则需要进行扩容.
void SeqCheckcapacity(SeqList * ps)
{
assert(ps);
//有效数据等于容量则进行扩容
if(ps->size == ps->capacity)
{
//若为0则将其初始容量为4,反之则进行二倍扩容
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//使用realloc进行扩容;如果为空指针,就等价于malloc(sizeof(SeqList) * newcapcity);防止扩容失败将原地址覆盖
SLDataType* temp = (SLDataType*)realloc(ps->array, sizeof(SLDataType) * newcapacity);
if(temp == NULL)
{
perror("realloc fail\n");
exit(1);
}
ps->array = temp;
ps->capacity = newcapacity;
printf("扩容成功\n");
}
}
2.2.2.3:头插与尾插数据
那么接下来我们就要去实现数据的插入了,首先是头插数据与尾插数据.
- 在插入数据前,我们首先得检查其空间容量是否足够.
- 头插数据的话,那么我们就得将已有的数据向后挪动.
- 尾插数据的话,直接在尾部插入即可.
//头插入数据
void SeqPushfront(SeqList* ps, SLDataType value)
{
assert(ps);
//插入数据前检查容量
SeqCheckcapacity(ps);
for(int i = ps->size - 1; i >=0 ; i--)
{
//进行挪动数据
ps->array[i + 1] = ps->array[i];
}
ps->array[0] = value;
ps->size++;
}
void SeqPushback(SeqList* ps, SLDataType value)
{
assert(ps);
//插入数据前检查容量
SeqCheckcapacity(ps);
//数组下标从0开始
ps->array[ps->size] = value;
ps->size++;
}
2.2.2.4:头删与尾删数据
那么接下来我们就要去实现数据的删除了,首先是头删数据与尾删数据.
- 在删除数据前,我们首先得检查里面是否有数据即有效数据不为0.
- 头删数据的话,那么我们就得将已有的数据向前挪动进行覆盖即可.
- 尾删数据的话,直接在尾部删除即可.
//头删数据
void SeqPopfront(SeqList* ps)
{
assert(ps);
//确保有效数据不为0
assert(ps->size);
for (int i = 0; i < ps->size - 1; i++)
{
ps->array[i] = ps->array[i + 1];
}
ps->size--;
}
//尾删数据
void SeqPopback(SeqList* ps)
{
assert(ps);
//确保有效数据不为0
assert(ps->size);
//有效数据 - 1即可达到尾删的效果
ps->size--;
}
2.2.2.5:任意位置的插入数据
//任意位置下标的插入
void SeqInsertPos(SeqList* ps, int position, SLDataType value)
{
assert(ps);
//确保插入的位置是有效的
assert(position >= 1 && position <= ps->size + 1);
SeqCheckcapacity(ps);
for(int i = ps->size - 1; i >= position - 1; i--)
{
//从后往前挪动覆盖
ps->array[i + 1] = ps->array[i];
}
//插入数据
ps->array[position - 1] = value;
ps->size++;
}
2.2.2.6:任意位置的删除
//任意位置数据的删除
void SeqErasePos(SeqList* ps, int position)
{
assert(ps);
//确保插入的位置是有效的
assert(position >= 1 && position <= ps->size + 1);
for(int i = position - 1; i < ps->size - 1; i++)
{
//从前向后挪动覆盖
ps->array[i] = ps->array[i + 1];
}
ps->size--;
}
//查找元素
int SeqFindelement(SeqList* ps, SLDataType value)
{
assert(ps);
for(int i = 0; i < ps->size; i++)
{
if (ps->array[i] == value)
return i + 1;
}
return 0;
}
//销毁顺序表
void SeqDestory(SeqList* ps)
{
assert(ps);
free(ps->array);
ps->array = NULL;
ps->size = 0;
ps->capacity = 0;
}
2.2.2.7:查找元素与销毁顺序表
2.2.3:Test.c
2.2.3.1:测试初始化与扩容
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"
void TestInitAndCheckCapcity(SeqList * ps)
{
SeqInit(ps);
SeqCheckcapacity(ps);
}
int main()
{
SeqList s1;
TestInitAndCheckCapcity(&s1);
return 0;
}
2.2.3.2:测试头插与尾插
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"
void TestPushFrontAndPushBack(SeqList* ps)
{
SeqInit(ps);
//尾插数据后
SeqPushback(ps,5);
SeqPushback(ps,6);
SeqPushback(ps,7);
SeqPrint(ps);
//头插数据后
SeqPushfront(ps, 4);
SeqPushfront(ps, 3);
SeqPushfront(ps, 2);
SeqPrint(ps);
}
int main()
{
SeqList s1;
TestPushFrontAndPushBack(&s1);
return 0;
}
2.2.3.3:测试头删与尾删
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"
void TestPopFrontAndPopBack(SeqList* ps)
{
SeqInit(ps);
//尾插数据后
SeqPushback(ps, 5);
SeqPushback(ps, 6);
SeqPushback(ps, 7);
SeqPrint(ps);
//头插数据后
SeqPushfront(ps, 4);
SeqPushfront(ps, 3);
SeqPushfront(ps, 2);
SeqPrint(ps);
//头删数据后
printf("头删数据后\n");
SeqPopfront(ps);
SeqPopfront(ps);
SeqPrint(ps);
//尾删数据后
printf("尾删数据后\n");
SeqPopback(ps);
SeqPopback(ps);
SeqPrint(ps);
}
int main()
{
SeqList s1;
TestPopFrontAndPopBack(&s1);
return 0;
}
2.2.3.4:测试任意位置的插入
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"
void TestInsertPos(SeqList* ps)
{
SeqInit(ps);
//尾插数据后
SeqPushback(ps, 5);
SeqPushback(ps, 6);
SeqPushback(ps, 7);
SeqPrint(ps);
//头插数据后
SeqPushfront(ps, 4);
SeqPushfront(ps, 3);
SeqPushfront(ps, 2);
SeqPrint(ps);
//在第三个位置插入,即在下标为2的位置插入
SeqInsertPos(ps, 3, 8);
SeqInsertPos(ps, 5, 9);
SeqInsertPos(ps, 9, 25);
SeqPrint(ps);
}
int main()
{
SeqList s1;
TestInsertPos(&s1);
return 0;
}
2.2.3.5:测试任意位置的删除
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"
void TestErasePos(SeqList * ps)
{
SeqInit(ps);
//尾插数据后
SeqPushback(ps, 5);
SeqPushback(ps, 6);
SeqPushback(ps, 7);
SeqPrint(ps);
//在第三个位置插入,即在下标为2的位置插入
SeqInsertPos(ps, 4, 8);
SeqInsertPos(ps, 5, 9);
SeqInsertPos(ps, 6, 25);
SeqPrint(ps);
SeqErasePos(ps, 6);
SeqErasePos(ps, 4);
SeqErasePos(ps, 1);
SeqPrint(ps);
}
int main()
{
SeqList s1;
TestErasePos(&s1);
return 0;
}
2.2.3.6:测试查找与销毁
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"
void TestDestoryAndFind(SeqList * ps)
{
SeqInit(ps);
//尾插数据后
SeqPushback(ps, 5);
SeqPushback(ps, 6);
SeqPushback(ps, 7);
SeqPrint(ps);
//在第三个位置插入,即在下标为2的位置插入
SeqInsertPos(ps, 4, 8);
SeqInsertPos(ps, 5, 9);
SeqInsertPos(ps, 6, 25);
SeqPrint(ps);
printf("找到了,在第%d个位置\n", SeqFindelement(ps,25));
printf("找到了,在第%d个位置\n", SeqFindelement(ps,5));
SeqDestory(ps);
SeqPrint(ps);
}
int main()
{
SeqList s1;
TestDestoryAndFind(&s1);
return 0;
}
3:总代码
3.1:Sequence_List.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
//进行函数与结构体的声明
typedef int SLDataType;
//定义顺序表的结构
typedef struct SeqList
{
//存储数据
int* array;
//记录有效数据
int size;
//记录容量
int capacity;
}SeqList;
//顺序表初始化
void SeqInit(SeqList* ps);
//检查容量
void SeqCheckcapacity(SeqList* ps);
//尾插入数据
void SeqPushback(SeqList* ps, SLDataType value);
//头插入数据
void SeqPushfront(SeqList* ps, SLDataType value);
//任意位置下标的插入
void SeqInsertPos(SeqList* ps, int position, SLDataType value);
//打印顺讯表
void SeqPrint(SeqList* ps);
//尾删数据
void SeqPopback(SeqList* ps);
//头删数据
void SeqPopfront(SeqList* ps);
//任意位置数据的删除
void SeqErasePos(SeqList* ps, int position);
//查找元素
int SeqFindelement(SeqList* ps, SLDataType value);
//销毁顺序表
void SeqDestory(SeqList* ps);
3.2:Sequence_List.c
#define _CRT_SECURE_NO_WARNINGS
#include "Sequence_list.h"
//初始化顺序表
void SeqInit(SeqList* ps)
{
assert(ps);
ps->array = NULL;
ps->capcity = 0;
ps->size = 0;
}
//检查容量
void SeqCheckcapcity(SeqList * ps)
{
assert(ps);
//有效数据等于容量,进行扩容
if (ps->size == ps->capcity)
{
int newcapcity = ps->capcity == 0 ? 4 : ps->capcity * 2;
//使用realloc进行扩容;如果为空指针,就等价于malloc(sizeof(SeqList) * newcapcity);防止扩容失败将原地址覆盖
SLDataType * tmp = (SLDataType *)realloc(ps->array, sizeof(SLDataType) * newcapcity);
if (tmp == NULL)
{
perror("realloc");
return;
}
ps->array = tmp;
ps->capcity = newcapcity;
printf("扩容成功\n");
}
}
//顺序表打印
void SeqPrint(SeqList * ps)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->array[i]);
}
printf("\n");
}
//头插数据
void SeqPushfront(SeqList* ps, SLDataType value)
{
assert(ps);
//插入前检查容量
SeqCheckcapcity(ps);
//数据从后向前挪动
for (int i = ps->size - 1; i >= 0; i--)
{
ps->array[i + 1] = ps->array[i];
}
ps->array[0] = value;
ps->size++;
}
//尾插数据
void SeqPushback(SeqList* ps, SLDataType value)
{
assert(ps);
//插入前检查容量
SeqCheckcapcity(ps);
ps->array[ps->size] = value;
ps->size++;
}
//任意下标位置的插入
void SeqInsertPos(SeqList* ps, int position, SLDataType value)
{
assert(ps);
//确保正确插入
assert(position >= 1 && position <= ps->size + 1);
SeqCheckcapcity(ps);
for (int i = ps-> size - 1 ; i >= position - 1; i--)
{
ps->array[i + 1] = ps->array[i];
}
ps->array[position - 1] = value;
ps->size++;
}
//尾删数据
void SeqPopback(SeqList* ps)
{
assert(ps);
//删除前确保有效数据不为0
assert(ps->size);
ps->size--;
}
//头删数据
void SeqPopfront(SeqList* ps)
{
assert(ps);
//确保有效数据不为0
assert(ps->size);
for (int i = 0; i < ps->size; i++)
{
ps->array[i] = ps->array[i + 1];
}
ps->size--;
}
//任意位置的删除
void SeqErasePos(SeqList* ps,int position)
{
assert(ps);
assert(position >= 1 && position <= ps->size + 1);
for (int i = position - 1; i < ps->size; i++)
{
//从后往前挪动覆盖
ps->array[i] = ps->array[i + 1];
}
ps->size--;
}
int SeqFindelement(SeqList* ps, SLDataType value)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
if(value == ps->array[i])
{
return (i + 1);
}
}
return 0;
}
//销毁顺序表
void SeqDestory(SeqList* ps)
{
//不为空则进行销毁
assert(ps);
free(ps->array);
ps->array = NULL;
ps->capcity = 0;
ps->size = 0;
}
3.3:Test.c
#define _CRT_SECURE_NO_WARNINGS
#include "Sequence_list.h"
//测试尾插与头插与打印
void test1(SeqList * ps)
{
//初始化
SeqInit(ps);
//尾插
SeqPushback(ps, 1);
SeqPushback(ps, 2);
SeqPushback(ps, 3);
SeqPushback(ps, 4);
SeqPushback(ps, 5);
printf("尾插之后:>");
SeqPrint(ps);
//头插
SeqPushfront(ps, 40);
SeqPushfront(ps, 30);
SeqPushfront(ps, 20);
SeqPushfront(ps, 10);
printf("头插之后:>");
SeqPrint(ps);
}
//测试尾删与头删
void test2(SeqList* ps)
{
//尾删
SeqPopback(ps);
SeqPopback(ps);
SeqPopback(ps);
printf("尾删之后:>");
SeqPrint(ps);
//头删
SeqPopfront(ps);
SeqPopfront(ps);
printf("头删之后:>");
SeqPrint(ps);
}
//测试任意位置的插入与删除
void test3(SeqList * ps)
{
SeqInsertPos(ps, 1, 20);
printf("在第1个位置插入之后:>");
SeqPrint(ps);
SeqInsertPos(ps, 4, 3);
printf("在第4个位置插入之后:>");
SeqPrint(ps);
SeqInsertPos(ps, 5, 4);
printf("在第5个位置插入之后:>");
SeqPrint(ps);
SeqInsertPos(ps, 6, 5);
printf("在第6个位置插入之后:>");
SeqPrint(ps);
SeqErasePos(ps, 3);
printf("删除第3个位置的元素之后:>");
SeqPrint(ps);
SeqErasePos(ps, 7);
printf("删除第7个位置的元素之后:>");
SeqPrint(ps);
}
test4(SeqList * ps)
{
int result = SeqFindelement(ps, 20);
if (result)
{
printf("在第%d个位置\n", result);
}
else
{
printf("无法找到\n");
}
}
int main()
{
SeqList s1;
test1(&s1);
test2(&s1);
test3(&s1);
test4(&s1);
//销毁顺序表
SeqDestory(&s1);
}
好啦,uu们,数据结构顺表表这部分滴详细内容博主就讲到这里啦,如果uu们觉得博主讲的不错的话,请动动你们滴小手给博主点点赞,你们滴鼓励将成为博主源源不断滴动力,同时也欢迎大家来指正博主滴错误~