1.1 顺序表基本概念
顺序表十分简单,简明扼要两句话
- 逻辑上:线性结构
- 物理上:地址连续的存储单元
1.2 顺序表构造
顺序表用结构体来定义
typedef struct
{
ElemType *data;
int length;
}SqList;
顺序表的基本功能如下:
- 初始化
- 定位数据
- 获取长度
- 获取数据
- 插入数据
- 删除数据
- 判空
- 销毁
写成接口,至于参数为啥这么给的,得看后面的具体实现了。
/* base functions */
// init function
bool InitList(SqList *L);
//get length
int Length(SqList L);
//locate data
int LocateElem(SqList L, ElemType e);
//get data
ElemType GetElem(SqList L, int i);
// insert data
bool ListInsert(SqList *L, int i, ElemType e);
// delete data
bool ListDelete(SqList *L, int i, ElemType *e);
//print data
bool PrintList(SqList L);
//wheater list is empty
bool Empty(SqList L);
// clear all the data
bool DestroyList(SqList *L);
1.3 顺序表实现
开始之前, 先为了程序看起来更加人性化,定义一些便于理解的宏变量。
#define ElemType int
#define MaxSize 50
#define InitSize 100
#define bool short
#define true 1
#define false 0
1.3.1 初始化
使用动态申请内存的方式初始化顺序表,若初始化失败则退出。
初始化顺序表长度为0。
bool InitList(SqList *L){
L->data = (ElemType*)malloc(InitSize * sizeof(ElemType));
if(!L->data)
exit(-1);
L->length = 0;
return true;
}
1.3.2 定位数据
根据数据按顺序往下找就完事了,找到了返回位置,找不到就返回0, 注意第一个位置是1。
int LocateElem(SqList L, ElemType e){
int i;
for(int i=0; i < L.length; ++i){
if(L.data[i] == e)
return i+1;
}
return 0;
}
1.3.3 获取长度
int Length(SqList L){
return L.length;
}
1.3.4 获取数据
根据位置返回数据。
ElemType GetElem(SqList L, int i){
return L.data[i];
}
1.3.5 插入数据
根据位置插入数据。
如果位置超过返回,直接返回失败;
从当前顺序表中的最后一个数据的后面(注意顺序表的长度length指向最后一个数据的后面)开始,依次将数据往后挪,直到需要插入的位置为止。
插入后将长度加1。
bool ListInsert(SqList *L, int i, ElemType e){
if(i < 1 || i > L->length+1)
return false;
if(L->length >= MaxSize)
return false;
for(int j=L->length; j >= i; j--)
L->data[j] = L->data[j-1];
L->data[i-1]=e;
L->length++;
return true;
}
1.3.6 删除数据
首先进行合理性检测,检查位置是否在范围内。
将要删除的数据赋值返回。
从删除的位置开始依次将数据往前挪,最后将长度减1。
bool ListDelete(SqList *L, int i, ElemType *e){
if(i < 1 || i > L->length)
return false;
*e = L->data[i-1];
for(int j=i; j < L->length; ++j)
L->data[j-1] = L->data[j];
L->length--;
return true;
}
1.3.7 判空
这里使用了三目运算符。
bool Empty(SqList L){
return L.length == 0?true:false;
}
1.3.8 销毁
释放指针所指的内存即可,注意将指针指空,并把长度设为0。
bool DestroyList(SqList *L){
free((L->data));
L->data = NULL;
L->length = 0;
return true;
}
1.3.9 测试
为了测试方便再加个打印函数。
bool PrintList(SqList L){
for(int i = 0; i < L.length; ++i)
printf("%d ", L.data[i]);
printf("
");
return true;
}
完整测试代码如下,对顺序表进行上述功能测试。
int main(){
SqList L;
ElemType e = 4;
printf("Initialize List...
");
InitList(&L);
printf("Insert data...
");
for(int i = 1; i <= 6; ++i)
ListInsert(&L, i, 2*i);
printf("List==>");
PrintList(L);
printf("Get length...
");
int len = Length(L);
printf("Length==>%d
", len);
printf("locate data...
");
int loc = LocateElem(L, e);
printf("locate at {%d}
", loc);
printf("Get data...
");
int elem = GetElem(L, 1);
printf("Get data==>%d
", elem);
printf("delete data...
");
int del;
ListDelete(&L, loc, &del);
printf("Delete Data==>%d
", del);
printf("List==>");
PrintList(L);
DestroyList(&L);
bool isEmpty = Empty(L);
if(isEmpty) printf("Empty!
");
return 0;
}
1.4 顺序表应用
- 从顺序表删除最小元素(假设唯一)并返回该值,空出的位置由最后一个元素填补。
过于简单不做分析。
bool Del_Min(SqList *L, ElemType *value){
if(!L->length)
return false;
int min = 0;
for(int i = 1; i < L->length; ++i){
if(L->data[min] > L->data[i])
min = i;
}
*value = L->data[min];
L->data[min] = L->data[--L->length];
return true;
}
2.将顺序表逆置,空间复杂度要求O(1)。
分别从头尾开始,交换每个数据。
bool ReverseList(SqList *L){
if(!L->length)
return false;
for(int i=0, j=L->length-1; i < j; ++i,--j){
swap(&L->data[i], &L->data[j]);
}
return true;
}
3.对长度为n的顺序表L, 删除L中所有值为x的数据元素。
方法一:将顺序表中不等于x的值按顺序保存,用k记录不等于k的个数,最后修改长度为k。
bool Del_x_1(SqList *L, ElemType x){
int k = 0;
for(int i = 0; i < L->length; ++i){
if(L->data[i] != x)
L->data[k++] = L->data[i];
}
L->length = k;
return true;
}
方法二:用k记录顺序表中等于k的值,并把不等于k的值向前移动k个位置,最后修改长度为length-k。
bool Del_x_2(SqList *L, ElemType x){
int k = 0;
for(int i = 0; i < L->length; ++i){
if(L->data[i] == x)
k++;
else
L->data[i-k] = L->data[i];
}
L->length -= k;
return true;
}
4.删除有序顺序表中s与t之间(s<t)的所有元。
这个题和第3题有异曲同工之妙,按下不表。
/*
同第三题方法一,将L中小于等于s,大于等于t的值按顺序保存, 用k记录不等于x的个数,最后长度修改为k。
*/
bool Del_s_t_1(SqList *L, ElemType s, ElemType t){
if(s >= t || L->length == 0)
return false;
int k = 0;
for(int i = 0; i < L->length; ++i){
if(L->data[i] <= s || L->data[i] >= t)
L->data[k++] = L->data[i];
}
L->length = k;
return true;
}
/*
由于是有序表,只需要找到大于等于s的第一个元素与大于等于t的第一个元素,将删除这段,只需将后面的元素前移。
*/
bool Del_s_t_2(SqList *L, ElemType s, ElemType t){
if(s >= t || L->length == 0)
return false;
int i, j;
for(i = 0; i < L->length && L->data[i] < s; ++i);
if(i == L->length) return false;
for(j = i; i < L->length && L->data[j] < t; ++j);
if(j == L->length) return false;
for(; j < L->length; ++i, ++j)
L->data[i] = L->data[j];
L->length = i;
return true;
}
6.从有序表中删除重复的元素。
注意是有序表,数据只会连续重复出现。
设置一个flag,用来标记当前数据,把接下的数据