1. 概念:
顺序表是用一段 物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
2. 顺序表分类:
(1)静态顺序表:使用定长数组存储。
(2)动态顺序表:使用动态开辟的数组存储。
2.1 静态顺序表
特点: 使用定长数组存储
// 顺序表的静态存储
// 设置顺序表有效元素的个数,即顺序表的长度
#define MAXSIZE 100
// 使用typedef类型定义关键字,给顺序表类型取别名为:DataType
typedef int DataType;
// 将顺序表分装成一个结构体
struct SeqList{
DataType array[MAXSIZE]; // 存储顺序表中的有效元素
int size; // 记录当前顺序表中有效元素的个数
};
2.2 动态顺序表
特点: 使用动态开辟的数组存储
// 顺序表的动态存储
typedef int DataType;
typedef struct SeqList{
DataType* _array; // 保存顺序表中的有效元素
int _capacity; // 顺序表空间大小,capacity(容量)
int _size; // 记录顺序表中有效元素的个数
}SeqList, *PSeqList;
3. 动态顺序表基本操作
SequenceList.h
///////////////////////////////////////////////////
// 这是一个顺序表基本操作的练习代码
///////////////////////////////////////////////////
#ifndef _SEQLIST_H_
#define _SEQLIST_H_
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#if 0
// 静态顺序表
// 顺序表容量不可变,使用定长数组存储
#define MAX_SIZE 100
typedef int SLDataType;
typedef struct SeqList {
SLDataType array[MAX_SIZE]; // 数组长度
size_t size; // 顺序表中有效元素的个数
} SList;
#endif
// 动态顺序表
// 顺序表容量可变,使用动态开辟的数组进行存储
typedef int SLDataType;
typedef struct SeqList {
SLDataType* array; // 纸箱动态开辟的数组
size_t size; // 顺序表中有效元素的个数
size_t capicity; // 容量空间的大小
} SList;
// 初始化顺序表
void SeqListInit(SList* psl, size_t capicity);
// 销毁顺序表
void SeqListDestory(SList* psl);
// 检查顺序表容量
void CheckCapicity(SList* psl);
// 尾插
void SeqListPushBack(SList* psl, SLDataType data);
// 尾删
void SeqListPopBack(SList* psl);
// 头插
void SeqListPushFront(SList* psl, SLDataType data);
// 头删
void SeqListPopFront(SList* psl);
// 查找数据为 data 的元素
int SeqListFind(SList* psl, SLDataType data);
// 任意位置插入
void SeqListInsert(SList* psl, size_t pos, SLDataType data);
// 任意位置删除
void SeqListErase(SList* psl, size_t pos);
// 移除数据为 data 的元素
void SeqListRemove(SList* psl, SLDataType data);
// 修改任意位置的元素
void SeqListModify(SList* psl, size_t pos, SLDataType data);
// 这是一个打印函数
void SeqListPrint(SList* psl);
// 扩展面试题
// 冒泡排序
void SeqListBubbleSort(SList* psl);
// 二分查找
int SeqListBinaryfind(SList* psl, SLDataType data);
// 移除所有值为 data 的元素
void SeqListRemoveAll(SList* psl, SLDataType data);
#endif // _SEQLIST_H_
SequenceList.c
#include "SList.h"
// 初始化顺序表
// 1. 判断顺序表是否存在
// 2. 申请一块内存空间
// 3. 判断空间是否申请成功
// 4. 让顺序表的有效元素个数 size = 0
void SeqListInit(SList* psl, size_t capicity) {
assert(psl);
psl->capicity = capicity;
psl->array = (SLDataType*)malloc(sizeof(SLDataType) * capicity);
assert(psl->array);
psl->size = 0;
}
// 销毁顺序表
// 1. 判断顺序表是否存在,如果顺序表不存在则无需进行销毁操作
// 2. 如果存在则判断顺序表是否为空,如果为空则无需销毁
// 3. 如果顺序表不为空则:
// a. 释放数组空间
// b. 让指针指向空
// c. 将有效元素的个数置为 0
// d. 将顺序表容量置为 0
void SeqListDestory(SList* psl) {
assert(psl);
if (psl->array) {
free(psl->array);
psl->array =NULL;
psl->size = 0;
psl->capicity = 0;
}
}
// 判断顺序表容量是否满
// 1. 判断顺序表是否存在
// 2. 判断有效元素的个数是否 等于 顺序表容量的大小,如果等于则需要进行扩容
// 3. 扩容有很多种办法,一般采用将容量扩大为原来的 2 倍
void CheckCapicity(SList* psl) {
assert(psl);
if (psl->size == psl->capicity) {
psl->capicity *= 2;
psl->array = (SLDataType*)realloc(psl->array, psl->capicity * sizeof(SLDataType));
}
}
// 尾插
// 1. 判断顺序表是否存在
// 2. 判断容量是否满
// 3. 插入数据
// 4. 顺序表有效元素个数加一
void SeqListPushBack(SList* psl, SLDataType data) {
assert(psl);
CheckCapicity(psl);
psl->array[psl->size] = data;
psl->size++;
}
// 尾删
// 1. 判断顺序表是否存在,如果存在判断顺序表有效元素个数是否不为 0
// 2. 有效元素个数减一
void SeqListPopBack(SList* psl) {
assert(psl || psl->size);
psl->size--;
}
// 头插
// 1. 判断顺序表是否存在
// 2. 判断顺序表容量是否满
// 3. 从后向前搬移元素
// 4. 插入元素
// 5. 顺序表有效元素个数加一
void SeqListPushFront(SList* psl, SLDataType data) {
assert(psl);
CheckCapicity(psl);
for (int i = psl->size - 1; i >= 0; --i) {
psl->array[i + 1] = psl->array[i];
}
psl->array[0] = data;
psl->size++;
}
// 头删
// 1. 判断顺序表是否存在
// 2. 顺序表有效元素个数减一
// 3. 从前向后搬移元素
void SeqListPopFront(SList* psl) {
assert(psl);
psl->size--;
for (size_t i = 0; i < psl->size; ++i) {
psl->array[i] = psl->array[i + 1];
}
}
// 查找元素
// 1. 判断顺序表是否存在
// 2. 遍历顺序表,查找值为 data 的元素
// 3. 找到返回该元素的下标,找不到返回 -1
int SeqListFind(SList* psl, SLDataType data) {
assert(psl);
for (size_t i = 0; i < psl->size; ++i) {
if (psl->array[i] == data) {
return i;
}
}
return -1;
}
// 任意位置插入
// 1. 判断顺序表是否存在
// 2. 判断要插入元素的位置是否 小于等于 顺序表有效元素的个数
// 3. 判断容量是否满
// 4. 从后向前搬移元素到要插入元素的位置停止搬移
// 5. 插入元素
// 6. 顺序表有效元素的个数加一
void SeqListInsert(SList* psl, size_t pos, SLDataType data) {
assert(psl || pos <= psl->size);
CheckCapicity(psl);
for (size_t i = psl->size - 1; i >= pos; --i) {
psl->array[i + 1] = psl->array[i];
}
psl->array[pos] = data;
psl->size++;
}
// 任意位置删除
// 1. 判断顺序表是否存在
// 2. 判断要删除的位置是否 小于 顺序表有效元素的个数
// 3. 顺序表有效元素的个数减一
// 4. 从要删除的位置开始进行元素搬移(从前向后搬移)
void SeqListErase(SList* psl, size_t pos) {
assert(psl || pos < psl->size);
psl->size--;
for (size_t i = pos; i < psl->size; ++i) {
psl->array[i] = psl->array[i + 1];
}
}
// 移除值为 data 的元素
// 1. 判断顺序表是否存在
// 2. 查找顺序表中是否有值为 data 的元素
// 3. 找到将该元素的下标记录为 pos
// 4. 删除下标为 pos 的元素
void SeqListRemove(SList*psl, SLDataType data) {
assert(psl);
int pos = SeqListFind(psl, data);
if (pos >= 0) {
SeqListErase(psl, pos);
}
}
// 修改任意位置的元素
// 1. 判断顺序表是否存在
// 2. 判断顺序表是否不为空
// 3. 将要修改位置的元素修改为目标值
void SeqListModify(SList* psl, size_t pos, SLDataType data) {
assert(psl || psl->size);
psl->array[pos - 1] = data;
}
// 冒泡排序
// 1. 判断顺序表是否存在
// 2. 定义一个临时变量
void SeqListBubbleSort(SList* psl) {
assert(psl);
SLDataType tmp;
for (size_t i = 0; i < psl->size - 1; ++i) {
for (size_t j = 0; j < psl->size - 1 - i; ++j) {
if (psl->array[j] > psl->array[j + 1]) {
tmp = psl->array[j];
psl->array[j] = psl->array[j + 1];
psl->array[j + 1] = tmp;
}
}
}
}
int SeqListBinaryfind(SList* psl, SLDataType data) {
assert(psl);
int left = 0;
int right = psl->size - 1;
int mid;
while (left <= right) {
mid = (left + right) / 2;
if (psl->array[mid] < data) {
left = mid + 1;
} else if (psl->array[mid] > data) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
void SeqListRemoveAll(SList* psl, SLDataType data) {
assert(psl);
int count = 0;
int pos = SeqListFind(psl, data);
if (pos >= 0) {
count ++;
}
if (count) {
SeqListErase(psl, pos);
count--;
}
}
void SeqListPrint(SList* psl) {
assert(psl);
for (size_t i = 0; i < psl->size; ++i) {
printf("%d ", psl->array[i]);
}
putchar('\n');
}
main.c
#include "SList.h"
int main() {
SList sl;
SeqListInit(&sl, 10);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPushBack(&sl, 6);
SeqListPushBack(&sl, 7);
SeqListPushBack(&sl, 8);
SeqListPrint(&sl);
SeqListPushFront(&sl, 9);
SeqListPushFront(&sl, 8);
SeqListPushFront(&sl, 7);
SeqListPushFront(&sl, 6);
SeqListPushFront(&sl, 5);
SeqListPushFront(&sl, 5);
SeqListPushFront(&sl, 5);
SeqListPushFront(&sl, 5);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPopBack(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopFront(&sl);
SeqListPopFront(&sl);
SeqListPrint(&sl);
SeqListInsert(&sl, 1, 31);
SeqListPrint(&sl);
SeqListErase(&sl, 2);
SeqListPrint(&sl);
SeqListRemove(&sl, 5);
SeqListPrint(&sl);
SeqListModify(&sl, 3, 66);
SeqListPrint(&sl);
SeqListBubbleSort(&sl);
SeqListPrint(&sl);
printf("%d\n", SeqListBinaryfind(&sl, 6));
SeqListRemoveAll(&sl, 5);
SeqListPrint(&sl);
SeqListDestory(&sl);
return 0;
}

本文介绍了顺序表的概念,包括静态和动态两种类型。动态顺序表使用动态开辟的数组存储,主要讨论了其增、删、改、查等基本操作。
808

被折叠的 条评论
为什么被折叠?



