1 无序数组的排序——快速排序
1.1 升序排序
一趟排序的思路:
- 选取区间 A 最左边的元素 x 作为基准值;
- 从区间 A 的最右边开始,往左找,碰到第一个比 x 小的元素时停下,把下标记为 j;(基准数在最左边,必须从最右边开始扫描!)
- 从区间 A 的最左边开始,往右找,碰到第一个比 x 大的元素时停下,把下标记为 i;
- 交换 A[i] 和 A[j];
- 继续从 j 往左找,再从 i 往右找,重复上述过程,直到 i 和 j 碰面为止,将 A[i] 与第一个元素 x 交换;
- 将区间 A 分为两段:
[最左边, i-1],[i+1, 最右边] (或[最左边, j-1],[j+1, 最右边] ),重复上述过程。
void QSort (int A[], int low, int high){
if (low >= high)
return;
int i = low, j = high;
int pivot;
将 A 数组中随机一个元素和 A[low] 交换;
pivot = A[low];
while (i != j){
while ((i < j) && (A[j] > pivot))
j--;
while ((i < j) && (A[i] <= pivot))
i++;
if (i < j)
swap(A[i], A[j]);
}
swap(A[low], A[i]);
QSort(A, low, i-1);
QSort(A, i+1, high);
}
1.2 降序排序
一趟排序的思路:
- 选取区间 A 最左边的元素 x 作为基准值;
- 从区间 A 的最右边开始,往左找,碰到第一个比 x 大的元素时停下,把下标记为 j;(基准数在最左边,必须从最右边开始扫描!)
- 从区间 A 的最左边开始,往右找,碰到第一个比 x 小的元素时停下,把下标记为 i;
- 交换 A[i] 和 A[j];
- 继续从 j 往左找,再从 i 往右找,重复上述过程,直到 i 和 j 碰面为止,将 A[i] 与第一个元素 x 交换;
- 将区间 A 分为两段:
[最左边, i-1],[i+1, 最右边] (或[最左边, j-1],[j+1, 最右边] ),重复上述过程。
void QSort (int A[], int low, int high){
if (low >= high)
return;
int i = low, j = high;
int pivot;
将 A 数组中随机一个元素和 A[low] 交换;
pivot = A[low];
while (i != j){
while ((i < j) && (A[j] <= pivot))
j--;
while ((i < j) && (A[i] >= pivot))
i++;
if (i < j)
swap(A[i], A[j]);
}
swap(A[low], A[i]);
QSort(A, low, i-1);
QSort(A, i+1, high);
}
2 有序数组的查找——折半查找(二分查找)
2.1 升序数组的查找
int Search(int A[], int low, int high, int x){
int mid;
while (low <= high){
mid = low + (high - low) / 2;
if (A[mid] > x)
high = mid - 1;
else if (A[mid] < x)
low = mid + 1;
else
return mid;
}
return -1;
}
- 左闭右开写法(
[low, high) ,high 对应的数组元素搜索不到):
int Search(int A[], int low, int high, int x){
int mid;
while (low < high){
mid = low + (high - low) / 2;
if (A[mid] > x)
high = mid;
else if (A[mid] < x)
low = mid + 1;
else
return mid;
}
return -1;
}
2.2 降序数组的查找
int Search(int A[], int low, int high, int x){
int mid;
while (low <= high){
mid = low + (high - low) / 2;
if (A[mid] < x)
high = mid - 1;
else if (A[mid] > x)
low = mid + 1;
else
return mid;
}
return -1;
}
- 左闭右开写法(
[low, high) ,high 对应的数组元素搜索不到):
int Search(int A[], int low, int high, int x){
int mid;
while (low < high){
mid = low + (high - low) / 2;
if (A[mid] < x)
high = mid;
else if (A[mid] > x)
low = mid + 1;
else
return mid;
}
return -1;
}
3 有序数组的合并——归并思想
3.1 归并两个升序数组
int C[n+m];
void UpMerge (int A[], int n, int B[], int m){
int i = j = 0;
int k = 0;
while ((i < n) && (j < m)){
if (A[i] < B[j]){
C[k] = A[i];
i++;
}
else{
C[k] = B[j];
j++;
}
k++;
}
for (; i < n; i++, k++)
C[k] = A[i];
for (; j < m; j++, k++)
C[k] = B[j];
}
3.2 归并两个降序数组
int C[n+m];
void DownMerge (int A[], int n, int B[], int m){
int i = j = 0;
int k = 0;
while ((i < n) && (j < m)){
if (A[i] > B[j]){
C[k] = A[i];
i++;
}
else{
C[k] = B[j];
j++;
}
k++;
}
for (; i < n; i++, k++)
C[k] = A[i];
for (; j < m; j++, k++)
C[k] = B[j];
}
3.3 升序和降序归并为升序
int C[n+m];
void UpMerge (int A[], int n, int B[], int m){
int i = 0;
int j = m;
int k = 0;
while ((i < n) && (j > 0)){
if (A[i] > B[j]){
C[k] = A[i];
i++;
}
else{
C[k] = B[j];
j--;
}
k++;
}
for (; i < n; i++, k++)
C[k] = A[i];
for (; j = 0; j--, k++)
C[k] = B[j];
}
3.4 升序和降序归并为降序
int C[n+m];
void DownMerge (int A[], int n, int B[], int m){
int i = n;
int j = 0;
int k = 0;
while ((i > 0) && (j < m)){
if (A[i] > B[j]){
C[k] = A[i];
i--;
}
else{
C[k] = B[j];
j++;
}
k++;
}
for (; i = 0; i--, k++)
C[k] = A[i];
for (; j < m; j++, k++)
C[k] = B[j];
}
4 数组元素的删除——快慢指针
- 快指针:正常遍历数组元素
- 慢指针:遇到多少个满足条件的元素就滞后于快指针多少个位置,同时能记录删除后需要保存的元素个数
4.1 删除特定元素
4.1.1 无序表中删除所有值为 x 的元素
从线性表中删除所有其值为 x 的元素,要求时间复杂度为 O(n),空间复杂度为 O(1)。
void Delete_x (int A[], int x){
int i;
int j;
for (i = 0, j = 0; i < length; i++){
if (A[i] != x){
A[j] = A[i];
j++;
}
}
length = j;
}
void Delete_x (int A[], int x){
int i;
int j;
for (i = 0, j = 0; i < length; i++){
if (A[i] == x)
j++;
else
A[i-j] = A[i];
}
length = length - j;
}
4.1.2 有序表中删除所有值为 x 的元素
从有序表中删除所有其值为 x 的元素。
void Delete_x (int A[], int x){
int i = 0;
int j = length - 1;
while ((A[i] != x) && (i < length))
i++;
while ((A[j] != x) && (j >= 0))
j--;
int d = j - i + 1;
for (; j < length; j++)
L.data[j - d] = L.data[j];
length = length - d;
}
4.2 删除值为 s 到 t 之间的所有元素
4.2.1 无序表中删除值为 s 到 t 之间的所有元素
从顺序表中删除其值为 s 到 t 之间的所有元素。
void Delete_s_t (int A[], int s, int t){
int i;
int j;
for (i = 0, j = 0; i < length; i++){
if ((A[i] < s) || (A[i] > t)){
A[j] = A[i];
j++;
}
}
length = j;
}
void Delete_x (int A[], int x){
int i;
int j;
for (i = 0, j = 0; i < length; i++){
if ((s <= A[i]) && (A[i] <= t))
j++;
else
A[i-j] = A[i];
}
length = length - j;
}
4.2.2 有序表中删除值为 s 到 t 之间的所有元素
从有序表中删除其值为 s 到 t 之间的所有元素。
void Delete_s_t (int A[], int s, int t){
int i = 0;
int j = length - 1;
while ((A[i] < s) && (i < length))
i++;
while ((A[j] > t) && (j >= 0))
j--;
int d = j - i + 1;
for (; j < length; j++)
L.data[j - d] = L.data[j];
length = length - d;
}
4.3 删除重复元素
4.3.1 有序表中删除所有重复的元素
从有序表中删除所有其值重复的元素,使表中所有元素的值均不相同。
void Delete_Same (int A[]){
int i;
int j;
for (i = 1, j = 0; i < length; i++){
if (A[i] != A[j]){
j++;
A[j] = A[i];
}
}
length = j + 1;
}
void Delete_Same (int A[]){
int prev = A[0];
int i;
int j;
for (i = 1, j = 1; i < length; i++){
if (A[i] != prev){
prev = A[i];
A[j] = A[i];
j++;
}
}
length = j;
}
4.3.2 无序表中删除所有重复的元素
从顺序表中删除所有其值重复的元素,使表中所有元素的值均不相同。
- 解法:若要使时间复杂度为 O(n),则需使用散列表。
(略)
5 数组的相关算法杂例
5.1 数组逆置
void Reverse (int A[], int low, int high){
for (int i = low; i <= low + (high - low) / 2; i++)
swap(A[i], A[high - i]);
}
5.2 求数组的最大和最小元素
#define INT_MAX 0x7FFFFFFF
int Min (int A[], int low, int high){
int A_Min = INT_MAX;
for (int i = low; i <= high; i++){
if (A[i] < D_Min)
A_Min = A[i];
}
return A_Min;
}
#define INT_MIN 0x80000000
int Max (int A[], int low, int high){
int A_Max = INT_MIN;
for (int i = low; i <= high; i++){
if (A[i] > D_Max)
A_Max = A[i];
}
return A_Max;
}
5.3 求多数元素——摩尔投票法
给定一个大小为 n 的整数数组,找出其中所有出现超过 ? n/2 ? 次的元素。
(略)
|