一、顺序表
(1)、什么是顺序表
在了解顺序表之前先,认识一下线性表。
线性表:是n个具有相同特性的数据元素的有限序列。线性表是在应用中被广泛使用的数据结构,常见的线性表:顺序表,链表,栈,队列,字符串等等。
线性表在逻辑上是连续的(想象中是连续的),在物理上不一定连续(内存中存储不一定连续,比如链表)。
顺序表:是线性表的一种,是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上进行增删查改。
(2)、如何使用?
顺序表分为:静态顺序表和动态顺序表。
静态顺序表:使用定长数组存储。
动态顺序表L:使用动态内存的数组存储。
顺序表的静态存储:
#define N 100//数组的大小
typedef int SLDateType;//想存储什么类型的数据,修改int 即可。
typedef struct SeqList
{
SLDateType a[N];//定长数组
size_t szie;//有效数据个数
}SeqList;
顺序表的静态存储:
typedef int SLDateType;
typedef struct Seqlist
{
SLDateType* arr;//柔性数组,使用malloc开辟动态内存。
SLDateType size;//已有数目
SLDateType capacity;//容量
}Seqlist;
二、实现动态顺序表
还是使用多文件实现。
头文件:包含头文件和函数声明,定义的结构体和宏定义:
#pragma once//防止头文件被重复包含
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#pragma warning(disable:4996)
typedef int SLDateType;
typedef struct Seqlist
{
SLDateType* arr;//柔性数组
SLDateType size;//已有数目
SLDateType capacity;//容量
}Seqlist;
//函数声明
//初始化ps函数
void SeqListInit(Seqlist *ps);
//尾插函数
void SeqListPushBack(Seqlist* ps,SLDateType x);
//尾删函数
void SeqListPopBack(Seqlist* ps);
//打印函数
void SeqListPrint(const Seqlist* ps);
//头插函数
void SeqListPushFront(Seqlist* ps, SLDateType x);
//头删函数
void SeqListPopFront(Seqlist* ps);
//顺序表寻找函数
int SeqListFind(const Seqlist* ps, SLDateType x);
//顺序表销毁函数
void SeqListDestory(Seqlist* ps);
//顺序表中间插入函数
void SeqListInsert(Seqlist* ps, int pos, SLDateType x);
//顺序表中间删除函数
void SeqListErase(Seqlist* ps, int pos);
源文件 main.c 进行测试函数:
int main()
{
Seqlist ps;
//调用函数,调试
return 0;
}
源文件SeqList.c实现函数功能:
我们定义了结构体变量,首先我们需要对ps进行初始化。
(1)、初始化函数SeqListInit函数:
void SeqListInit( Seqlist *ps)
{
ps->arr = (SLDateType*)malloc(sizeof(SLDateType) * 4);
//初始化,申请动态内存
if (ps->arr == NULL)
{
printf("malloc failed");
return;
}
ps->size = 0;
ps->capacity = 4;//初始容量为4
}
(2)、尾插功能
在每次插入之前都要判断容量是否够用,用CheckSeqList(ps);
每添加一个size++;
void SeqListPushBack(Seqlist* ps, SLDateType x)
{
assert(ps);
CheckSeqList(ps);//判断是否需要扩容
ps->arr[ps->size] = x;//将新值赋给下标为size的arr
ps->size++;
}
(3)判断是否需要扩容函数CheckSeqList
void CheckSeqList(Seqlist* ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
ps->capacity *= 2;//扩容成原来的两倍,最多浪费不到50%
ps->arr=(SLDateType*)realloc(ps->arr, sizeof(SLDateType) * ps->capacity);
if (ps->arr == NULL)
{
printf("realloc失败\n");
return;
}
}
}
(4)尾删函数SeqListPopBack
只需要将最后一个数无效就好
void SeqListPopBack(Seqlist* ps)
{
assert(ps);
ps->size--;//减少数组中的有效数目,让最后一个数无效
}
(5)、头插函数
画个图理解一下:
将每一个只能向后移动,将arr下标size-1的值给szie ,size-2给size-1,依次空出arr[0],将x赋值给arr[0];
void SeqListPushFront(Seqlist* ps, SLDateType x)
{//将每一个只能向后移动,
assert(ps);
CheckSeqList(ps);
int i = ps->size;//不能改变size的值
while (i > 0)
{
ps->arr[i] = ps->arr[i - 1];
i--;
}
ps->arr[0] = x;//把新值符给第一个
ps->size++;
}
(6)、顺序表打印函数:
void SeqListPrint(const Seqlist* ps)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->arr[i]);
}
printf("\n");
}
(7)头删函数:
1、可以用下标为size-1的值一个覆盖第一个,然后size–,但是会打乱原来的顺序,如图一样:2、整体向左移动,覆盖第一个,size–,这样不会打乱顺序,如图:
将每一个只能向左移动,将arr下标size-1的值给szie-2 ,size-2给size-3,最后覆盖arr[0];
代码实现如下:
void SeqListPopFront(Seqlist* ps)
{
//可以用最后一个覆盖第一个,然后size--,但是会打乱原来的顺序
/*ps->arr[0] = ps->arr[ps->size - 1];
ps->size--;*/
//也可以整体向<-移动,不会打乱顺序
int i = 1;
for (i = 0; i < ps->size-1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
(8)、中间插入函数:
给定一个位置在他的后边插入新值,只是将pos位置之后的向后移,也可以调用头插实现,
d代码实现如下:
void SeqListInsert(Seqlist* ps, int pos, SLDateType x)
{//size是0 size是1 size是多个三种情况
assert(ps);
assert(pos < ps->size);//pos不能小于ps->size
CheckSeqList(ps);
int end = ps->size;//pos位置到最后整体,向后移动一位,预留pos位置
for (end; end > pos; end--)
{
ps->arr[end] = ps->arr[end - 1];
}
ps->arr[pos] = x;
ps->size++;
}
(9)中间删除函数:
和头删一样,用pos(要删掉的位置)后边的值向后移动覆盖pos位置的值。
代码实现如下:
void SeqListErase(Seqlist* ps, int pos)//pos是位置
{
assert(ps);
assert(pos < ps->size);
int start = pos;
for (start; start < ps->size; start++)
{
ps->arr[start] = ps->arr[start + 1];
}
ps->size--;
}
(10)顺序表查找函数:
判断x与arr里边的值是否相等,相等返回下标,
没有相等的,就是找不到。
int SeqListFind(const Seqlist* ps, SLDateType x)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (ps->arr[i] == x)
{
printf("找到了,下标是%d\n", i);
return i;
}
}
printf("找不到\n");
return -1;
}
(11)、销毁顺序表函数
我们使用了malloc申请了动态内存,如果不释放,会发生内存泄漏。所以使用完顺序表,要销毁。
void SeqListDestory(Seqlist* ps)
//我们使用了malloc申请了动态内存,如果不释放,会发生内存泄漏
{
free(ps->arr);
ps->arr = NULL;
ps->size = ps->capacity = 0;
}