顺序表的定义
- 线性表:线性表与顺序表互为父子级关系,可以说线性表是包含了顺序表等多个·具有相同特征的数据结构的集合,举例来说:线性表相当于水果,而顺序表就是其中的苹果。
- 相同特征:既然顺序表,链表等数据结构都被成为线性表的一种,则说明他们具有相同的特征,从逻辑结构来看:之所以被称为线性表,是因为在我们看来其数据的组织结构像线性一样关联着,并且更加容易理解,所以被称为线性表。而物理结构方面是指数据的存储形式,但是并没有表现出线性的特征。所以我们将其成为线性表是因为其逻辑结构方面更加方便我们理解和归纳等。
- 顺序表的底层结构:顺序表是由数组来实现的,所以其底层结构是数组,但与数组不同的是:顺序表具有对数据进行修改删除添加等一系列操作,所以是利用结构体对数组进行封装,使其能够实现多种功能。
顺序表的分类
- 静态顺序表:静态顺序表是指空间为指定大小的顺序表,即不能对空间大小进行修改的顺序表,这样做可以简化操作步骤,相对动态顺序表来说要更加简易,但有很大的缺点:在设置空间大小的时候,会发生申请空间过大或者过小的情况,空间过大会造成浪费,空间过小会造成数据丢失,所以静态顺序表一般不会被用来代替动态顺序表。
- 动态顺序表:动态顺序表相对于静态顺序表的区别是可以随时申请空间,不会对空间造成太大的浪费,也不会发生数据丢失的情况。但动态顺序表的申请空间的方法有些特别,通常来说缺少几个空间就申请几个空间是最完美的情况,但并没有这样做,而是再申请等于自身大小的空间,这样虽然会造成一定的浪费,但会大幅减少程序的运行时间,所以在时间和空间两个方面上是双赢的局面。
顺序表的实现
这是头文件(SeqList.h) ,是实现各种功能的目录,标注了每一个函数的功能
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a;
int size;
int capacity;
}SeqList;
// 对数据的管理:增删查改
void SeqListInit(SeqList* ps);//顺序表的初始化
void SeqListDestroy(SeqList* ps);//顺序表的销毁
void SLcheckCapacity(SeqList* ps);//顺序表申请空间
void SeqListPrint(SeqList* ps);//顺序表的打印
void SeqListPushBack(SeqList* ps, SLDateType x);//顺序表的尾插
void SeqListPushFront(SeqList* ps, SLDateType x);//顺序表的头插
void SeqListPopFront(SeqList* ps);//顺序表的头删
void SeqListPopBack(SeqList* ps);//顺序表的尾删
// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);
这是SeqList.c源文件,用来实现各种函数的功能。
#include "SeqList.h"
void SeqListInit(SeqList * ps)
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}
void SeqListDestroy(SeqList* ps)
{
if (ps->a)
{
free(ps->a);
}
ps->a = NULL;
ps->size = ps->capacity = 0;
}
void SLcheckCapacity(SeqList* ps)
{
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
SeqList* tmp = (SeqList*)realloc(ps->a, newcapacity * sizeof(SeqList));
if (tmp == NULL)
{
perror("realloc fail!!!");
exit(1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
void SeqListPrint(SeqList* ps)
{
if (ps->size != 0)
{
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
}
printf("\n");
}
void SeqListPushBack(SeqList* ps, SLDateType x)
{
assert(ps);
SLcheckCapacity(ps);
ps->a[ps->size++] = x;
}
void SeqListPushFront(SeqList* ps, SLDateType x)
{
assert(ps);
SLcheckCapacity(ps);
for (int i = ps->size; i > 0; i--)
{
ps->a[i] = ps->a[i-1];
}
ps->a[0] = x;
ps->size++;
}
void SeqListPopFront(SeqList* ps)
{
assert(ps);
assert(ps->size);
for (int i = 1; i < ps->size; i++)
{
ps->a[i - 1] = ps->a[i];
}
ps->size--;
}
void SeqListPopBack(SeqList* ps)
{
assert(ps);
assert(ps->size);
ps->size--;
}
int SeqListFind(SeqList* ps, SLDateType x)
{
assert(ps);
assert(ps->size);
for (int i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
printf("%d ", i);
}
}
printf("\n");
}
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
assert(ps);
assert(ps->size);
for (int i = ps->size; i > pos; i--)
{
ps->a[i] = ps->a[i - 1];
}
ps->size++;
ps->a[pos] = x;
}
void SeqListErase(SeqList* ps, int pos)
{
assert(ps);
assert(ps->size);
for (int i = pos; i < ps->size-1; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->size--;
}
这是测试函数,用来测试每个函数的功能是否正常,以防止代码在写完后到处报错。
#include "SeqList.h"
int main()
{
SeqList s;
SeqListInit(&s);
SeqListPushBack(&s, 5);
SeqListPushBack(&s, 5);
SeqListPushBack(&s, 4);
SeqListPushBack(&s, 5);
SeqListPushBack(&s, 5);
SeqListPushBack(&s, 6);
SeqListPushFront(&s, 9);
SeqListPopFront(&s);
SeqListPopBack(&s);
SeqListFind(&s, 5);
SeqListInsert(&s, 3, 6);
SeqListErase(&s, 2);
SeqListPrint(&s);
SeqListDestroy(&s);
return 0;
}