1.顺序表的概念
1.1线性表
具有相同特性的数据元素的有限序列,再逻辑结构上呈现线性,但是在物理结构上不一定是线性(也就是在内存中非线性)
顺序表是线性表中的一种,他的底层逻辑就是数组,就是对数组的一种封装形式,有了增删改查等用法;
注:数组在逻辑结构和物理结构都是线性的;
1.2顺序表的分类
顺序表可分为:动态顺序表和静态顺序表
1.2.1静态顺序表
例如:
struct L
{int a[100];int size //当前有效数据个数
};
1.2.2动态顺序表
strcut
{int* a;int sizeint ca//当前空间大小
}
动态顺序表对于内存处理更加灵活;对于扩容更加方便,不需要整个数组进行修改,增加了数据的安全性。
1.3顺序表的头文件
1.3.1顺序表基础
//包含头文件
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
//关键字转变
typedef int SLDateType;
typedef struct SeqList
{SLDateType* a;int size;int capacity;
}SQ;
第一,typedef int SLDateType;可以更好改变数据变量的类型;
第二,
typedef struct SeqList
{SLDateType* a;int size;int capacity;
}SQ;
把名叫SeqList的结构体typedef成SQ,方便未来对此结构体的调用。
SLDateType* a;->a指向的空间就是顺序表存储的位置。
int size;->顺序表成员的数量
int capacity;->顺序表空间的大小
1.3.2顺序表基本应用
// 对数据的管理:增删查改
//初始化
void SeqListInit(SQ* ps);
//结构体的清除
void SeqListDestroy(SQ* ps);
//结构体打印
void SeqListPrint(SQ* ps);
//尾插
void SeqListPushBack(SQ* ps, SLDateType x);
//头插
void SeqListPushFront(SQ* ps, SLDateType x);
//头删
void SeqListPopFront(SQ* ps);
//尾删
void SeqListPopBack(SQ* ps);
// 顺序表查找
int SeqListFind(SQ* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SQ* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SQ* ps, int pos);
顺序表初始化
#include "SeqList.h"void SeqListInit(SQ* ps)
{assert(ps);ps->a = NULL;ps->size = 0;ps->capacity = 0;
}
a的空间指向NULL,size成员数量和空间大小都置为0;
顺序表清除
void SeqListDestroy(SeqList* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->size = ps->capacity = 0;
}
首先判断ps是否为空,为空则中断,不为空则为继续执行,此处assert(x),x为真
才不会被中断。
free(ps->a)把a所指向的空间置为NULL;
a的指针置为空,size,capacity为0;
顺序表的打印
void SeqListPrint(SQ* ps)
{assert(ps);for (inti = 0; i < ps->size; ++i){printf("%d ", ps->a[i]);}printf("%\n");
}
顺序表空间开辟
void CheckCacpity(SQ* ps)
{if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;ps->a = (SLDateType*)realloc(ps->a, newcapacity*sizeof(SLDateType));ps->capacity = newcapacity;}
}
当size的大小和capacity的大小一样的时候,则表示空间满了,当空间capacity和size大小为空时,也会开辟空间;
创建newcapacity(判断capacity是非为0,为0则开辟为4,不为0,则*2)
realloc(存储空间,重新开辟空间的大小)
之后再把capacity置为新空间大小。
1.3.3顺序表的增删改查
顺序表的尾部插入
void SeqListPushBack(SQ* ps, SLDateType x)
{assert(ps);CheckCacpity(ps);ps->a[ps->size] = x;ps->size++;
}
首先断言ps是否为空指针,之后开辟一个空间,其中ps->a[ps->size],ps所指向的数组a的下标为ps->size的元素(新开辟空间的下标),因为下标是从0开始的,所以原数组最大下标为size-1,新开辟的则为size。
不要忘记size还需要增加。
顺序表的头部插入
void SeqListPushFront(SQ* ps, SLDateType x)
{assert(ps);CheckCacpity(ps);int end = ps->size;while (end > 0){ps->a[end] = ps->a[end - 1];--end;}ps->a[0] = x;++ps->size;
}
首先进行断言和开辟空间,设置一个新整型end存放最大元素个数size,end用来控制变量。
循环判定条件是end>0,循环体内部将数组元素向后移动,之后将end减小,直至end=0时,循环终止。
之后再将a[0]置为新的数字x,size又增大一位。
顺序表的头部删除
void SeqListPopFront(SQ* ps)
{assert(ps);int start = 0;while (start < ps->size-1){ps->a[start] = ps->a[start + 1];++start;}--ps->size;
}
先断言ps,创建一个整型变量,置为0,循环体内将整个数组进行遍历,原理是用后面的元素把前面的覆盖掉,从小到大覆盖,最后将size-1;
顺序表的尾部删除
void SeqListPopBack(SeqList* ps)
{assert(ps);ps->a[ps->size - 1] = 0;ps->size--;
}
老规矩,先断言,ps为空就不能进行插入删除,此处凸显了顺序表的好处,能够很灵活的调用顺序表内的各个成员(因为有下标的关系),
只需要将最后一个元素置为0,之后将size-1即可。
1.3.4顺序表其他应用
找到数据位x下标位置
int SeqListFind(SQ* ps, SLDateType x)
{for (int i = 0; i < ps->size; ++i){if (ps->a[i] == x){return i;}}return -1;
}
再循环体内,生成一个新整型i,对其进行增加操作,遍历数组,如果下标为i的元素等于要找的x,则返回下标i,如果没找到则返回-1;
顺序表在pos位置插入x
void SeqListInsert(SQ* ps, size_t pos, SLDateType x)
{assert(ps);assert(pos <= ps->size);CheckCacpity(ps);int end = ps->size ;while (end > pos){ps->a[end] = ps->a[end - 1];--end;}ps->a[pos] = x;ps->size++;
}
断言ps,断言下标pos不能小于size,开辟一个待插入的新空间
while循环将pos小标之后的元素集体向后移动一位,
最后留下pos位置置为x,size增加1;
顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{assert(ps && pos < ps->size);int start = pos+1;while (start < ps->size){ps->a[start-1] = ps->a[start];++start;}ps->size--;
}
断言,start是pos的下一个;
循环前置,pos之后的数据集体向前覆盖,把pos覆盖,最后size--,表示原数组最后一位不在读取。