顺序表
**前言:**本文主要讲线性表的其中一种,那就是顺序表。顺序表就是采用顺序储存方式来存储数据。所谓顺序存储,就是数据在内存上的地址同样为连续储存,中间不允许有空(有间隔)。顺序表的优点在于支持随机访问,就是通过下标来访问元素;缺点是插入,删除数据时需要挪动大量元素。共有两种方式来创建顺序表,分别是静态顺序表和动态顺序表。
正文开始:
1.静态顺序表
通过前言,我们可以了解到,顺序表中的数据是连续存放的,所以我们不难想到要用数组来建立顺序表。静态顺序表由一个定长的数组组成。
//静态顺序表 #define MAX 10 typedef int SLDateType;//声明数据类型 typedef struct Seqlist//顺序表 { SLDateType arr[MAX];//存放数据的数组 size_t size;//有效数据个数 }SeqList;
大家可能对typedef int SLDateType;这个语句有点疑问,觉得它多余。其实不然,这样做是为了提高程序的可移植性,如果要改变数据的类型为char只需要改成 typedef char SLDateType,这是比较方便的。
将结构体名重命名为SeqList,是为提高代码的可读性以及简化了复杂的类型声明。
顺序表的基本操作有:(1)顺序表初始化(2)顺序表增容
(3)顺序表尾插(4)顺序表尾删(5)顺序表头插(6)顺序表头删(7)顺序表查找(8)顺序表在指定位置插入x(9)顺序表在指定位置删除(10)顺序表销毁(11)顺序表打印
共有上面这几种基本操作,在本文里我主要用动态顺序表来讲解这些操作,因为动态顺序表相对用的多一些。
2.动态顺序表
动态顺序表就是在堆区上开辟了一个数组来存放数据,如果内存不够,就增容。其余的基本和静态顺序表没区别。
//动态顺序表
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a;//指向了动态开辟的数组空间
size_t size;//已存数据个数
size_t capacity; // 总容量
}SeqList;
上文已经说了顺序表的基本操作,我们来逐个击破。
(1)顺序表初始化:
void SeqListInit(SeqList* ps)//初始化
{
ps->capacity = 0;//容量先置为0
ps->size = 0;
ps->a = NULL;//先置为NULL,避免野指针问题
}
(2)顺序表增容:
void CheckCapacity(SeqList* ps)//增容
{
//检查容量是否为0,为0就置新容量为4,不为0就扩2倍
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//调整空间大小
int* tmp = (int*)realloc(ps->a, newcapacity*sizeof(int));
//判断是否开辟成功
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
//如果开辟成功,对a,capacity赋新值
ps->a = tmp;
ps->capacity = newcapacity;
}
(3)顺序表尾插:
void SeqListPushBack(SeqList* ps, SLDateType x)//尾插
{
//先检查容量
CheckCapacity(ps);
//在尾部插入数据x
ps->a[ps->size] = x;
//已存数据+1
ps->size++;
代码跑一波
#include"sxb.h"
void test1()
{
SeqList sxb;
//初始化
SeqListInit(&sxb);
//尾插1,2,3,4,5
SeqListPushBack(&sxb, 1);
SeqListPushBack(&sxb, 2);
SeqListPushBack(&sxb, 3);
SeqListPushBack(&sxb, 4);
SeqListPushBack(&sxb, 5);
//打印
SeqListPrint(&sxb);
}
int main()
{
test1();
return 0;
}
(4)顺序表尾删
void SeqListPopBack(SeqList* ps)//尾删
{
assert(ps->size>0);//断言有效数据是否存在
ps->size--;//有效数据减少
}
(5)顺序表头插
void SeqListPushFront(SeqList* ps, SLDateType x)//头插
{
assert(ps);
CheckCapacity(ps);//检验增容
//挪动数据
for (int i = ps->size; i >0; i--)
{
ps->a[i] = ps->a[i - 1];
}
//头插
ps->a[0] = x;
ps->size++;
}
(6)顺序表头删
void SeqListPopFront(SeqList* ps)//头删
{
assert(ps->a);
//覆盖头一个数据
for (size_t i = 0; i<ps->size; i++)
{
ps->a[i] = ps->a[i+1];
}
//有效数据减一
ps->size--;
}
(7)顺序表查找
int SeqListFind(SeqList* ps, SLDateType x)//查找
{
assert(ps->size > 0);
//遍历数组,如果找到就返回下标
for (int i = 0; i < ps->size; i++)
{
if (x == ps->a[i])
return i;
}
return -1;
}
(8)顺序表在指定位置插入x
void SeqListInsert(SeqList* ps, size_t pos, SLDateType x) //指定位置插入
{
assert(ps->size>0);
CheckCapacity(ps);
int end = ps->size;
//判断pos位置是否正确
if (pos >= 0 && pos <= ps->size)
{
//pos后的位置向后移一位
for (int i = end; i >pos; i--)
{
ps->a[i] = ps->a[i - 1];
}
ps->a[pos] = x;
ps->size++;
}
else
return;
}
(9)顺序表在指定位置删除
void SeqListErase(SeqList* ps, size_t pos)//任意删除
{
assert(ps->size > 0);
int begin = pos;
if (pos >= 0 && pos <= ps->size)
{
//pos后的元素向前移一位,覆盖pos位置
for (int i = begin; i < ps->size; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->size--;
}
}
(10)顺序表销毁
void SeqListDestory(SeqList* ps)//顺序表销毁
{
//容量置为0,有效数据个数置为0
ps->capacity = 0;
ps->size = 0;
//释放指定的空间
free(ps->a);
//将指针置为NULL
ps->a = NULL;
}
(11)顺序表打印
void SeqListPrint(SeqList* ps)//打印
{
//遍历数组打印
for (size_t i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
以上就是本期内容,希望大家有所收获!!!