題目:請手寫出兩種以上排序算法,並分析不同情況下複雜度的變化情況(語言不限)。
思考:
算法分析領域,排序算法應該算是最基礎的,入門就會接觸到的算法。但是在這看似簡單的排序上,卻體現了算法分析最精髓的思想。在排序算法的歷史發展過程當中,有無數大神發明了N多種排序算法,也有給CS的學生提供了大量論文素材。我在這裏僅僅選擇一些簡單的典型進行實現,目的是爲了幫助自己進一步理解其中的核心思想。
最常見的排序莫過於冒泡,快排,歸併了。具體的實現代碼亦有參考一些前輩。歡迎大家一起交流,學習。
C#排序算法實現:
/*****
1.冒泡排序,即兩兩相比較,按大小置換。
分析:在最壞的情況下,即所有的比較之後,都需要進行置換。此時總共經歷的比較次數爲(N-1)K0+(N-2)K1+...+0*KN,K爲循環的趟數。結果爲N*(N-1)/2
在最好的情況下,無需置換,但是比較的次數並沒有減少。該算法的複雜度爲O(N^2)。
*****/
public static void BubbleSort(List<int> list)
{
for (int i = 0; i < list.Count(); i++) {
int temp;
for (int j=i+1; j<list.Count();j++ ) {
if (list[j] < list[i])
{
temp = list[j];
list[j] = list[i];
list[i] = temp;
}
}
}
}
/*****
2.快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的
所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。算法核心的思想是分
治處理,在數組切分的過程中進行遞歸,各子部分完成排序後,數組即完成排序。其複雜度可以達到O(N*LogN)。
*****/
public class SortHelper
{
public static int Division(List<int> list, int left, int right)
{
//首先挑選一個基準元素
int baseNum = list[left];
while (left < right)
{
//從數組的右端開始向前找,一直找到比base小的數字爲止(包括base同等數)
while (left < right && list[right] >= baseNum)
right = right - 1;
//最終找到了比baseNum小的元素,要做的事情就是此元素放到base的位置
list[left] = list[right];
//從數組的左端開始向後找,一直找到比base大的數字爲止(包括base同等數)
while (left < right && list[left] <= baseNum)
left = left + 1;
//最終找到了比baseNum大的元素,要做的事情就是將此元素放到最後的位置
list[right] = list[left];
}
//最後就是把baseNum放到該left的位置
list[left] = baseNum;
//最終,我們發現left位置的左側數值部分比left小,left位置右側數值比left大
//至此,我們完成了第一篇排序
return left;
}
public static void QuickSort(List<int> list, int left, int right)
{
//左下標一定小於右下標,否則就超越了
if (left < right)
{
//對數組進行分割,取出下次分割的基準標號
int i = Division(list, left, right);
//對“基準標號“左側的一組數值進行遞歸的切割,以至於將這些數值完整的排序
QuickSort(list, left, i - 1);
//對“基準標號“右側的一組數值進行遞歸的切割,以至於將這些數值完整的排序
QuickSort(list, i + 1, right);
}
}
}
/*****
3.大名鼎鼎的歸併排序。由馮諾依曼發明,其核心的思想和快排是一樣的,都是分治的原則。
將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。
歸併排序在算法的空間複雜度上較高,時間複雜度上爲O(N*LogN)。
*****/
public class SortHelper
{
//主方法
public static void MergeSortFunction(int[] array, int first, int last)
{
if (first < last) //子表的長度大於1,則進入下面的遞歸處理
{
int mid = (first + last) / 2; //子表劃分的位置
MergeSortFunction(array, first, mid); //對劃分出來的左側子表進行遞歸劃分
MergeSortFunction(array, mid + 1, last); //對劃分出來的右側子表進行遞歸劃分
MergeSortCore(array, first, mid, last); //對左右子表進行有序的整合(歸併排序的核心部分)
}
//return array;
}
//歸併排序的核心部分:將兩個有序的左右子表(以mid區分),合併成一個有序的表
private static void MergeSortCore(int[] array, int first, int mid, int last)
{
int indexA = first; //左側子表的起始位置
int indexB = mid + 1; //右側子表的起始位置
int[] temp = new int[last + 1]; //聲明數組(暫存左右子表的所有有序數列):長度等於左右子表的長度之和。
int tempIndex = 0;
while (indexA <= mid && indexB <= last) //進行左右子表的遍歷,如果其中有一個子表遍歷完,則跳出循環
{
if (array[indexA] <= array[indexB]) //此時左子表的數 <= 右子表的數
{
temp[tempIndex++] = array[indexA++]; //將左子表的數放入暫存數組中,遍歷左子表下標++
}
else//此時左子表的數 > 右子表的數
{
temp[tempIndex++] = array[indexB++]; //將右子表的數放入暫存數組中,遍歷右子表下標++
}
}
//有一側子表遍歷完後,跳出循環,將另外一側子表剩下的數一次放入暫存數組中(有序)
while (indexA <= mid)
{
temp[tempIndex++] = array[indexA++];
}
while (indexB <= last)
{
temp[tempIndex++] = array[indexB++];
}
//將暫存數組中有序的數列寫入目標數組的制定位置,使進行歸併的數組段有序
tempIndex = 0;
for (int i = first; i <= last; i++)
{
array[i] = temp[tempIndex++];
}
}
}
JAVA實現上述三種排序
//1.冒泡
public static void bubbleSort(int[] numbers)
{
int temp = 0;
int size = numbers.length;
for(int i = 0 ; i < size-1; i ++)
{
for(int j = 0 ;j < size-1-i ; j++)
{
if(numbers[j] > numbers[j+1]) //交換兩數位置
{
temp = numbers[j];
numbers[j] = numbers[j+1];
numbers[j+1] = temp;
}
}
}
}
//2.快排
public class SortHelper
{
public static int getMiddle(int[] numbers, int low,int high)
{
int temp = numbers[low]; //數組的第一個作爲中軸
while(low < high)
{
while(low < high && numbers[high] > temp)
{
high--;
}
numbers[low] = numbers[high];//比中軸小的記錄移到低端
while(low < high && numbers[low] < temp)
{
low++;
}
numbers[high] = numbers[low] ; //比中軸大的記錄移到高端
}
numbers[low] = temp ; //中軸記錄到尾
return low ; // 返回中軸的位置
}
public static void quickSort(int[] numbers,int low,int high)
{
if(low < high)
{
int middle = getMiddle(numbers,low,high); //將numbers數組進行一分爲二
quickSort(numbers, low, middle-1); //對低字段表進行遞歸排序
quickSort(numbers, middle+1, high); //對高字段表進行遞歸排序
}
}
}
//3.歸併排序
public class SortHelper
{
public static int[] sort(int[] nums, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
// 左邊
sort(nums, low, mid);
// 右邊
sort(nums, mid + 1, high);
// 左右歸併
merge(nums, low, mid, high);
}
return nums;
}
public static void merge(int[] nums, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
int i = low;// 左指針
int j = mid + 1;// 右指針
int k = 0;
// 把較小的數先移到新數組中
while (i <= mid && j <= high) {
if (nums[i] < nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}
// 把左邊剩餘的數移入數組
while (i <= mid) {
temp[k++] = nums[i++];
}
// 把右邊邊剩餘的數移入數組
while (j <= high) {
temp[k++] = nums[j++];
}
// 把新數組中的數覆蓋nums數組
for (int k2 = 0; k2 < temp.length; k2++) {
nums[k2 + low] = temp[k2];
}
}
}
python實現以上三種算法
#冒泡
def bubble_sort(lists):
# 冒泡排序
count = len(lists)
for i in range(0, count):
for j in range(i + 1, count):
if lists[i] > lists[j]:
lists[i], lists[j] = lists[j], lists[i]
return lists
#快排
def quick_sort(lists, left, right):
# 快速排序
if left >= right:
return lists
key = lists[left]
low = left
high = right
while left < right:
while left < right and lists[right] >= key:
right -= 1
lists[left] = lists[right]
while left < right and lists[left] <= key:
left += 1
lists[right] = lists[left]
lists[right] = key
quick_sort(lists, low, left - 1)
quick_sort(lists, left + 1, high)
return lists
#歸併
def merge(left, right):
i, j = 0, 0
result = []
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
def merge_sort(lists):
if len(lists) <= 1:
return lists
num = len(lists) / 2
left = merge_sort(lists[:num])
right = merge_sort(lists[num:])
return merge(left, right)