线性表之顺序存储---顺序表
逻辑结构: 线性结构 元素和元素之间 存在1:1
内存空间的天然连续性 逻辑上连续性 映射 顺序表
逻辑结构和行为 (抽象数据类型)
线性表:
存储行为
顺序存储
访问的接口
<1> 初始化的动作
<2> 获取某个位置元素的动作
传入pos,直接访问索引为pos - 1位置的值 ,某个位置找到元素的效率非常高,时间复杂度为O(1)
<3>查找某个元素的位置,时间复杂度为O(n)
<4>插入某个元素在表的某个位置上
要在pos插入元素 [pos ... n] 都往后移动一位 ,内部索引[pos-1...n-1]都往后移动一位,效率不高,时间复杂度为O(n)
<5>删除...
要把pos位置的元素删除 [pos+1 ... n] 往前移动一位,对程序来说,索引为[pos...n-1] 的值都要往前移动一位,效率不高,时间复杂度为O(n)
<6>更新...
传入pos,要更改pos位置的值,只需更改索引为pos-1位置的值, 效率非常高,时间复杂度为O(1)
这些过程中需要注意内部的索引是从0开始的,[0,1,2,...n-1]
而对外接口是从1开始的,[1,2,...n]
三、动态顺序表的设计与实现
静态顺序表:
数组来存储表里的元素
int data[5]; 一旦申请空间,空间个数确定,不能变化,经常会空间不够,不建议使用。
动态顺序表:
动态空间来存储表里的元素 C语言用指针来实现,int *elem用指针来指向动态区
空间不够时,我们可以申请新的空间。
如上图所示,表中只有元素1和2,elem[100]出现越界,为避免此情况,需要长度len
除此之外,len可能比目前的容量还大,需要扩容,所以我们需要知道容量capacity
故要想维护一个动态顺序表,我们需要有这三个元素。
代码:
sqList.h
#ifndef SQLIST_H
#define SQLIST_H
/*
* 动态顺序表,使用顺序存储,数据容量动态增加
* 外部按照[1,...,n]的方式进行访问
* 内部使用C语言实现,索引从0开始
*/
typedef int Element;//这个元素不一定是int,用typedef重命名,以后假如存的不是int,改一下就可以,这样就不用通篇都要改
//动态顺序表必要的三个元素是一个整体,整体用struct结构体,最好也用typedef重命名一下
typedef struct {
Element *elem; //顺序表元素空间首地址
int len; //记录顺序表的元素个数
int capacity; //记录顺序表的容量
}SqList;
//第一件事情初始化,先产生这个表
SqList *creatSqList(int n); //产生容量为n个元素的顺序表
void releaseSqList(SqList *seq); //释放这个顺序表
//获取顺序表中某个位置上元素的值
//在哪个seq表中获取,返回是否找到(有可能越界没找到,故函数为int类型,返回-1出错,返回0则找到),很显然返回这个值,值用指针反向更新
int getSqList(SqList *seq,int pos,Element *ele);
//查找顺序表中某个元素的位置
//在哪个seq表中找哪个元素ele(这里的ele不用更新,故不用指针)
int locateSqList(SqList *seq,Element ele);
//向顺序表指定位置上插入元素
int insertSqList(SqList *seq,int pos,Element ele);
//显示顺序表里的元素
void showSqList(SqList *seq);
//从顺序表中指定位置处删除元素
//从哪个seq表中删除某个位置pos的元素
int deleteSqList(SqList *seq,int pos);
#endif //SQLIST_H
sqList.c
#include <stdlib.h>
#include <stdio.h>
#include "sqList.h"
SqList *creatSqList(int n){
SqList *seq = (SqList *)malloc(sizeof(SqList));//申请空间,为了安全,前面加强制类型转换
// 判断申请是否成功
if(seq == NULL){
printf("malloc error\n");
return NULL;
}
//初始化顺序表里的每个元素
seq->elem = (Element *)malloc(sizeof(Element)*n);//申请n个元素的空间
//初始化,给每个元素赋值0
for(int i =0;i<n;++i){
seq->elem[i]=0;
}
seq->len = 0;//长度最开始为0
seq->capacity = n;//容量为n
return seq;
}
//先释放里面的,再释放外面的空间
void releaseSqList(SqList *seq){
//首先判断用户传来的seq是非空的
if(seq){
//如果不空,判断不空的seq里的元素是否申请
if(seq->elem){
free(seq->elem);//释放元素
}
free(seq);//释放表
}
}
/*[1,2,...,seq->len] pos的用户访问范围,对外
*
*/
int getSqList(SqList *seq,int pos,Element *ele){
//pos必须在1到len之间,否则pos位置无效,返回-1
if(pos < 1 || pos > seq->len){
printf("pos invalid!\n");
return -1;
}
*ele = seq->elem[pos-1];//反向更新
return 0;//成功返回0
}
//找元素,顺序表天然就是一个数组,for循环遍历
int locateSqList(SqList *seq,Element ele){
for(int i=0;i<seq->len;++i){
if(seq->elem[i]==ele){
return i+1;//找到了,返回位置
}
}
return 0;//没找到
}
/*插入操作:
*外部范围:[1,...seq->len]
* 插入行为:可以在表的最后插入,范围是[1,...seq->len+1]
*/
int insertSqList(SqList *seq,int pos,Element ele){
//判断插入范围是否正确
if(pos < 1 || pos > seq->len+1){
printf("pos invalid!\n");
return -1;
}
//判断容量是否满足
if(seq->len +1 > seq->capacity){ //容量越界,就扩容
printf("enlarge!\n");
//扩容要申请一个新空间,临时申请一个tmp,一般扩到原来的2倍
Element *tmp = (Element *)malloc(sizeof(Element) * seq->capacity * 2);
//判断扩容是否成功
if(tmp == NULL){
printf("malloc error\n");
return -1;
}
//成功扩容之后
//把老空间的值拷贝给新空间
for(int i = 0;i < seq->len;++i){
tmp[i] = seq->elem[i];
}
seq->capacity = seq->capacity * 2;//容量更新
free(seq->elem);//释放掉原来的老元素
seq->elem = tmp;//指针指向新空间
}
//将pos位置后面的元素向后移一位,从seq->len逐步靠近pos的位置(从最后一个元素后移,往前操作,直到pos)
for(int i = seq->len -1;i >= pos-1;--i){
seq->elem[i+1] = seq->elem[i];//后移一位
}
seq->elem[pos-1]=ele;//插入新元素ele
seq->len++;//更新表长
return 0;
}
//显示seq就是一个遍历
void showSqList(SqList *seq){
for(int i=0;i < seq->len;++i){
printf("%d\t",seq->elem[i]);
}
printf("\n");
}
int deleteSqList(SqList *seq,int pos){
if(pos < 1 || pos > seq->len){
printf("pos invalid!\n");
return -1;
}
//从pos+1位置到最后的位置处,向前赋值
for(int i = pos; i < seq->len; ++i){
seq->elem[i-1] = seq->elem[i];//将后一个位置的元素前移
}
seq->len--;//更新表长
return 0;
}
main.c
#include <stdio.h>
#include "sqList.h"
int main(){
int n = 5;
//生成一个顺序表
SqList *sqList = creatSqList(n);
//操作这个顺序表
for(int i = 0; i < n; ++i){
insertSqList(sqList,i+1,i+100);
}
showSqList(sqList);
insertSqList(sqList,3,300);
showSqList(sqList);
insertSqList(sqList,9,1000);
showSqList(sqList);
printf("--------------------\n");
deleteSqList(sqList,4);
showSqList(sqList);
releaseSqList(sqList);
return 0;
}
在CLion上的运行结果,如下图: