大家好,今天我们来给大家分享下数据结构顺序表,以及顺序表增删查改数据的一些的方法。
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表可分为静态顺序表和动态顺序表:
静态顺序表:使用定长数组存储元素。
#define N 7
typedef int SLDataType;
typedef struct SeqlList
{
SLDataType array[N];
size_t size;
}SeqList;
动态顺序表:使用动态开辟的数组存储。
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* array;
size_t size;
size_t capicity;
}SeqList;
顺序表的接口实现:
typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
SLDataType* array; // 指向动态开辟的数组
size_t size ; // 有效数据个数
size_t capicity ; // 容量空间的大小
}SeqList;
// 基本增删查改接口
// 顺序表初始化
void SeqListInit(SeqList* psl, size_t capacity);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* psl);
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);
// 顺序表头删
void SeqListPopFront(SeqList* psl);
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
// 顺序表打印
void SeqListPrint(SeqList* psl);
顺序表初始化:
void SLInit(SL* ps1)
{
assert(ps1);
ps1->a = NULL;
ps1->capacity = 0;
ps1->size = 0;
}
顺序表的检查,容量不够我们就扩容:
void SLCheckCapacity(SL* ps1)
{
assert(ps1);
if (ps1->size == ps1->capacity)
{
int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;
SLDataType* tmp = (SLDataType*)realloc(ps1->a, sizeof(SLDataType) * newCapacity);
if (tmp == NULL)
{
perror("relloc fail");
return;
}
ps1->a = tmp;
ps1->capacity = newCapacity;
}
}
首先我们要确保ps1指针不为空指针,防止出现野指针访问的情况,size是我们保存的数据个数,capacity使是我们数据表的容量,如果二者相等那就代表着我们的顺序表需要扩容。所以我们给tmp开辟空间赋给a,新的容量赋给capacity。
顺序表的打印:
void SLPrint(SL* ps1)
{
assert(ps1);
for (int i = 0; i < ps1->size; i++)
{
printf("%d ", ps1->a[i]);
}
printf("\n");
}
顺序表的销毁:
void SLDestroy(SL* ps1)
{
assert(ps1);
if (ps1->a != NULL)
{
free(ps1->a);
ps1->size = 0;
ps1->capacity = 0;
}
}
注意的是要确保ps1不是空指针,如果为空的话那么就是野指针,野指针访问的话程序就崩溃了。
顺序表头插:
void SLPushFront(SL* ps1, SLDataType x)
{
assert(ps1);
SLCheckCapacity(ps1);
int end = ps1->size - 1;
while (end>=0)
{
ps1->a[end+1] = ps1->a[end];
--end;
}
ps1->a[end] = x;
ps1->size++;
}
我们要想实现头插的话就拿上面的例子,我们想要在这之前插入数据5,我们就得给后面的数据挪动移位,但是我们在挪动之前我们要检查顺序表是否有容量,如果没有就扩容,保证我们后面可以成功的挪动数据。我们挪动数据之后就把5插入进去就可以了,最后表示数据个数的size++。
顺序表尾插:
void SLPushBack(SL* ps1, SLDataType x)
{
assert(ps1);
SLCheckCapacity(ps1);
ps1->a[ps1->size] = x;
ps1->size++;
}
顺序表头删:
void SLPopFront(SL* ps1)
{
assert(ps1);
assert(ps1->size > 0);
int begin = 1;
while (begin < ps1->size)
{
ps1->a[begin-1] = ps1->a[begin ];
++begin;
}
ps1->size--;
}
我们对头删的理解非常的简单,就是我们将后面的数据给前面的数据覆盖掉,而且我们的size–就行了。但是我们这里一定要注意我们的顺序表一定要有数据。
顺序表尾删:
void SLPopBack(SL* ps1)
{
assert(ps1);
assert(ps1->size > 0);
ps1->size--;
}
尾删我们只需要减少数据的个数,比如将最后一个数据去掉就可以了,我们size–的话最后一个数据就访问不到了,但是我们要保证我们的顺序表中有数据。
顺序表任意位置插入数据:
void SLInsert(SL* ps1, int pos, SLDataType x)
{
assert(ps1);
assert(pos >= 0 && pos <= ps1->size);
SLCheckCapacity(ps1);
int end = ps1->size-1;
while (end >= pos)
{
ps1->a[end+1] = ps1->a[end ];
--end;
}
ps1->a[pos] = x;
ps1->size++;
}
pos是我们要插入的数据位置,我们前面的数据保持不变,我们后面的位置要向后挪动一位,我们的end是我们最后一位数据的下标,我们的循环条件使我们的后面数据的坐标大于pos,当我们的end
顺序表任意位置删除数据:
void SLErase(SL* ps1, int pos)
{
assert(ps1);
assert(pos >= 0 && pos <= ps1->size);
int begin = pos+1;
while (begin < ps1->size)
{
ps1->a[begin - 1] = ps1->a[begin];
++begin;
}
ps1->size--;
}
这里和我们头删的逻辑差不多,只需要我们后面的数据向前挪动移位覆盖前面的数据就行了,这里我们pos后面的数据向前挪动移位,将我们的pos位置的数据覆盖就可以了,最后再size–就可以了。
今天的分享就到这里了,感谢大家的支持。