1.顺序表
1.1概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素。2. 动态顺序表:使用动态开辟的数组存储。
1.2 接口函数
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
SLDataType* array; // 指向动态开辟的数组
size_t size; // 有效数据个数
size_t capicity; // 容量空间的大小(空间不够要进行扩容)
}SeqList;
// 基本增删查改接口
// 顺序表初始化
void SeqListInit(SeqList* psl);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* psl);
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);
// 顺序表头删
void SeqListPopFront(SeqList* psl);
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
// 顺序表打印
void SeqListPrint(SeqList* psl);
1.3接口函数的实现
// 顺序表初始化
void SeqListInit(SeqList* psl)
{
psl->array = NULL;
psl->capicity = 0;
psl->size = 0;
}
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl)
{
if (psl->size == psl->capicity)
{
int new = psl->capicity == 0 ? 4 : 2 * (psl->capicity);
SLDataType* temp = (SLDataType*)realloc(psl->array, sizeof(SLDataType) * new);
if (temp == NULL)
{
perror("realloc");
return;
}
psl->array = temp;
psl->capicity = new;
}
}
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x)
{
CheckCapacity(psl);
psl->array[psl->size] = x;
psl->size++;
}
// 顺序表尾删
void SeqListPopBack(SeqList* psl)
{
//检查是否为空
assert(psl->size > 0);
psl->size--;
}
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x)
{
CheckCapacity(psl);
int end = psl->size - 1;
while (end >= 0)
{
psl->array[end + 1] = psl->array[end];
--end;
}
psl->array[0] = x;
psl->size++;
}
// 顺序表头删
void SeqListPopFront(SeqList* psl)
{
//数据往前挪动覆盖,size--
assert(psl->size > 0);
int begin = 1;
while (begin < psl->size)
{
psl->array[begin - 1] = psl->array[begin];
}
psl->size--;
}
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x)
{
assert(psl);
for (int i = 0; i < psl->size; i++)
{
if (psl->array[i] == x)
{
return i;
}
}
return -1;
}
// 顺序表在pos位置插入x
//注意pos在这里是下标,从0开始
//而size是数据个数
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
assert(psl);
assert(pos >= 0 && pos <= psl->size);
CheckCapacity(psl);
int end = psl->size - 1;
while (end >= psl->size)
{
psl->array[end + 1] = psl->array[end];
--end;
}
psl->array[pos] = x;
psl->size++;
}
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
assert(pos >= 0 && pos <= psl->size);
int begin = pos;
while (begin < psl->size)
{
psl->array[begin] = psl->array[begin + 1];
++begin;
}
psl->size--;
}
// 顺序表销毁
void SeqListDestory(SeqList* psl)
{
if (psl->array != NULL)
{
free(psl->array);
psl->array = NULL;
psl->capicity = 0;
psl->size = 0;
}
}
// 顺序表打印
void SeqListPrint(SeqList* psl)
{
assert(psl);
for (int i = 0; i < psl->size; i++)
{
printf("%d ", psl->array[i]);
}
printf("\n");
}
1.4实现详解:
1.增容问题
在这里我们直接使用realloc函数,此函数比malloc函数更加便捷,当空间为0的时候,直接开辟空间,当空间不足的时候会进行增容。
int new = psl->capicity == 0 ? 4 : 2 * (psl->capicity);
这条语句的意思是,当空间为0是,开辟4个结构体大小的空间。
2.打印
实现打印操作是十分简单的,只需要打印有效个数据(size)即可。
3.尾插
实现尾插是十分简单的,只需要在size位置存入数据,再++size数据就好了。
4.尾删
删除,我们首先要断言顺序表是否为空,为空就不进行删除操作了。然后,直接--size就能完成删除操作了。
5.头插
顺序表的头插,只需要将首元素往后的数据向后挪动即可,然后将首元素的数据写入。
这时我们使用end指针来接收,挪动数据就好了。
6.头删
头删,实际上把首元素覆盖掉就行了,此次用begin向前挪动数据
7.任意位置插入
任意位置插入和头插差异不大,只要从想要插入的节点往后挪动数据就好了,但要注意不要越界访问。
8.任意位置删除
这里也是和头删非常相似的,删除一个数据,则向前挪动数据。
9.销毁顺序表
最后当然不能忘记销毁顺序表了。
2.顺序表完整代码。
list.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
SLDataType* array; // 指向动态开辟的数组
size_t size; // 有效数据个数
size_t capicity; // 容量空间的大小(空间不够要进行扩容)
}SeqList;
// 基本增删查改接口
// 顺序表初始化
void SeqListInit(SeqList* psl);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* psl);
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);
// 顺序表头删
void SeqListPopFront(SeqList* psl);
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
// 顺序表打印
void SeqListPrint(SeqList* psl);
list.c
#include"list.h"
// 顺序表初始化
void SeqListInit(SeqList* psl)
{
psl->array = NULL;
psl->capicity = 0;
psl->size = 0;
}
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl)
{
if (psl->size == psl->capicity)
{
int new = psl->capicity == 0 ? 4 : 2 * (psl->capicity);
SLDataType* temp = (SLDataType*)realloc(psl->array, sizeof(SLDataType) * new);
if (temp == NULL)
{
perror("realloc");
return;
}
psl->array = temp;
psl->capicity = new;
}
}
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x)
{
CheckCapacity(psl);
psl->array[psl->size] = x;
psl->size++;
}
// 顺序表尾删
void SeqListPopBack(SeqList* psl)
{
//检查是否为空
assert(psl->size > 0);
psl->size--;
}
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x)
{
CheckCapacity(psl);
int end = psl->size - 1;
while (end >= 0)
{
psl->array[end + 1] = psl->array[end];
--end;
}
psl->array[0] = x;
psl->size++;
}
// 顺序表头删
void SeqListPopFront(SeqList* psl)
{
//数据往前挪动覆盖,size--
assert(psl->size > 0);
int begin = 1;
while (begin < psl->size)
{
psl->array[begin - 1] = psl->array[begin];
}
psl->size--;
}
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x)
{
assert(psl);
for (int i = 0; i < psl->size; i++)
{
if (psl->array[i] == x)
{
return i;
}
}
return -1;
}
// 顺序表在pos位置插入x
//注意pos在这里是下标,从0开始
//而size是数据个数
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
assert(psl);
assert(pos >= 0 && pos <= psl->size);
CheckCapacity(psl);
int end = psl->size - 1;
while (end >= psl->size)
{
psl->array[end + 1] = psl->array[end];
--end;
}
psl->array[pos] = x;
psl->size++;
}
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
assert(pos >= 0 && pos <= psl->size);
int begin = pos;
while (begin < psl->size)
{
psl->array[begin] = psl->array[begin + 1];
++begin;
}
psl->size--;
}
// 顺序表销毁
void SeqListDestory(SeqList* psl)
{
if (psl->array != NULL)
{
free(psl->array);
psl->array = NULL;
psl->capicity = 0;
psl->size = 0;
}
}
// 顺序表打印
void SeqListPrint(SeqList* psl)
{
assert(psl);
for (int i = 0; i < psl->size; i++)
{
printf("%d ", psl->array[i]);
}
printf("\n");
}