歸併排序
時間複雜度O(N*logN),額外空間複雜度O(N),實現可以做到穩定性
#include <cstdio>
#include <cstdlib>
void merge(int A[], int L, int mid, int R)//兩個數組的合併過程,其中要注意的是要合併的兩個數組分別一定是有序的
{
int i = L, j = mid + 1, k = 0;
int *help = (int*)malloc(sizeof(int)*(R - L + 1));//輔助數組
while (i <= mid&&j <= R)
{
if (A[i] < A[j]) //那邊數組數值小放入輔助數組help當中
{
help[k++] = A[i++];
}
else
{
help[k++] = A[j++];
}
}
while (i <= mid)//其餘兩個while只會實現一個,那個數組沒有放入help數組當中,循環放入
{
help[k++] = A[i++];
}
while (j <= R)
{
help[k++] = A[j++];
}
for (int i = 0; i < k; i++)//最後將輔助數組help當中的數值放入到當前A[]數組的當前排序區域
{
A[L + i] = help[i];
}
}
void sortprosess(int A[], int L, int R)
{
if (L == R)//遞歸邊界 如果左邊等於右邊直接返回
{
return;
}
int mid = L + (R - L) / 2;
sortprosess(A, L, mid);//遞歸的過程就是不斷的二分
sortprosess(A, mid + 1, R);
merge(A, L, mid, R);
}
void mergeSort(int A[], int n)
{
if (n == 0 || n == 1)
{
return;
}
else
{
sortprosess(A, 0, n - 1);
}
}
int main()
{
int A[] = { 32, 34, 65, 21, 23, 22, 11, 9, 8, 6, 4, 3, 2 };
for (int i = 0; i < 13; i++)
{
printf("%d ", A[i]);
}
printf("\n");
mergeSort(A, 13);
for (int i = 0; i < 13; i++)
{
printf("%d ", A[i]);
}
printf("\n");
return 0;
}
小和問題:
在一個數組中, 每一個數左邊比當前數小的數累加起來, 叫做這個數組的小和。 求一個數組
的小和。
例子:
{1,3,4,2,5}
1左邊比1小的數,沒有
3左邊比3小的數,1
4左邊比4小的數,1,3
2左邊比2小的數,1
5左邊比5小的數,1,3,4,2
因此小和爲1+1+3+1+1+3+4+2=16
還是需要強調的是merge合併過程中合併的兩個數組分別是有序的!!因此在merge過程中只要左邊數組有數值比右邊小,右數組比較的該數值以及該數值之後的數值一定都大於左邊當前比較的數值
//merge中的第一個循環
while (i <= mid&&j <= R)
{
if (A[i] < A[j])//根據歸併排序性質,合併過程中的兩個數組一定是有序的;
//那麼只要A[i]<A[j]則A[j]~A[R]必然大於A[i],即當前位置的小和爲
//A[i]*(R-j+1);
{
sum += A[i] * (R - j + 1);//小和數
help[k++] = A[i++];
}
只要設置一個全局變量記錄所有小和的和即可
上邊代碼的小和
{ 32, 34, 65, 21, 23, 22, 11, 9, 8, 6, 4, 3, 2 }
32左邊比32小的數, 沒有;
34左邊比34小的數, 32;
65左邊比65小的數, 32、 34;
23左邊比23小的數, 21;
22左邊比22小的數,21; 因此小和爲 32+32+34+21+21=140
#include <cstdio>
#include <cstdlib>
int sum = 0;//----------------設置全局變量記錄所有的小和
void merge(int A[], int L, int mid, int R)
{
int i = L, j = mid + 1, k = 0;
int *help = (int*)malloc(sizeof(int)*(R - L + 1));//輔助數組
while (i <= mid&&j <= R)
{
if (A[i] < A[j])
{
sum += A[i] * (R - j + 1);//記錄當前合併數組過程中的小和數
help[k++] = A[i++];
}
else
{
help[k++] = A[j++];
}
}
while (i <= mid)
{
help[k++] = A[i++];
}
while (j <= R)
{
help[k++] = A[j++];
}
for (int i = 0; i < k; i++)
{
A[L + i] = help[i];
}
}
void sortprosess(int A[], int L, int R)
{
if (L == R)
{
return;
}
int mid = L + (R - L) / 2;
sortprosess(A, L, mid);
sortprosess(A, mid + 1, R);
merge(A, L, mid, R);
}
void mergeSort(int A[], int n)
{
if (n == 0 || n == 1)
{
return;
}
else
{
sortprosess(A, 0, n - 1);
}
}
int main()
{
int A[] = { 1, 3, 4, 2, 5 };
for (int i = 0; i < 5; i++)
{
printf("%d ", A[i]);
}
printf("\n");
mergeSort(A, 5);
for (int i = 0; i < 5; i++)
{
printf("%d ", A[i]);
}
printf("\n");
printf("%d\n", sum);//輸出小和
return 0;
}