1.概念
顺序表是用一段 物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用数组存 储。在数组上完成数据的增删查改。
2.分类
顺序表一般可以分为:2.1 静态顺序表:使用定长数组存储元素
这样会造成空间给多了浪费,给少了不够用。于是我们使用一种动态开辟的数组储存
2.22. 动态顺序表:使用动态开辟的数组存储
3.实现
3.1 构建一个结构体
typedef int SLDatatype; typedef struct SeqList { SLDatatype* a; int size; // 存储的有效数据的个数 int capacity; // 容量 }SL;
3.2顺序表初始化和销毁
//初始化 void SLInit(SL* psl) { psl->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4); if (psl->a == NULL) { perror("malloc fail"); return; } psl->capacity = 4; psl->size = 0; }
//销毁 void SLDestroy(SL* psl) { free(psl->a); psl->a = NULL; psl->size = 0; psl->capacity = 0; }
3.3顺序表的打印
//打印 void SLprintf(SL* psl) { int i = 0; for (i = 0; i < psl->size; i++) { printf("%d ", psl->a[i]); } printf("\n"); printf("Size:%d\n", psl->size); }
3.4顺序表任意位置插入
//是否要增容 void SLCheck(SL* psl) { if (psl->size == psl->capacity) { SLDatatype* tmp = (SLDatatype*)realloc(psl->a, sizeof(SLDatatype) * psl->capacity * 2); if (tmp == NULL) { perror("realloc fail"); return; } psl->a = tmp; psl->capacity *= 2; } }
//任意位置插入 void SLInsert(SL* psl, int pos, SLDatatype x) { //检查是否要增容 SLCheck(psl); int end = 0; end = psl->size - 1; while (end >= pos) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[pos] = x; psl->size++; }
3.5顺序表任意位置删除
//任意位置删除 void SLErase(SL* psl, int pos) { int start = pos + 1; while (start < psl->size) { //相当与直接覆盖 psl->a[start - 1] = psl->a[start]; ++start; } psl->size--; }
3.6顺序表的查找
//查找并返回下标 int SLFind(SL* psl, SLDatatype x) { assert(psl); int i = 0; for (i = 0; i < psl->size; i++) { if (x == psl->a[i]) { return i; } } }
3.7顺序表的修改
//pos是要修改的下标,x是要修改的数字 void SLModify(SL* psl, int pos, SLDatatype x) { assert(psl); assert(0 <= pos && pos < psl->size); psl->a[pos] = x; }
4.完整的代码
#pragma once #include<stdio.h> #include<assert.h> #include<string.h> #include<stdlib.h> typedef int SLDatatype; typedef struct SeqList { SLDatatype* a; int size; // 存储的有效数据的个数 int capacity; // 容量 }SL; //顺序表初始化 void SLInit(SL* psl); //顺序表初销毁 void SLDestroy(SL* psl); //顺序表初打印 void SLprintf(SL* psl); //检查空间,如果满了则进行增容 void SLCheck(SL* psl); //顺序表查找 int SLFind(SL* psl, SLDatatype x); //顺序表在POS中插入一个数 void SLInsert(SL* psl, int pos, SLDatatype x); //顺序表在POS中删除一个数 void SLErase(SL* psl, int pos); //顺序表修改 void SLModify(SL* psl, int pos, SLDatatype x)
上面是SeqList.h
SeqList.c
#include"SeqList.h" //˳ʼ void SLInit(SL* psl) { psl->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4); if (psl->a == NULL) { perror("malloc fail"); return; } psl->capacity = 4; psl->size = 0; } //˳ void SLDestroy(SL* psl) { free(psl->a); psl->a = NULL; psl->size = 0; psl->capacity = 0; } void SLprintf(SL* psl) { int i = 0; for (i = 0; i < psl->size; i++) { printf("%d ", psl->a[i]); } printf("\n"); printf("Size:%d\n", psl->size); } void SLCheck(SL* psl) { if (psl->size == psl->capacity) { SLDatatype* tmp = (SLDatatype*)realloc(psl->a, sizeof(SLDatatype) * psl->capacity * 2); if (tmp == NULL) { perror("realloc fail"); return; } psl->a = tmp; psl->capacity *= 2; } } int SLFind(SL* psl, SLDatatype x) { assert(psl); int i = 0; for (i = 0; i < psl->size; i++) { if (x == psl->a[i]) { return i; } } } void SLInsert(SL* psl, int pos, SLDatatype x) { SLCheck(psl); int end = 0; end = psl->size - 1; while (end >= pos) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[pos] = x; psl->size++; } void SLErase(SL* psl, int pos) { int start = pos + 1; while (start < psl->size) { psl->a[start - 1] = psl->a[start]; ++start; } psl->size--; } void SLModify(SL* psl, int pos, SLDatatype x) { assert(psl); assert(0 <= pos && pos < psl->size); psl->a[pos] = x; }
5.总结
上面便是我今天讲的全部内容,还有许多不足希望多多指正
下面给大家个问题
1. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。2. 增容一般是呈 2 倍的增长,势必会有一定的空间浪费。例如当前容量为 100 ,满了以后增容到 200,我们再继续插入了 5 个数据,后面没有数据插入了,那么就浪费了 95 个数据空间。如何减少空间复杂度呢?