实现线性表 增删改查 等基本操作
当数据结构是线性结构时,我们可以用顺序表或者是链表实现,此处我们先讨论顺序表的一些基本操作
首先为了便于程序的演示以及说明,我们先定义相应的数据结构如下:
typedef struct Vector {
int size, length; //顺序表的总体大小以及现有长度
int *data; //data指向存储数据数组的首地址
} Vector; //因类似于C++中的vector向量,因此我们以vector为名
一 线性表的初始化以及删除
- 在初始化时,我们首先初始化线性表的大小和长度并以此大小申请内存数组空间
- 删除时操作更简单,直接释放对应的数组空间以及Vector结构体空间
对应代码如下:
#include <iostream>
using namespace std;
typedef struct Vector {
int size, length;
int *data;
} Vector;
void init(Vector *vector, int size) {
vector->size = size;
vector->length = 0;
vector->data = (int*)malloc(sizeof(int) * size);
}
void clear(Vector *vector) {
free(vector->data);
free(vector);
}
int main() {
Vector *a = (Vector *)malloc(sizeof(Vector));
init(a, 100); //这里我们先初始化线性表的大小为100
clear(a);
return 0;
}
二 线性表的插入及扩容操作
在插入元素时需要提前进行两方面的预判
- 当前插入元素的位置是否合法?
- 顺序表是否已满?若已满,此时需要先进性扩容操作,增大顺序表的大小
此外 需要注意的是:应从后向前逐步将元素后移,顺序不可颠倒,否则将覆盖有效数字,破坏顺序表
对应代码如下:
void expand(Vector *vector) { //扩容顺序表,默认当顺序表满时,顺序表大小翻倍
int *old_data = vector->data;
vector->size *= 2;
vector->data = (int *)malloc(sizeof(int) * vector->size);
for (int i = 0; i < vector->length; i++)
vector->data[i] = old_data[i];
free(old_data);
}
bool insert(Vector *vector, int loc, int value) { //将数字value插入顺序表的第value号位置 (下标从0开始)
if (loc < 0 || loc > vector->length) return false; //插入位置非法,返回false,插入失败
if (vector->length >= vector->size) expand(vector); //若顺序表已满,执行扩容操作
for (int i = vector->length; i > loc; i--)
vector->data[i + 1] = vector->data[i];
vector->data[loc] = value;
vector->length++;
return true;
}
代码说明:
- 在插入元素时,可以在顺序表的最前最后或者中间位置插入,所以合法的 location ∈ \in ∈ [0, vector->length]
- 当vector->length == vector->size时,顺序表满;扩容时,先暂存元顺序表数组首地址,之后申请一片新的大小为原来两倍的数组空间,将原来的元素依次复制过来即可,vector->size更新为原来的两倍。
- 设将要插入的位置为
i
i
i,顺序表的长度为
n
n
n,则原来第
i
i
i 号到最后的第
n
−
1
n-1
n−1号元素都要向后移动一个单位。
总共有n + 1个位置可以插入,每个位置插入元素的可能性相同均为 1 n + 1 {\frac{1} {n + 1}} n+11,在第 i i i位插入元素,需要移动元素的次数为 n − i n - i n−i,因此插入一个元素,需要移动元素的次数为: 1 n + 1 ∗ ∑ i = 0 n i {\frac{1} {n + 1}} * {\sum_{i = 0}^{n}} i n+11∗∑i=0ni = 1 n + 1 {\frac{1} {n + 1}} n+11 * n ( n + 1 ) 2 {\frac{n(n + 1)}{2}} 2n(n+1) = n 2 \frac{n} {2} 2n
换句话说,插入一个元素,平均下来需要移动一半元素 !
三 线性表的查找以及删除操作
线性表中元素的查找,直接遍历顺序表即可,若当前元素等于要查找的元素值,返回元素对应下标。
删除元素时,输入元素在顺序表中的下标,删除对应位置元素即可。由此可见元素的查找以及删除操作一般是配套使用的。
对应代码如下:
//删除loc处的元素
bool delete_node(Vector *vector, int loc) {
if (loc < 0 || loc >= vector->length) return false;
for (int i = loc; i < vector->length - 1; i--)
vector->data[i] = vector->data[i + 1];
vector->length--;
return true;
}
//找到值为value元素的位置
int search(Vector *vector, int value) {
for (int i = 0; i < vector->length; i++) {
if (vector->data[i] == value) return i;
}
return -1;
}
代码说明:
- 删除元素之前同样要判断删除元素的位置是否合法,删除元素所处的合法位置 loc ∈ \in ∈ [0, vector->length - 1]
- 设将要删除的位置为
i
i
i,顺序表的长度为
n
n
n,则原来第
i
+
1
i + 1
i+1 号到最后的第
n
−
1
n-1
n−1号元素都要向前移动一个单位。
总共有 n n n个位置可以删除,每个位置删除元素的可能性相同均为 1 n {\frac{1} {n}} n1,删除第 i i i位元素,需要移动元素的次数为 n − i − 1 n - i - 1 n−i−1,因此插入一个元素,需要移动元素的次数为: 1 n ∗ ∑ i = 0 n − 1 i {\frac{1} {n}} * {\sum_{i = 0}^{n - 1}} i n1∗∑i=0n−1i = 1 n {\frac{1} {n}} n1 * n ( n − 1 ) 2 {\frac{n(n - 1)}{2}} 2n(n−1) = n − 1 2 \frac{n - 1} {2} 2n−1
同样,换句话说,删除一个元素,平均下来也需要移动一半元素 !
四 线性表的遍历输出
线性表的线性输出比较简单,直接展示代码如下:
//打印输出顺序表中的元素,行末不要输出多余的空格
void print(Vector *vector) {
for (int i = 0; i < vector->length; i++) {
if (i) printf(" ");
printf("%d", vector->data[i]);
}
printf("\n");
}
五 线性表基本操作练习题
题意如下:
对应实现代码如下:
#include <iostream>
using namespace std;
//顺序表结构体
typedef struct Vector {
int length, size; //顺序表的长度以及大小
int *data; //指向数组的指针
}Vector;
//顺序表的初始化以及删除
void init(Vector *vector, int init_size) {
vector->length = 0;
vector->size = init_size;
vector->data = (int *)malloc(sizeof(int) * init_size);
}
void clear(Vector *vector) {
free(vector->data);
free(vector);
}
//插入操作以及顺序表的扩建
void expand(Vector *vector) {
int *old_data = vector->data;
vector->size *= 2;
vector->data = (int *)malloc(sizeof(int) * vector->size);
for (int i = 0; i < vector->length; i++)
vector->data[i] = old_data[i];
free(old_data);
}
bool insert(Vector *vector, int loc, int value) {
if (loc < 0 || loc > vector->length) return false;
if (vector->length >= vector->size) expand(vector);
for (int i = vector->length; i > loc; i--)
vector->data[i + 1] = vector->data[i];
vector->data[loc] = value;
vector->length++;
return true;
}
//删除loc处的元素
bool delete_node(Vector *vector, int loc) {
if (loc < 0 || loc >= vector->length) return false;
for (int i = loc; i < vector->length - 1; i--)
vector->data[i] = vector->data[i + 1];
vector->length--;
return true;
}
//找到值为value元素的位置
int search(Vector *vector, int value) {
for (int i = 0; i < vector->length; i++) {
if (vector->data[i] == value) return i;
}
return -1;
}
//打印输出顺序表中的元素
void print(Vector *vector) {
for (int i = 0; i < vector->length; i++) {
if (i) printf(" ");
printf("%d", vector->data[i]);
}
printf("\n");
}
int main() {
Vector *a = (Vector *)malloc(sizeof(Vector));
init(a, 20);
int m = 0;
scanf("%d", &m);
while (m--) {
int t;
scanf("%d", &t);
switch(t) {
case 1: {
int loc, value;
scanf("%d %d", &loc, &value);
if (insert(a, loc, value)) printf("insert success\n");
else printf("insert failed\n");
break;
}
case 2: {
int loc;
scanf("%d", &loc);
if (delete_node(a, loc)) printf("delete success\n");
else printf("delete failed\n");
break;
}
case 3: {
int value;
scanf("%d", &value);
int index = search(a, value);
if (index + 1) printf("find success, index = %d\n", index);
else printf("find failed\n");
break;
}
case 4: {
print(a);
break;
}
default: {
printf("something wrong\n");
}
}
}
clear(a);
return 0;
}
/* 对应输入输出
9
1 0 1
insert success
1 5 2
insert failed
1 1 2
insert success
1 2 3
insert success
3 2
find success, index = 1
2 2
delete success
2 9
delete failed
3 3
find failed
4
1 2
*/
加油! 路漫漫其修远兮,吾将上下而求索!
最后,对于这次的武汉肺炎,希望科学家们早点找到新型冠状病毒的疫苗,天佑中华,天佑武汉!! 祈祷!!