顺序表的特点
1)随机访问:即可在o(1)时间内找到第i个元素。 {data[i-1]}
2)存储密度高,每个结点只存储数据元素
3)拓展容量不方便
4)插入,删除不方便
一,顺序表的定义
1)静态分配内存空间
//静态分配数组(无法改变顺序表大小)
#define MaxSize 10
typedef struct {
int data[MaxSize];
int length;
}SqlList; //顺序表的定义类型
//初始化一个顺序表
void InitList(SqlList& L) {
for (int i = 0; i <= MaxSize; i++) {
L.data[i] = 0;
//初始化所有数据元素设置为默认初始值0,若不初始化初始值则会出现脏数据。
}
L.length = 0; //顺序表初始长度为0;
}
2),动态分配
//动态分配
#define InitSize 10 //顺序表初始长度
//声明顺序表
typedef struct {
int* data; //指示动态分配数组的指针,指向顺序表中第一个元素的地址
int MaxSize; //最大容量
int length; //当前容量
}SeqList;
//初始化
void InitList(SeqList& L) {
//用malloc函数申请一篇连续的存储空间,其大小为 顺序表初始长度 * 元素数据类型大小
L.data = (int *)malloc(InitSize*sizeof(int));
L.length = 0;
L.MaxSize = InitSize;
}
//增加动态数组长度
void IncreaseSize(SeqList& L, int len) {
int* p = L.data;
L.data = (int*)malloc((L.MaxSize + len) * sizeof(int));
for (int i = 0; i < L.length; i++) {
L.data[i] = p[i]; //将数据复制到新的空间
}
L.MaxSize = L.MaxSize + len;
free(p); //释放内存(老指针指向的内存空间)
//通过分配一块新的空间将原指针指向新的空间,再把久的数据复制到新的空间中即可。
}
int main() {
SeqList L;
InitList(L);
IncreaseSize(L, 5);
return 0;
}
总结
二,顺序表的插入删除(基于静态分配的)
1)插入
ListInsert(&L,i,e):在顺序表L中的第i个位置上插入元素e
逻辑:将第i个元素和之后的元素都往后移动一位,并将新的元素赋值给data[i-1];
代码
void ListInsert(SqList &L, int i, int e) {
for (int j = L.length; j >= 1; j--) {
L.data[j] = L.data[j - 1];
}
L.data[i - 1] = e;
L.length++;
}
*但i的值可能不合法,所以需要对i进行合法性判断。
改进的代码:
bool ListInsert(SqList &L, int i, int e) {
//判断i是否合法
if (L.length >= MaxSize) {
printf("顺序表已经达到最大值");
return false;
}
else if (i<1||i>L.length+1) {
printf("i不合法");
return false;
}
else
{ //将第i个元素和之后的元素都往后移动一位,并将新的元素赋值给data[i-1];
for (int j = L.length; j >= 1; j--) {
L.data[j] = L.data[j - 1];
}
L.data[i - 1] = e;
L.length++;
return true;
}
时间复杂度分析
最好的情况:插入元素在顺序表表尾 i =L.length+1。此时时间复杂度为o(1);
最坏的情况:新元素插在表头i=1。即原表中所有的元素都要后移一位,for循环需要循环n = L.length次。此时时间复杂度为o(n);
平均情况:假设新元素到任何一个位置的概率都是相同的,即i=1,2,3,,,,length+1的概率都是p = 1/(n+1)。
所以平均循环次数 = p*{(n)+(n-1)+......1+0} = {n(n+1)/2}*1/(n+1) = n/2。
2)顺序表的删除
bool ListDelete(SqList &L, int i, int &e) { //这里使用的&L表示在原顺序表的地址上操作,不会复制另一个相同的顺序表
//判断i是否合法
if (i < 1 || i>L.length) {
//i不能<1且不能大于表长
return false;
}
else {
//将删除的元素赋值给e
e = L.data[i - 1];
//顺序表的删除:将i个元素之后的元素都往前移动一位。
for (int j = i; j < L.length; j++) {
L.data[j - 1] = L.data[j];
}
L.length--;
return true;
}
}
删除操作的时间复杂度分析:
最好的情况:删除最后一个元素:for循环执行循环0次,时间复杂度为o(1).
最坏的情况:删除第一个元素:for循环执行循环n = L.length次,时间复杂度为o(n)。
平均的情况:同样删除每个元素的概率为p = 1/n。
则平均的循环次数为 = p*{(n) + (n-1)+......1+0} = (n-1)/2