面試被虐系列_算法分析篇_排序算法

題目:請手寫出兩種以上排序算法,並分析不同情況下複雜度的變化情況(語言不限)。


思考:
算法分析領域,排序算法應該算是最基礎的,入門就會接觸到的算法。但是在這看似簡單的排序上,卻體現了算法分析最精髓的思想。在排序算法的歷史發展過程當中,有無數大神發明了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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章