数据结构之顺序表
Posted 小倪同学 -_-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构之顺序表相关的知识,希望对你有一定的参考价值。
文章目录
线性表
- 线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一 种在实际中广 泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
- 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构.上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
顺序表的概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表可分为静态顺序表(使用定长数组储存元素),动态顺序表(使用动态开辟的数组存储元素)。为了提高顺序表的灵活性,我们通常使用动态顺序表。
顺序表的功能实现
首先要创建三个文件
- 创建SeqList.h表示头文件(存放函数声明)
- 创建SeqList.c表示函数文件(存放各个函数文件)
- 创建test.c表示测试文件(帮助测试函数功能)
定义顺序表
在头文件中创建如下结构体
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a; //动态数组
size_t size; //数组已存储的数量
size_t capacity; //数组的容量
}SeqList;
这里将int重命名是方便之后对顺序表中存储数据类型的修改
顺序表初始化
void SeqListInit(SeqList* ps)
{
assert(ps); //断言,防止文件传空指针,需引头文件assert.h
ps->a = NULL;
ps->capacity = ps->size = 0;
}
效果如下
修改前
修改后
顺序表打印
将数组中所有数据按顺序打印
void SeqListPrint(SeqList* ps)
{
assert(ps);
size_t i = 0;
for (i = 0; i < ps->size; i++)
{
if (i == ps->size - 1)
{
printf("%d", ps->a[i]);
}
else
{
printf("%d-->", ps->a[i]);
}
}
printf("\\n");
}
顺序表尾插
尾插前首先要检查数组是否填满,如果已经填满就要增容,然后把数据尾插,存储量加一
那么如何增容呢?
先判断数组中已存数据个数是否等于数组容量,如果等于就要进行增容
再判断该数组容量是否为0,如果为0就给它4个空间,否则增容一倍
void SeqListCheckCapcity(SeqList* ps)
{
assert(ps);
//检查是否满了,满了就增容
if (ps->size == ps->capacity)
{
size_t newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ps->a = (SLDateType*)realloc(ps->a, newcapacity*sizeof(SeqList));
if (ps->a == NULL)
{
printf("增容失败\\n");
return;
}
ps->capacity = newcapacity;
}
}
void SeqListPushBack(SeqList* ps, SLDateType x)
{
assert(ps);
SeqListCheckCapcity(ps);
ps->a[ps->size] = x;//尾插
ps->size++;//存储量+1
}
检测
该功能已实现
注意:每个函数实现后尽量测试一下,确保该功能能够实现。若是程序写完再测试不易找到错误出处
顺序表尾删
尾删就相对简单多了,只需size-1
有人会问,数据不是没删除码?
我们访问时只会访问size个数据,其后数据不会访问,变相等于删除。当插入数据时,该数据又会被新数据给覆盖,所以只需size-1
void SeqListPopBack(SeqList* ps)
{
assert(ps->size > 0); //必须保证数组中有数据
assert(ps);
ps->size--;
}
检测:
顺序表头插
思路:
- 头插和尾插一样要检测是否需要增容
- 然后将所有数据往后移动一位
- 最后再把数据插入
void SeqListPushFront(SeqList* ps, SLDateType x)
{
assert(ps);
SeqListCheckCapcity(ps);
//所有数据往后移动一位
int end = ps->size;
while (end)
{
ps->a[end] = ps->a[end-1];
end--;
}
//插入数据
ps->a[0] = x;
//存储量+1
ps->size++;
}
检测:
顺序表头删
头删是将第一位以后的数据依次往前挪一位,并将size减一
void SeqListPopFront(SeqList* ps)
{
assert(ps);
assert(ps->size > 0);
//记录最后一位数据的下标
int end = ps->size - 1;
int i = 0;
//挪位
while (end)
{
ps->a[i] = ps->a[i + 1];
end--;
i++;
}
ps->size--;
}
检测:
查找指定元素
思路:
- 遍历顺序表
- 找到返回下标,否则返回-1
int SeqListFind(SeqList* ps, SLDateType x)
{
assert(ps);
//遍历顺序表
for (size_t i = 0; i < ps->size; i++)
{
if (x == ps->a[i])
return i;//返回下标
}
return -1;
}
在指定位置插入
思路:
- 传入位置下标和要插入的数据
- 将该位置及其后数据往后挪一位
- size+1
void SeqListInsert(SeqList* ps, size_t pos, SLDateType x)
{
assert(ps);
//插入位置必须在容量内
assert(pos < ps->size);
//检查是否需要增容
SeqListCheckCapcity(ps);
int end = ps->size;
for (size_t i = end; i > pos; i--)
{
ps->a[i] = ps->a[i - 1];
}
ps->a[pos] = x;
ps->size++;
}
测试
删除指定位置
思路:
- 将指定位置以后的数据都往前挪动一位
- size-1
void SeqListErase(SeqList* ps, size_t pos)
{
assert(ps);
int end = ps->size;
//挪位
for (size_t i = pos; i < end; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->size--;
}
测试
销毁顺序表
void SeqListDestory(SeqList* ps)
{
assert(ps);
//释放空间
if (ps->a)
{
free(ps->a);
}
ps->size = ps->capacity = 0;
}
总结
SeqList.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a; //动态数组
size_t size; //数组已存储的数量
size_t capacity; //数组的容量
}SeqList;
// 对数据的管理:增删查改
void SeqListInit(SeqList* ps);
//打印
void SeqListPrint(SeqList* ps);
//尾插
void SeqListPushBack(SeqList* ps, SLDateType x);
//尾删
void SeqListPopBack(SeqList* ps);
//头插
void SeqListPushFront(SeqList* ps, SLDateType x);
//头删
void SeqListPopFront(SeqList* ps);
// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, size_t pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, size_t pos);
//销毁
void SeqListDestory(SeqList* ps);
SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
void SeqListInit(SeqList* ps)
{
assert(ps); //断言,防止文件传空指针,需引头文件assert.h
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SeqListPrint(SeqList* ps)
{
assert(ps);
size_t i = 0;
for (i = 0; i < ps->size; i++)
{
if (i == ps->size - 1)
{
printf("%d", ps->a[i]);
}
else
{
printf("%d-->", ps->a[i]);
}
}
printf("\\n");
}
void SeqListCheckCapcity(SeqList* ps)
{
assert(ps);
//检查是否满了,满了就增容
if (ps->size == ps->capacity)
{
size_t newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ps->a = (SLDateType*)realloc(ps->a, newcapacity*sizeof(SeqList));
if (ps->a == NULL)
{
printf("增容失败\\n");
return;
}
ps->capacity = newcapacity;
}
}
void SeqListPushBack(SeqList* ps, SLDateType x)
{
assert(ps);
SeqListCheckCapcity(ps);
ps->a[ps->size] = x;//尾插
ps->size++;//存储量+1
}
void SeqListPopBack(SeqList* ps)
{
assert(ps->size > 0);//必须保证数组中有数据
assert(ps);
ps->size--;
}
void SeqListPushFront(SeqList* ps, SLDateType x)
{
assert(ps);
SeqListCheckCapcity(ps);
//所有数据往后移动一位
int end = ps->size;
while (end)
{
ps->a[end] = ps->a[end-1];
end--;
}
//插入数据
ps->a[0] = x;
//存储量+1
ps->size++;
}
void SeqListPopFront(SeqList* ps)
{
assert(ps);
assert(ps->size > 0);
//记录最后一位数据的下标
int end = ps->size - 1;
int i = 0;
//挪位
while (end)
{
ps->a[i] = ps->a[i + 1];
end--;
i++;
}
ps->size--;
}
// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x)
{
assert(ps);
//遍历顺序表
for (size_t i = 0; i < ps->size; i++)
{
if (x == ps->a[i])
return i;//返回下标
}
return -1;
}
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, size_t pos, SLDateType x)
{
assert(ps);
//插入位置必须在容量内
assert(pos < ps->size);
//检查是否需要增容
SeqListCheckCapcity(ps);
int end = ps->size;
for (size_t i = end; i > pos; i--)
{
ps->a[i] = ps->a[i - 1];
}
ps->a[pos] = x;
ps->size++;
}
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, size_t pos)
{
assert(ps);
int end = ps->size;
//挪位
for (size_t i = pos; i < end; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->size--;
}
void SeqListDestory(SeqList* ps)
{
assert(ps);
if (ps->a)
{
free(ps->a);
}
ps->size = ps->capacity = 0;
}
以上是关于数据结构之顺序表的主要内容,如果未能解决你的问题,请参考以下文章