顺序表是线性结构中的一种----顺序储存结构
该种结构的占用的是内存中的一块连续的空间(和数组相似)
顺序表可以有两种实现方式:
#define NUM 100
typedef struct SeqList{
int a[NUM];
int size;//表长
}SeqList;
NUM是数组的大小,也就是顺序表中可以放置的元素个数。
我们可以用size来记录某个时刻数组中已经放入了多少个元素。
typedef struct SeqList {
SeqListType* list;
int size;//表长
int capacity;
}SeqList;
利用指针以及动态内存开辟可以灵活的控制空间的大小
同样用size来记录已经存放了多少个元素
capacity和静态数组中的NUM作用相似,不同的是Capacity可以按照需求扩大缩小。
两者比较:我们在使用前并不能确定实际上需要用到多大的空间,所以我们采用了动态开辟的方法,这样可以灵活的控制空间的大小。
顺序表可以实现以下功能:
//函数的声明
//顺序表的初始化----SeqListInit
//尾插一个元素----SeqListPushBack
//尾删一个元素----SeqListPopBack
//头插一个元素----SeqListPushFront
//头删一个元素----SeqListPopFront
//任何位置的元素插入----SeqListInsert
//任何位置的元素删除----SeqListErase
//检查容量----SeqListCheckCapacity
//销毁顺序表----SeqListDeStroy
接下来我们依次来实现这些函数
void SeqListInit(SeqList* psl)
{
assert(psl);
psl->capacity = 0;
psl->size = 0;
psl->list = NULL;
}
我们可以一开始让capacity 有一个初始值,也可以像这样将初始值赋为0
注意:我们在操作一个顺序表的时候,需要注意的是顺序表的容量是否已满,如果顺序表的容量满了,我们就需要扩容,这样我们才能继续向顺序表中添加元素。
void SeqListCheckCapacity(SeqList* psl)
{
assert(psl);//判断psl是否为空指针
if (psl->size == psl->capacity)
{
int newcapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
//如果capacity的值为0(只有初始化的时候才可能为0),那么就将capacity 的值赋为4。
//如果caoacity的值不为0,那么就让容量翻倍。
SeqListType* tmp = (SeqListType*)realloc(psl->list, sizeof(SeqListType) * newcapacity);
if (tmp == NULL)
{
printf("realloc:fail\n");
exit(-1);
}
else
{
psl->list = tmp;
psl->capacity = newcapacity;
}
}
}
当size 与capacity的值相同时,说明顺序表的容量已经满了,我们需要扩容
注意:我们需要判断是否扩容成功(判断tmp是否为空指针)。
注意:1. 每一次向顺序表中添加元素都需要检查顺序表的容量。
2. 每一次添加一个元素后都需要将size的值加1。
void SeqListPushBack(SeqList* psl, SeqListType x)
{
assert(psl);
SeqListCheckCapacity(psl);
psl->list[psl->size] = x;
psl->size++;
}
向尾部添加元素时,
psl->list[psl->size]
就是我们要赋值的地址,由于size 的值很容易得到,所以向尾部添加元素得操作十分简单。
void SeqListPushFront(SeqList* psl, SeqListType x)
{
assert(psl);
SeqListCheckCapacity(psl);
int begin = psl->size;
while (begin > 0)
{
psl->list[begin] = psl->list[begin - 1];
begin--;
}
psl->list[0] = x;
psl->size++;
}
void SeqListInsert(SeqList* psl, size_t pos, SeqListType x)
{
assert(psl);
if (pos > psl->size)
{
printf("越界");
}
SeqListCheckCapacity(psl);//检查容量
size_t begin = psl->size;
while (begin > pos)
{
psl->list[begin] = psl->list[begin - 1];
begin--;
}
psl->list[pos] = x;
psl->size++;
}
在指定位置添加元素的操作和在顺序表的头部添加元素的操作十分相似。
不过在插入元素之前我们需要判断传过来的参数是否符合条件
不同的插入位置会有不同的结果:
需要注意的是:每一次在顺序表中删除一个元素size的值就需要减1
//尾删一个元素
void SeqListPopBack(SeqList* psl)
{
assert(psl);
if (psl->size > 0)
{
psl->size--;
}
}
删除尾部的元素,只需要将表长(size)减1,因为我们是通过size来记录顺序表中有几个元素,如果size减1 ,就相当于顺序表中的元素个数减1,也就相当于删除了最后一个元素。
//头删一个元素
void SeqListPopFront(SeqList* psl)
{
assert(psl);
int begin = 1;
while (begin < psl->size)
{
psl->list[begin-1] = psl->list[begin];
begin++;
}
psl->size--;
}
删除元素表头部的元素,只需要从顺序表中的第二个元素开始,依次向前覆盖,直到最后一个元素的值,覆盖到倒数第二个元素的位置上,然后让表长(size)减1,就完成了头部元素的删除。
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
assert(pos < psl->size);
size_t begin = pos+1;
while (begin < psl->size)
{
psl->list[begin-1] = psl->list[begin];
begin++;
}
psl->size--;
}
删除指定位置的元素方法和删除头部元素的方法类似:
由于我们使用的是动态内存开辟的方法实现的顺序表,所以在最后我们需要将动态开辟出来的空间释放。
void SeqListDeStroy(SeqList* psl)
{
assert(psl);
free(psl->list);
psl->capacity = 0;
psl->size = 0;
psl->list = NULL;
}
顺序表的完整实现
头文件SeqList.h
#pragma once
//顺序表
#include
#include
#include
//结构的声明
//有两种顺寻标的声明,一种是静态的---以数组的形式
//另一种是动态的----动态内存开辟,第一种方式开辟出来的空间可能会不足,,也可能会浪费,所以我们采用动态内存开辟的方式
typedef int SeqListType;
typedef struct SeqList {
SeqListType* list;
int size;
int capacity;
}SeqList;
//一个顺序表要实现的功能有:在任何一个位置插入一个元素,
//在任何一个位置删除一个元素,修改元素,查找元素
//函数的声明
//顺序表的初始化
void SeqListInit(SeqList* psl);
//尾插一个元素
void SeqListPushBack(SeqList* psl, SeqListType x);
//尾删一个元素
void SeqListPopBack(SeqList* psl);
//头插一个元素
void SeqListPushFront(SeqList* psl, SeqListType x);
//头删一个元素
void SeqListPopFront(SeqList* psl);
//任何位置的元素插入
void SeqListInsert(SeqList* psl, size_t pos, SeqListType x);
//任何位置的元素删除
void SeqListErase(SeqList* psl, size_t pos);
//检查容量
void SeqListCheckCapacity(SeqList* psl);
//销毁顺序表
void SeqListDeStroy(SeqList* pal);
//打印顺序表的内容
void SeqListPrint(SeqList* psl);
源文件SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1
//函数实现
#include"SeqList.h"
//顺序表的初始化
void SeqListInit(SeqList* psl)
{
assert(psl);
psl->capacity = 0;
psl->size = 0;
psl->list = NULL;
}
//检查容量
void SeqListCheckCapacity(SeqList* psl)
{
assert(psl);
if (psl->size == psl->capacity)
{
int newcapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
SeqListType* tmp = (SeqListType*)realloc(psl->list, sizeof(SeqListType) * newcapacity);
if (tmp == NULL)
{
printf("realloc:fail\n");
exit(-1);
}
else
{
psl->list = tmp;
psl->capacity = newcapacity;
}
}
}
//尾插一个元素
void SeqListPushBack(SeqList* psl, SeqListType x)
{
assert(psl);
SeqListCheckCapacity(psl);
psl->list[psl->size] = x;
psl->size++;
}
//尾删一个元素
void SeqListPopBack(SeqList* psl)
{
assert(psl);
if (psl->size > 0)
{
psl->size--;
}
}
//头插一个元素
void SeqListPushFront(SeqList* psl, SeqListType x)
{
assert(psl);
SeqListCheckCapacity(psl);
int begin = psl->size;
while (begin > 0)
{
psl->list[begin] = psl->list[begin - 1];
begin--;
}
psl->list[0] = x;
psl->size++;
}
//头删一个元素
void SeqListPopFront(SeqList* psl)
{
assert(psl);
int begin = 1;
while (begin < psl->size)
{
psl->list[begin-1] = psl->list[begin];
begin++;
}
psl->size--;
}
//任何位置的元素插入
void SeqListInsert(SeqList* psl, size_t pos, SeqListType x)
{
assert(psl);
if (pos > psl->size)
{
printf("越界");
}
SeqListCheckCapacity(psl);
size_t begin = psl->size;
while (begin > pos)
{
psl->list[begin] = psl->list[begin - 1];
begin--;
}
psl->list[pos] = x;
psl->size++;
}
//任何位置的元素删除
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
assert(pos < psl->size);
size_t begin = pos+1;
while (begin < psl->size)
{
psl->list[begin-1] = psl->list[begin];
begin++;
}
psl->size--;
}
//销毁顺序表
void SeqListDeStroy(SeqList* psl)
{
assert(psl);
free(psl->list);
psl->capacity = 0;
psl->size = 0;
psl->list = NULL;
}
//打印顺序表的内容
void SeqListPrint(SeqList* psl)
{
assert(psl);
int i = 0;
for (i = 0; i < psl->size; i++)
{
printf("%d ", psl->list[i]);
}
printf("\n");
}
源文件test.c
void menu()
{
printf("********************************\n");
printf("*** 1.尾插 2.尾删 ***\n");
printf("*** 3.头插 4.头删 ***\n");
printf("*** 5.指定插入 6.指定删除 ***\n");
printf("*** 7.查看 -1.退出 ***\n");
printf("********************************\n");
}
int main()
{
SeqList data;
InitSeqList(&data);
int option = -1;
do {
menu();
printf("请选择您想要进行的操作:>");
scanf("%d", &option);
SeqListType val = 0;
size_t pos = 0;
switch (option)
{
case 1:
printf("请输入您想要插入的数据:>");
scanf("%d", &val);
SeqListPushBack(&data, val);
break;
case 2:
SeqListPopBack(&data);
break;
case 3:
printf("请输入您想要插入的数据:>");
scanf("%d", &val);
SeqListPushFront(&data, val);
break;
case 4:
SeqListPopFront(&data);
break;
case 5:
printf("请输入你想要插入的数据:>");
scanf("%d", &val);
printf("请输入你想要插入的位置:>");
scanf("%d", &pos);
SeqListInsert(&data, pos, val);
break;
case 6:
printf("请输入您想要删除的位置:>");
scanf("%d", &pos);
SeqListErase(&data, pos);
break;
case 7:
SeqListPrint(&data);
break;
case -1:
printf("退出程序\n");
return 0;
break;
default:
printf("请重新选择\n");
break;
}
} while (option);
test2(&data);
return 0;
}