排序和搜索
1.所謂的內排序是指所有的數據已經讀入內存。在內存中進行排序的算法;同時,內排序也一般假定所有用到的輔助空間可以直接存在於內存中。與之對應,另一類排序稱爲外排序,即內存中無法保存全部數據,需要進行磁盤訪問,每次讀入部分數據到內存進行排序。
合併排序:利用分而治之的思想,對兩部分非別進行排序,排序完成後,在將各自排序好的兩個部分合並還原成一個有序結構;算法的時間複雜度爲O(nlog n)。
//合併函數
void Merge(int *_Array, int p, int q, int r) {// p:第0個;r:第n-1個數,q:第(r + p) / 2個數
int len1 = q - p + 1;
int len2 = r - q;
int *L = new int[len1 + 1];//用動態數組儲存左邊的數
int *R = new int[len2 + 1];//用動態數組儲存右邊的數
for (int i = 0; i < len1; i++) {// 把Array數組左邊的數放入L數組
L[i] = _Array[p + i];
}
for (int j = 0; j < len2; j++) {// 把Array數組右邊的數放入R數組
R[j] = _Array[q + 1 + j];
}
L[len1]=R[len2]=INT_MAX; //定義無窮大
int i = 0, j = 0;
for (int k = p; k <= r; k++) {
if (L[i] < R[j]) {//小的放左邊,大的放右邊
_Array[k] = L[i];
i++;
}
else {
_Array[k] = R[j];
j++;
}
}
}
// 歸併排序
void MergeSort(int _Array[], int p, int r) {
if (p < r) {//p:第0個;r:第n-1個數。數組至少要有兩個數據
int q;
q = (r + p) / 2;//拆分兩組
MergeSort(_Array , p , q);//拆分第0個到第 (r + p) / 2個 ,即拆分左半部分
MergeSort(_Array , q+1 , r);//拆分第(r + p) / 2個到第r個 ,即拆分右半部分
Merge(_Array , p , q , r);//調用合併函數,從第0個到第n-1個排好
}
}
快速排序:隨機選定一個元素作爲軸值,利用該軸值將數據分爲左右兩個部分,左邊元素都比軸值小,右邊元素都比軸值大,但他們不是完全排序的,在此基礎上,分別對左右兩堆遞歸調用快速排序。算法的時間複雜度爲O(nlog n),在最壞的情況下爲O(n^2),額外空間複雜度O(log n)。
//快速排序
void quick_sort(int s[], int l, int r)
{
if (l < r)
{
//Swap(s[l], s[(l + r) / 2]); //將中間的這個數和第一個數交換 參見注1
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j] >= x) // 從右向左找第一個小於x的數
j--;
if(i < j)
s[i++] = s[j];
while(i < j && s[i] < x) // 從左向右找第一個大於等於x的數
i++;
if(i < j)
s[j--] = s[i];
}
s[i] = x;
quick_sort(s, l, i - 1); // 遞歸調用
quick_sort(s, i + 1, r);
}
}
堆排序:每次將剩餘的最大元素移動到數組的最右邊。算法的時間複雜度爲O(nlog n),空間複雜度O(1)。
//堆排序函數
void HeapSort(int a[],int length)
{
int temp;
BuildMaxHeap(a,length);
for (int i = length - 1; i >= 1; i--)
{
//交換根節點和數組的最後一個節點
temp = a[i];
a[i] = a[0];
a[0] = temp;
MaxHeapify(a, 0, 0, i-1);//維護從下標爲i-1到0的子數組
}
}
桶排序和基數排序:不需要進行數據之間的兩輛比較,但是需要事先知道數組的一些具體情況。桶排序適用於知道待排序數組大小範圍的情況,其特性在於將數據根據其大小,放入合適的桶中,再依次從桶中取出,形成有序序列。基數排序,進行了K次桶排序。
void radixsort(int data[], int n) //基數排序
{
int d = maxbit(data, n);
int tmp[n];
int count[10]; //計數器
int i, j, k;
int radix = 1;
for(i = 1; i <= d; i++) //進行d次排序
{
for(j = 0; j < 10; j++)
count[j] = 0; //每次分配前清空計數器
for(j = 0; j < n; j++)
{
k = (data[j] / radix) % 10; //統計每個桶中的記錄數
count[k]++;
}
for(j = 1; j < 10; j++)
count[j] = count[j - 1] + count[j]; //將tmp中的位置依次分配給每個桶
for(j = n - 1; j >= 0; j--) //將所有桶中記錄依次收集到tmp中
{
k = (data[j] / radix) % 10;
tmp[count[k] - 1] = data[j];
count[k]--;
}
for(j = 0; j < n; j++) //將臨時數組的內容複製到data中
data[j] = tmp[j];
radix = radix * 10;
}
}
快速選擇算法:利用快速排序的思想,時間複雜度是O(n)。
二分查找:算法複雜度爲O(logn)。
int binarySearch(int *array, int left, int right, int value){
if(left>right){
return -1;
}
int mid = right - (right - left)/2;
if(array[mid] == value){
return mid;
} else if(array[mid] < value){
return binarySearch(array,mid+1,right, value);
} else {
return binarySearch(array, left, mid-1, value);
}
}