0x00001:顺序表概念
顺序存储表示:将数据元素按其"逻辑先后次序"存放在一组地址连续的存储单元
顺序表:采用了顺序存储结构的线性表,这里可能有些绕
正如上面的图:比如A[0】与A[1]逻辑上相邻,相应的物理位置相邻,因此可以用“物理位置相邻”代表线性表数据元素的逻辑关系
随机存取结构:存数和取数的时候是随机的,不需要顺序遍历或搜索,而是直达。即可在相同时间内()求出任意数据元素的存储地址(存储地址是i的线性函数):LOC(Ai)=LOC(A1)+(i-1)d(每个元素占据d个存取单位比如int ,d=4)
0x00002:顺序表操作
在思考操作之前,先采用"结构体"定义顺序表,为什么用结构体呢?试想这样一个场景,在我们核对学生成绩表("那张纸"可能有空白未填的表格,"当前总格数","实际所用格数"),我们用"食指"定位某一学生的"相关信息"。
typedef struct{
ElemType * data; //"食指"的相对定位作用,这里的ElemType是广义的,具体代表一些数据类型,data作为首地址 // LOC(A1)
int length; //"实际所用格数"
int size; //"当前总格数",形容数据的总容量
} Sqlist; //Sqlist就是这样一种结构体类型,在这里可以理解为"那张纸(表)的样式",也就是顺序表
初始化(链表的一种)顺序表
int initList(Sqlist *L, int size){
L->data = (int *)malloc(sizeof(int)*size);//动态分配的首地址
if(!L->data) return 0;//一般地址非0,若为0,则返回0作为initList的返回值
L->length = 0; //初始化成功
L->size = size;
return 1;
} //只有一个return 值,这样的初始化相当于打印一张"怎样的空表",规定了现有行(size),L就相当于"那张纸"
int initList(Sqlist *L, int size){
L->data = (int *)malloc(sizeof(int)*size);//动态分配的首地址
if(!L->data) return 0;//一般地址非0,若为0,则返回0作为initList的返回值
L->length = 0; //初始化成功
L->size = size;
return 1;
} //只有一个return 值,这样的初始化相当于打印一张"怎样的空表",规定了现有行(size),L就相当于"那张纸"
销毁顺序表
void destoryList(Sqlist *L){
free(L->data); //free(L->data)是收回存储空间
L->data = NULL;//指针指向一个空
L->length = 0;
L->size = 0;
} //此时相当于一张白纸,没有表格,自然无法填充数据
清空顺序表
void clearList(Sqlist *L){
L->length = 0;//只令length为零,下图中并不是十分准确,格子中可能还有数据,但由于指向了开头,原
} //有数据会被替代,所以就是"空表"(空表看的是有效数据长度为0),或说原有数据无 效
Status ListClear(Sqlist *L)//线性表的清空 //第二种写法 Status是状态码
{
int i;
for (i = 0; i < L->cur_length; i++)
L->data[i] = 0; //归零操作,其实归不归0都可,其实没不要处理无效数据
L->cur_length = 0;
return OK;
}
//清空顺序表与销毁顺序表的区别:销毁顺序表需要再次初始化顺序表,但是清空顺序表则不用初始化顺序表。
求表长(元素个数)
int listLength(Sqlist L){ //如是SqList * L 对应L->length
return L.length;
}
取值操作
int getElem(SqList L, int i, int *e){
if(i >= 0 && i < L.length){ //判断合法性,用变量i
*e = L.data[i]; //允许取值,采用指针更灵活,比如int*p=&a; p做为媒介改变a
return 1;
}else{
return 0;
}
}
定位操作
int searchElem(Sqlist L, int e){
int i;
for(i = 0; i < L.length; i++){
if(e == L.data[i]) return i;
}
return 0;
}
算法二:
int LOCElem (Sqlist L,int e){
i=1;
p=L.data //p是LOC(A1)的地址
while((i<L.length)&&(*p++!=e))i++; //*p++ 先*p ,后p++
if (i<=L.length) return i;
else return 0;
}
时间复杂度分析:定位成功时,i++次数最少是0,最多n-1,(0+n-1)*n/2 *(1/n)=n-1/2 (简记就是最大最小的一半),定位不成功为n ,故为O(n).
插入操作
先介绍动态数组扩容的函数
void Increment(Sqlist * L)
{ Sqlist * p;
int i;
p->data=(int *)malloc(sizeof(int)*(size+addsize);//之前宏定义好size ,addsize
if(!p->data) return 0;
for (i=1;i<=L->lenth;i++)
p->data[i-1]=L->data[i-1]; //换容器 数据从L->data到p->data
free(L->data); //释放空间
L->data=p->data; //移交首地址
L->size+=addsize; //容量增加
}
int insertElem(Sqlist *L, int i, int e){ //i与位置差1
if (i<0||i>L->length-1) //非法插入
return 0;
if(L->length == L->size)//顺序表已满
Increment(L); //扩容 在这里L是地址
if(i >= 0 && i <= L->length){ //合法插入
int j;
for(j = L->length - 1; j >= i; j--){ // 0 1 2 ... i-1,i,...j,j+1....size
//插入第一个元素时候不用移动其他元素 L->length-1
if(j >= 0)
L->data[j+1] = L->data[j];//直至i-1个元素给了后一个
}
L->data[i] = e; //插入元素 //0 1 2...i-1(e)......
L->length++; //长度加1
}
删除操作
int deleteElem(SqList *L, int i, int *e){ //灵活性考虑int * e;
if(isEmpty(*L)){
return 0;
} //判断是否为空表
else{
if(i >= 0 && i <= L->length){ //判断合理性
if(i!=L->length)
{*e = L->data[i];
int j;
for(j = i; j < L->length - 1; j++){
L->data[j] = L->data[j+1];
}
}
L->length--;//有效长度减一
return 1;
}
else{
return 0;//错误标识
}
}
}
输出操作
void Printlist(Sqlist *L)
{if(isEmpty(*L)){
return 0;
} //判断是否为空表
else
{
int i=1;
Elemtype *p=L->data; //数组首地址
for(i=1;i<=length-1;i++)
printf("%d",*p++);//逐次打印
}
}
参考:
https://www.cnblogs.com/huster666/p/5625804.html
https://zhuanlan.zhihu.com/p/36429436