顺序表的应用:
顺序表的结构体:
#define ElemType int
#define Maxsize 50
typedef struct {
ElemType data[Maxsize];
int length;
}Sqlist;
一.题目1:
假设一个线性表采用顺序表表示,设计一个算法,删除其中所有值等于x的元素,要求算法的时间复杂度O(n),空间复杂度为O(1)。
方法1:整体建表法
思路:使用 i 遍历 L。使用 k 记录 L 中元素值等于e的个数。当 i 指向元素值等于 e 时 k+1;但是不移动元素位置,之后i移动到后面不等于e 的元素,则需要前移,L->data[i-k]=L->data[i].最后长度减少 k。
void delNode(Sqlist*& L, ElemType e) {
int k = 0;
for (int i = 0; i < L->length; i++) {
if (L->data[i] != e) {
L->data[k] = L->data[i];
k++;
}
}
L->length = k;
方法2:元素移动法
思路:使用 i 遍历 L。使用 k 记录 L 中元素值等于e的个数。当 i 指向元素值等于 e 时 k+1;但是不移动元素位置,之后i移动到后面不等于e 的元素,则需要前移,L->data[i-k]=L->data[i].最后长度减少 k。
void delNode2(Sqlist*& L, ElemType e) {
int k = 0;
for (int i = 0; i < L->length; i++) {
if (L->data[i] != e) {
L->data[i - k] = L->data[i];
}
else {
k++;
}
}
L->length -= k;
}
二.题目2:
有一个顺序表 L,假设元素类型ElemType 为整型,设计一个尽可能高效的算法,以第一个元素为基准,将所有小于或等于它的元素移动到该基准的前面,将所有大于它的元素移动到该基准的后面。(类似于后面排序中的快速排序的思想,少了一个递归)
方法1:快速排序的思想
思路:将第一个元素存储在 变量 base 中,使用 i 从前面遍历,使用 j 从后面遍历, 当 j 遍历发现一个当前值比 base 大的话,j--;反之比base小,那么 j 不变,将当前 j 的元素放置于 i 的空白位置上,之后从 i 开始,当 i 遍历发现当前值比 base 小时,i++;反之;i不变,将当前 i 的元素放置在 j 的空白位置上,直到i=j,那么就是 base基准元素的位置。
void partition(Sqlist*& L) {
int i = 0;
int j = L->length - 1;
ElemType base = L->data[0];
while (i < j) {
while (i<j && L->data[j]>base)
j--;
L->data[i] = L->data[j];
while (i < j && L->data[i] < base)
i++;
L->data[j] = L->data[i];
}
L->data[i] = base;
}
方法2:元素交换法
思路: 将 L->data[0] 放于 base 上,之后 i 从左往右开始查找, j 从右往左开始查找。 i != j 的时候循环,i 从左往右找一个大于 base的元素,j 从右往左找一个小于 base 的元素,之后将两个交换位置,data[i] 和 data[j] 进行交换。
void swap(ElemType &a, ElemType &b) {
int num;
num = a;
a = b;
b = num;
}
void partition2(Sqlist*& L,ElemType e) {
int i = 0;
int j = L->length - 1;
ElemType base = e;
while (i < j) {
while (i<j && L->data[i]<base)
i++;
while (i<j && L->data[j]>base)
j--;
if (i < j)
swap(L->data[i], L->data[j]);
}
swap(L->data[0], L->data[i]); // 这里不能使用 L->data[i]=0;因为中间元素并没有被寄放
}
三.题目3:
有一个顺序表 L;假设元素类型 ElemType 为整型,设计一个尽可能高效的算法将所有奇数移动到偶数的前面。
方法1:元素交换法;类似于 Example 2的方法,只不过改变了判定条件
void movel(Sqlist*& L) {
int i = 0;
int j = L->length - 1;
while (i < j) {
while (i < j && L->data[i] % 2 != 0)
i++;
while (i < j && L->data[j] % 2 == 0)
j--;
if (i < j)
swap(L->data[i], L->data[j]);
}
}
方法2:区间划分法
思路:将顺序表的前半段作为奇数区间。L->data[0……i] 表示的是奇数区间。i表示的是奇数区间的最后一个元素。起初将 i置为-1,表示奇数区间是空的。然后使用 j从左往右遍历所有的元素,若出现一个奇数,那么 i+1,并且将 L->data[i] 与 L->data[j] 进行交换位置。j继续遍历。
void move2(Sqlist*& L){
int i = -1;
for (int j = 0; j < L->length - 1; j++) {
if (L->data[j] % 2 != 0) {
i++;
if (i != j)
swap(L->data[i], L->data[j]);
}
}
}