顺序表的基本操作——插入
首先,静态分配一个顺序表
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 5 // 定义队列的最大长度
typedef struct {
int data[MaxSize];
int length;
}SqList;
然后实现插入方法,for循环
我们提前插入了四个元素,顺序排放
原理是以i为插入位置(位序),e为插入的元素,j为这个顺序表的长度为5,当j所代表的长度大于等于插入位置时,这个循环就会继续,每一轮循环之后j自减1,此时j为5,然后进入循环把原本在位序4的元素放到位序5的位置,然后循环继续到j<i,此时插入元素e,因为位序和数组下标不同,位序比下标多1,最后扩大顺序表的长度+1.
void ListInsert(SqList& L, int i, int e) {
for (int j = L.length; j >= i; j--)
L.data[j] = L.data[j - 1];
L.data[i - 1] = e;
L.length++;
}
但此时代码还不够健壮,我们无法让别人知道自己想插入的操作是否合法,此时要考虑到:
L的范围是(1,length+1),并且插入操作不能违反顺序表的规则,不能隔空插入
我们可以使用bool型来实现这个需求
bool ListInsert(SqList& L, int i, int 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;
}
这样代码就能够拥有足够的“防患于未然性”
插入操作的时间复杂度
关注最深层循环语句的执行次数与问题规模n的关系
L.data[j] = L.data[j - 1];
问题规模n=L.length(表长)
最好情况:新元素插入到表尾,不需要移动元素 i = n+1 ,循环 0 次; 最好时间复杂度 = O(1) 最坏情况:新元素插入到表头,需要将原有的 n 个元素全都向后移动 i=1 ,循环 n 次; 最坏时间复杂度 =O(n); 平均情况:假设新元素插入到任何一个位置的概率相同,即 i=1,2,3,…,length+1 的概率都是p=/n+ 1 i=1 ,循环 n 次; i=2 时,循环 n-1 次; i=3 ,循环 n-2 次 ……i=n+1 时,循环 0 次 平均循环次数 =np+(n-1)p+(n-2)p+……+1 ⋅ p 平均时间复杂度 =O(n)顺序表的基本操作——删除
删掉某一处元素然后把后面的数据往前移一位再让顺序表长度减1
和插入相反
ListDelete(&L,i,&e) :删除操作。删除表 L 中第 i 个位置的元素, 并用 e 返回删除元素的值。//删除
bool ListDelete(SqList &L, int i, int &e) {
if (i<1 || i>L.length) //判断i的范围是否有效
return false;
e = L.data[i - 1]; //将被删除的元素赋值给e
for (int j = i; j < L.length; j++)//将第i个位置后的元素前移
L.data[j - 1] = L.data[j];
L.length--; //线性表长度减1
return true;
}
int main() {
SqList L; //声明一个顺序表
InitList(L); //初始化顺序表
L.data[0] = 3;
L.data[1] = 4;
L.data[2] = 5;
L.data[3] = 6;
L.data[4] = 7;
int e = -1; //用变量e把删除的元素“带回来”
if (ListDelete(L,3,e))
printf("已删除第三个元素,删除元素值为=%d\n", e);
else
printf("位序i不合法,删除失败\n");
return 0;
}
这里的变量e根据顺序表中的数据类型而改变,内存会专门开辟一个空间给e用
依然使用bool类型使代码健壮起来,防止输入不正常值
if语句调用删除语句,意思为删除L顺序表的第三个元素并用e这个元素代表返回
如果在bool中的语句没有返回false,那么就把要删除的值复制给e,然后让后面的每一个值的位序前移一位
然后线性表长度减一,返回true,输出删除语句
(e在删除方法中是一个引用数据类型,它和main函数中的值在内存当中对应同一个值,如果我们在删除方法中没有添加引入符号,就无法使用,这时相当于方法中的e是赋给了内存中的一个新的开辟空间,是main函数中e的一个复制品,没有与main函数中的e联系起来,这时main中的e还是-1)
前面的&L同理,也是复制了一个区域,进行操作,没有与main函数联系,在这一块,有点像Java里面的方法调用
删除是先把前面的元素往前移,然后下一个往前移 插入是先把最后一个元素往后移,再后移其他元素