顺序表
顺序表是线性表的一种。
线性表:具有相同特性的数据结构,线性表在逻辑结构上一定是连续的,在物理结构上不一定是连续的。
顺序表:用顺序存储的方式实现线性表,把逻辑上相邻的两个变量在物理位置也相邻的存储。
顺序表的底层是数组
(文章结尾处放完整代码)
顺序表分类:
-
静态顺序表:底层是一个静态数组。静态顺序表并不方便,当数组的空间给大时,会造成空间浪费;当数组的空间给小了,会造成数据的丢失。
-
动态顺序表:一个指针,动态开辟内层。可以动态的增容。
创建一个顺序表:
(静态顺序表顺序表)
typedef struct SeqList
{
int arr[100];
int size;//记录的是顺序表有效数据个数
int capacity;//记录的是有效空间大小
}
静态顺序表这里不过多阐述,主要动态顺序表。
typedef int SLDatatype;//为什么要对Int重命名?
typedef struct SeqList
{
SLDatatype* arr;
SLDatatype size;//记录的是顺序表有效数据个数
SLDatatype capacity;//记录的是有效空间大小
}
为什么要对int重命名?如果我们后面需求变更,要在顺序表中存储的数据类型是char类型,只需要修改typedef int SLDatatype;
即可。
顺序表初始化
void SeqListInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
为什么要对顺序表初始化?我们知道,顺序表的空间是我们动态内层分配的来的,在将这块空间分配给顺序表前,这块空间中可能已经存储了其他值(脏数据),那么,我们在使用顺序表的时候可能会得到一些不是我们想要的值。
顺序表的销毁
//顺序表的销毁
void SeqListDestory(SL* ps)
{
if (ps->arr)
{
free(ps->arr);
}
ps->capacity = ps->size = 0;
}
在使用完顺序表后,要将空间归还,否则会造成内存泄漏。如果不归还,可能在当下不会有什么问题,但时间久了,被占用的空间多了,程序就会出现问题。
顺序表的头/尾插
void SLCheckCapacity(SL* ps)//检查顺序表的空间是否足够
{
if (ps->capacity == ps->size)//如果空间不足,则增容。当有效数据个数与顺便的空间大小相等时,表示空间以用完。
{
int newCapacity = (ps->capacity == 0 ? 4 : 2 * ps->capacity);
SLDatatype* tmp = (SLDatatype*)realloc(ps->arr, newCapacity * sizeof(SLDatatype));
if (tmp == NULL)
{
perror("realloc Fail");
exit(1);
}
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
void SeqPushBack(SL*ps,SLDatatype x)//尾插
{
assert(ps);//传入的数值不能为NULL,因为不能对空指针解引用
SLCheckCapacity(ps);//检查顺序表空间是否足够
ps->arr[ps->size++] = x;
}
void SeqPushFront(SL*ps,SLDatatype x)//头插
{
assert(ps);
SLCheckCapacity(ps);//检查顺序表空间是否足够
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;
}
顺序表的头/尾删
void SeqPopBcack(SL*ps)//尾删
{
assert(ps);
assert(ps->size);
//ps->arr[ps->size - 1] = 0; 可要可不要
ps->size--;//当作数组来理解,就是把数组的长度减1
}
void SeqPopFront(SL*ps)//头删
{
assert(ps);
assert(ps->size);
for (int i = 0; i < ps->size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1];//当作数组来理解,头删就是将所有数据前移一位,第一个数据直接被后面的数据覆盖掉。
}
ps->size--;
}
顺序表插入数据
void SLInsert(SL*ps,SLDatatype x,int pos)//在指定位置之前插入数据
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
SLCheckCapacity(ps);
for (int i = ps->size; i > pos; i--)//当作数组来理解,就是从pos下标处开始,(包括pos下标处),每个元素后移一位,再在pos处插入数据
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[pos] = x;//在Pos位置插入数据
ps->size++;
}
void SLErase(SL *ps,int pos)//删除指定位置的数据
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
for(int i=pos;i<ps->size-1;i++)
{
ps->arr[i] = ps->arr[i + 1];//当作数组,就是从pos下标开始(不包括pos下标位置),每个元素前移一位,把Pos位置处的数据覆盖掉
}
ps->size--;
}
顺序表查找数据
int SLFind(SL *ps,SLDatatype x )//查找数据
{
assert(ps);
for (int i=0;i<ps->size;i++)
{
if (ps->arr[i]==x)
{
return i;
}
}
return -1;
}
顺序表完整代码
将顺序表的代码分别放在两个个文件下,一个.h头文件,一个.c文件,最好在创建一个test.c文件对顺序表代码进行测试就行了。
SeqList.h文件 头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDatatype;
//顺序表
typedef struct SeqList
{
SLDatatype* arr;
SLDatatype size;//元素个数
SLDatatype capacity;//空间大小
}SL;
void SeqPrint(SL ps);//打印
void SeqListInit(SL*ps);//顺序表初始化
void SeqListDestory(SL*ps);//顺序表的销毁
void SeqPushBack(SL*ps,SLDatatype x);//尾插
void SeqPushFront(SL*ps,SLDatatype x);//头插
void SeqPopBcack(SL*ps);//尾删
void SeqPopFront(SL*ps);//头删
void SLInsert(SL*ps,SLDatatype x,int pos);//在指定位置之前插入数据
void SLErase(SL *ps,int pos);//删除指定位置的数据
int SLFind(SL *ps,SLDatatype x );//查找数据
SeqList.c文件,放的是顺序表函数的实现
#include"SeqList.h"
void SeqPrint(SL ps)
{
for (int i=0;i<ps.size;i++)
{
printf("%d ", ps.arr[i]);
}
printf("\n");
}
//顺序表的初始化
void SeqListInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//顺序表的销毁
void SeqListDestory(SL* ps)
{
if (ps->arr)
{
free(ps->arr);
}
ps->capacity = ps->size = 0;
}
void SLCheckCapacity(SL* ps)
{
if (ps->capacity == ps->size)
{
int newCapacity = (ps->capacity == 0 ? 4 : 2 * ps->capacity);
SLDatatype* tmp = (SLDatatype*)realloc(ps->arr, newCapacity * sizeof(SLDatatype));
if (tmp == NULL)
{
perror("realloc Fail");
exit(1);
}
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
//尾插
void SeqPushBack(SL* ps, SLDatatype x)
{
assert(ps);
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
}
//头插
void SeqPushFront(SL* ps, SLDatatype x)
{
assert(ps);
SLCheckCapacity(ps);
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;
}
void SeqPopBcack(SL* ps)//尾删
{
assert(ps);
assert(ps->size);
//ps->arr[ps->size - 1] = 0; 可要可不要
ps->size--;
}
void SeqPopFront(SL* ps)//头删
{
assert(ps);
assert(ps->size);
for (int i = 0; i < ps->size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
void SLInsert(SL* ps, SLDatatype x, int pos)//在指定位置之前插入数据
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
SLCheckCapacity(ps);
for (int i = ps->size; i > pos; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[pos] = x;
ps->size++;
}
void SLErase(SL* ps, int pos)//删除指定位置的数据
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
for(int i=pos;i<ps->size-1;i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
int SLFind(SL* ps, SLDatatype x)//查找数据
{
assert(ps);
for (int i=0;i<ps->size;i++)
{
if (ps->arr[i]==x)
{
return i;
}
}
return -1;
}
test.c测试文件,这个文件可以不用看了,但是为了文章的完整性,所有我写在了这里。
#include"SeqList.h"
void test1()
{
SL s;
SeqListInit(&s);
/*
SeqPushBack(&s,1);
SeqPushBack(&s,2);
SeqPushBack(&s,3);
SeqPushBack(&s,4);
SeqPrint(s);*/
SeqPushFront(&s,1);
SeqPushFront(&s,2);
SeqPushFront(&s,3);
SeqPrint(s);
//SeqPopBcack(&s);
//SeqPrint(s);
//SeqPopBcack(&s);
//SeqPrint(s);
//SeqPopBcack(&s);
//SeqPrint(s);
//SeqPopBcack(&s);
//SeqPrint(s);
/*1111*/
/*SeqPopFront(&s);
SeqPrint(s);*/
/*SLInsert(&s,9,s.size);
SeqPrint(s);
SLErase(&s,s.size-1);
SeqPrint(s);*/
int find=SLFind(&s,2);
if (find==-1)
{
printf("没找到");
}
else
{
printf("找到了");
}
SeqListDestory(&s);
}
int main()
{
test1();
return 0;
}