顺序表
认识了解顺序表
a.顺序表的概念
在数据结构中,顺序表是一种线性表的存储结构,它是由一组地址连续的存储单元依次存储线性表的各个元素。顺序表有两种形式:静态顺序表和动态顺序表。
静态顺序表(Static Array): 在创建时就确定了固定大小,不可改变。静态顺序表的元素在物理地址上是连续存储的,支持随机访问,通过下标可以直接访问任意位置的元素。
//顺序表的静态存储
define N 7
//SLDataType 是一个整数类型的别名,
//DataType仅仅只是作为表示符,无实际作用
typedef int SLDataType
typedef struct seqlist
{
//定义顺序表的长度
SLDataType array[n];
//有效数据个数,顺序表中实际存储的元素数量
size_t size;
}seqlist;
动态顺序表(Dynamic Array): 具有动态分配和扩展的特性。最典型的例子是动态数组(Dynamic Array),比如在一些编程语言中的 ArrayList(Java)或 Vector(C++),它们可以根据需要动态调整内存空间,允许在数组末尾高效地进行元素的插入和删除操作。
/顺序表的动态存储
//SLDataType 是一个整数类型的别名,
//DataType仅仅只是作为表示符,无实际作用
typedef int SLDataType
typedef struct seqlist
{
// 指向动态开辟的数组,存储数据元素
SLDataType* array;
//有效数据个数,顺序表中实际存储的元素数量
size_t size;
// 容量空间的大小
size_t capicity;
}seqlist;
顺序表的优点是支持随机访问,元素存储在一块连续的内存空间中,这使得通过索引直接访问元素非常快速。然而,它的缺点是在插入和删除操作时可能需要移动大量元素,导致操作效率降低。
顺序表的基础功能实现(接口实现)
函数声明
#pragma once
// 顺序表的动态存储
//SLDataType 是一个整数类型的别名,
//DataType仅仅只是作为表示符,无实际作用
typedef int SLDataType;
typedef struct SeqList
{
// 指向动态开辟的数组,存储数据元素
SLDataType* a;
//有效数据个数,顺序表中实际存储的元素数量
int size;
// 容量空间的大小
int capicity;
}SL;
void SLInit(SL* ps1);//顺序表的初始化
void SLDestory(SL* ps1);//顺序表的销毁
void CheckCapacity(SL* psl);// 检查空间,如果满了,进行增容
void SLPushBack(SL* psl, SLDataType x); //顺序表的尾插
void SLPrint(SL* ps1);//顺序表的打印
void SLPopBack(SL* ps1);//顺序表的尾删
void SLPushFront(SL* ps1, SLDataType x); //顺序表的头插
void SLPopFront(SL* ps1);//顺序表的头删;
int SLFind(SL* ps1, SLDataType x); //顺序表的查找
void SLInsert(SL* ps1, int pos, SLDataType x); //顺序表在任意位置插入
void SLErase(SL* ps1, int pos); //顺序表在任意位置删除数据
a.顺序表的初始化
//顺序表的初始化
void SLInit(SL* psl)
{
psl->a = NULL;
psl->size = 4; //初态的顺序表的成员为4
psl->capicity = 0; //
}
动态顺序表的结构中包含一个指针,防止指针成为野指针,将指针指向空.
b.顺序表的销毁
void SLDestory(SL* ps1) //顺序表的销毁
{
while (ps1->a != NULL)
{
free(ps1->a);
ps1->a = NULL;
ps1->size = 0;
ps1->capicity = 0;
}
}
c.顺序表的空间扩容
void CheckCapacity(SL* ps1) //检查扩容
{
if (ps1->size == ps1->capacity)
{
int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2; //三目操作符
SLDataType* tmp = (SLDataType*)realloc(ps1->a, sizeof(SLDataType) * newCapacity); //void* realloc (void* ptr, size_t size);
if (tmp == NULL) //判断是否扩容成功
{
perror("realloc fail"); //打印错误原因
return;
}
ps1->a = tmp;
ps1->capacity = newCapacity;
}
}
d.顺序表的尾插
尾插:在顺序表的末尾插入一个元素.
void SLPushBack(SL* ps1, SLDataType x) //顺序表的尾插
{
CheckCapacity(ps1); //检查扩容
ps1->a[ps1->size] = x;
ps1->size++;
}
e.顺序表的尾删
尾删:删除顺序表末尾的元素.
在这里断言是为了防止访问到size为负数的情况,造成越界访问的问题.
void SLPopBack(SL* ps1) //顺序表的尾删
{
assert(ps1->size);
ps1->size--;
}
f.顺序表的头插
void SLPushFront(SL* ps1, SLDataType x) //顺序表的头插
{
CheckCapacity(ps1);
int end = ps1->size-1;
while (end>=0)
{
ps1->a[end + 1] = ps1->a[end];
end--;
}
ps1->a[0] = x;
ps1->size++;
}
g.顺序表的头删
这里断言是为了,防止进行n次头删操作后,顺序表中没有元素了,再次进行头删操作,造成越界访问的问题.
void SLPopFront(SL* ps1) //顺序表的头删
{
assert(ps1->size);
int begin = 1;
while (begin<ps1->size)
{
ps1->a[begin - 1] = ps1->a[begin];
begin++;
}
ps1->size--;
}
h.顺序表的查找
int SLFind(SL* ps1, SLDataType x) //顺序表的查找
{
for (int i = 0; i < ps1->size; i++)
{
if (ps1->a[i] == x)
{
//return i;
printf("%d\n", ps1->a[i]);
}
}
return -1;
}
i,顺序表任意位置插入
把特殊的情况都去除掉,一般这些情况我们都是需要通过if 来判断的,现在就相当于一个暴力的检测
oid SLInsert(SL* ps1, int pos, SLDataType x) //顺序表在任意位置插入
{
CheckCapacity(ps1);
assert(pos>=0&&pos<=ps1-size);
int end = ps1->size - 1;
while (end >= pos)
{
ps1->a[end + 1] = ps1->a[end];
end--;
}
ps1->a[pos] = x;
ps1->size++;
}
j.顺序表任意位置删除
把特殊的情况都去除掉,一般这些情况我们都是需要通过if 来判断的,现在就相当于一个暴力的检测
void SLErase(SL* ps1, int pos) //顺序表在任意位置删除数据
{
assert(pos >= 0 && pos < ps->size);
assert(ps1->size);
int begin = pos;
while (pos<ps1->size)
{
ps1->a[begin-1] = ps1->a[begin];
pos++;
begin++:
}
ps1->size--;
}
完整代码
函数声明
#pragma once
// 顺序表的动态存储
//SLDataType 是一个整数类型的别名,
//DataType仅仅只是作为表示符,无实际作用
typedef int SLDataType;
typedef struct SeqList
{
// 指向动态开辟的数组,存储数据元素
SLDataType* a;
//有效数据个数,顺序表中实际存储的元素数量
int size;
// 容量空间的大小
int capacity;
}SL;
void SLInit(SL* ps1);//顺序表的初始化
void SLDestory(SL* ps1);//顺序表的销毁
void CheckCapacity(SL* psl);// 检查空间,如果满了,进行增容
void SLPushBack(SL* psl, SLDataType x); //顺序表的尾插
void SLPrint(SL* ps1);//顺序表的打印
void SLPopBack(SL* ps1);//顺序表的尾删
void SLPushFront(SL* ps1, SLDataType x); //顺序表的头插
void SLPopFront(SL* ps1);//顺序表的头删;
int SLFind(SL* ps1, SLDataType x); //顺序表的查找
void SLInsert(SL* ps1, int pos, SLDataType x); //顺序表在任意位置插入
void SLErase(SL* ps1, int pos); //顺序表在任意位置删除数据
函数的定义
//定义
#include "seqlist.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void SLInit(SL* ps1)//顺序表的初始化
{
ps1->a = NULL;
ps1->size = 0;
ps1->capacity = 0;
}
void SLDestory(SL* ps1) //顺序表的销毁
{
if(ps1->a != NULL)
{
free(ps1->a);
ps1->a = NULL;
ps1->size = 0;
ps1->capacity = 0;
}
}
void SLPrint(SL* ps1)//顺序表的打印
{
for (int i = 0; i < ps1->size; i++)
{
printf("%d ", ps1->a[i]);
}
printf("\n");
}
void CheckCapacity(SL* ps1) //检查扩容
{
if (ps1->size == ps1->capacity)
{
int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2; //三目操作符
SLDataType* tmp = (SLDataType*)realloc(ps1->a, sizeof(SLDataType) * newCapacity); //void* realloc (void* ptr, size_t size);
if (tmp == NULL) //判断是否扩容成功
{
perror("realloc fail"); //打印错误原因
return;
}
ps1->a = tmp;
ps1->capacity = newCapacity;
}
}
void SLPushBack(SL* ps1, SLDataType x) //顺序表的尾插
{
CheckCapacity(ps1); //检查扩容
ps1->a[ps1->size] = x;
ps1->size++;
}
void SLPopBack(SL* ps1) //顺序表的尾删
{
assert(ps1->size);
ps1->size--;
}
void SLPushFront(SL* ps1, SLDataType x) //顺序表的头插
{
CheckCapacity(ps1);
int end = ps1->size-1;
while (end>=0)
{
ps1->a[end + 1] = ps1->a[end];
end--;
}
ps1->a[0] = x;
ps1->size++;
}
void SLPopFront(SL* ps1) //顺序表的头删
{
assert(ps1->size);
int begin = 1;
while (begin<ps1->size)
{
ps1->a[begin - 1] = ps1->a[begin];
begin++;
}
ps1->size--;
}
int SLFind(SL* ps1, SLDataType x) //顺序表的查找
{
for (int i = 0; i < ps1->size; i++)
{
if (ps1->a[i] == x)
{
//return i;
printf("%d\n", ps1->a[i]);
}
}
return -1;
}
void SLInsert(SL* ps1, int pos, SLDataType x) //顺序表在任意位置插入
{
CheckCapacity(ps1);
int end = ps1->size - 1;
while (end >= pos)
{
ps1->a[end + 1] = ps1->a[end];
end--;
}
ps1->a[pos] = x;
ps1->size++;
}
void SLErase(SL* ps1, int pos) //顺序表在任意位置删除数据
{
assert(ps1->size);
int begin = pos;
while (pos<=ps1->size)
{
ps1->a[pos-1] = ps1->a[pos];
begin++;
pos++;
}
ps1->size--;
}
函数测试
#include<stdio.h>
#include "seqlist.h"
void test1()
{
SL s1;
SLInit(&s1);
SLPushBack(&s1, 1);
SLPushBack(&s1, 2);
SLPushBack(&s1, 3);
SLPushBack(&s1, 4);
SLPushBack(&s1, 5);
SLPushBack(&s1, 6);
/*SLPopBack(&s1);
SLPushFront(&s1, 10);
SLPushFront(&s1, 20);
SLPopFront(&s1);
SLPopFront(&s1);
SLPopFront(&s1);*/
//SLFind(&s1, 4);
//SLErase(&s1, 2);
SLFind(&s1, 4);
//SLPrint(&s1);
SLDestory(&s1);
}
void test2()
{
SL s1;
SLInit(&s1);
SLPushBack(&s1, 1);
SLPushBack(&s1, 2);
SLPushBack(&s1, 3);
SLPushBack(&s1, 4);
SLPushBack(&s1, 5);
SLPushBack(&s1, 6);
//SLFind(&s1, 4);
SLErase(&s1, 3);
//SLErase(&s1, 4);
SLFind(&s1, 4);
SLPrint(&s1);
SLDestory(&s1);
}
int main()
{
//test1();
test2();
}