前言
- 《数据结构系列首页》是数据结构系列文章的首页,其中会逐步更新各种数据结构的实现,有兴趣的选手可以一看。
- 首页中不仅有各种数据结构的实现,还有学习数据结构必备的基础知识,如果有选手觉得自己的基础不太牢固,可以先将搞定基础知识,之后再攻克数据结构这一部分的内容。
- 由于我也是刚开始学习数据结构这门课程,所以如果发现文章中存在错误,希望大家可以直接指出,我将第一时间修改。
- 更多数据结构的实现请见《数据结构系列文章》,我会在学习完新的数据结构后不断更新其中的内容。
开场白
顺序表是线性表的一种存储方式,在正式写代码之前,先来看看顺序表的定义,顺序表是指用一组地址连续的存储单元依次存储线性表数据元素的存储结构。由于存储单元的地址要连续,故想到可以使用数组来实现顺序表,数组又分为动态数组和静态数组,本篇展示使用动态一维数组实现顺序表以及实现对顺序表的各种操作。
具体实现
头文件
#include <stdio.h> // printf、scanf函数所在的头文件
#include <stdlib.h> // exit函数所在的头文件
#include <malloc.h> // malloc、free函数所在的头文件
#include <math.h> // 宏OVERFLOW所在的头文件,OVERFLOW的值为3
// 按照严蔚敏老师书中的编程习惯,定义如下4个宏
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; // Status是函数返回值的类型,其返回的是函数执行结果的状态
typedef int ElemType; // ElemType是元素的数据类型,想要整体改变元素的数据类型只需改变ElemType前的数据类型即可
#define LIST_INIT_SIZE 10 // 动态顺序表存储空间的初始容量
#define LIST_INCREMENT 5 // 动态顺序表存储空间的增量
// 定义动态顺序表的存储结构
typedef struct SqList
{
ElemType* base; // 存储动态顺序表的第一个元素地址,即顺序表的基地址
int length; // 存储动态顺序表的当前长度
int listsize; // 存储动态顺序表的当前最大容量
}SL; // SL 等同于 struct SqList
函数声明
// 低阶操作函数
void init_list(SL&);
void destroy_list(SL&);
void clear_list(SL&);
Status is_empty(SL&);
Status is_full(SL&);
int get_length(SL&);
Status get_element(SL&, int, ElemType&);
// 初阶操作函数
Status insert_element(SL&, int, ElemType);
Status delete_element(SL&, int, ElemType&);
void traverse_list(SL&, void(*visit)(ElemType&));
int locate_element(SL&, ElemType, Status(*compare)(ElemType, ElemType));
Status get_prior_element(SL&, ElemType, ElemType&);
Status get_next_element(SL& L, ElemType cur_e, ElemType& next_e);
// 中阶操作函数
void reverse_list(SL&);
void sort_list_1(SL&);
void sort_list_2(SL&);
void union_list(SL&, SL&);
void merge_list_1(SL&, SL&, SL&);
void merge_list_2(SL&, SL&, SL&);
Status delete_minmum_element(SL&, ElemType&);
// 辅助操作函数
void print(ElemType&);
void double_element(ElemType&);
Status equal(ElemType, ElemType);
Status square(ElemType, ElemType);
操作函数的实现
- 低阶操作函数实现(7个)
// 初始化顺序表L
void init_list(SL& L)
{
L.base = (ElemType*)malloc(sizeof(ElemType) * LIST_INIT_SIZE);
// 采用动态分配的一维数组,将分配好的空间地址(第一个字节的地址)赋给表L的基地址
if (!L.base) // 如果L.base不存在,则分配失败并退出程序
exit(OVERFLOW);
L.length = 0; // 初始化时表L的长度为0
L.listsize = LIST_INIT_SIZE; // 初始化时表L的当前最大容量为LIST_INIT_SIZE
}
// 销毁顺序表L
void destroy_list(SL& L)
{
free(L.base); // 释放表L基地址对应的动态存储空间
L.base = NULL; // 将表L的基地址置为空
L.length = 0; // 将表L的当前长度置为0
L.listsize = 0; // 将表L的当前最大容量置为0
}
// 清空顺序表L中的所有元素
void clear_list(SL& L)
{
L.length = 0; // 仅需将表L的当前长度置为0即可
}
// 判断顺序表L是否为空
Status is_empty(SL& L)
{
if (L.length == 0) // 如果表L的当前长度为0,则表L为空表
return TRUE;
else
return FALSE;
}
// 判断顺序表L是否已满
Status is_full(SL& L)
{
if (L.length == L.listsize) // 如果表L的当前长度等于其当前最大容量,则表L已满
return TRUE;
else
return FALSE;
}
// 获取顺序表L的当前长度
int get_length(SL& L)
{
return L.length; // 返回L.length即可
}
// 用e返回顺序表L中第pos个元素的值
Status get_element(SL& L, int pos, ElemType& e)
{
if (pos > L.length || pos < 1) // pos的范围:1 ≤ pos ≤ L.length
return ERROR;
e = L.base[pos - 1]; // 利用下标获取数组中的元素
// 等同于 e = *(L.base + pos - 1); // 利用指针获取数组中的元素
return OK;
}
- 初阶操作函数实现(6个)
// 在顺序表L的第pos个位置上插入元素e
Status insert_element(SL& L, int pos, ElemType e)
{
ElemType* newbase;
if (pos < 1 || pos > L.length + 1) // pos的范围:1 ≤ pos ≤ L.length+1
return ERROR;
if (is_full(L)) // 如果表L已满,则需要重新分配更大的存储空间
{
newbase = (ElemType