1. 程式人生 > >(面試必知)必知必會的氣泡排序和快速排序

(面試必知)必知必會的氣泡排序和快速排序

本博文介紹兩個最常被提起的排序演算法:氣泡排序和快速排序。氣泡排序是入門排序演算法,思路比較常規,但確是最耗時的排序演算法,所以聽到氣泡排序笑一笑就好了,千萬不要拿來裝B。另一個是被譽為面試必知演算法快速排序,以及針對陣列特徵進行優化的“隨機快排”和“平衡快排”。

氣泡排序

(一)概念及實現

氣泡排序的原理:重複的遍歷要排序的陣列,每次遍歷過程中從頭至尾比較兩個相鄰的元素,若順序錯誤則交換兩個元素。

具體如下(實現為升序)

設陣列為a[0n]

1.從頭至尾比較相鄰的元素。如果第一個元素比第二個元素大,就交換。

2.重複步驟1,每次遍歷都將冒出一個最大數,直到排序完成。

實現程式碼:

        public static void Sort<T>(IList<T> arr) where T : IComparable<T>
        {
            if (arr == null)
                throw new ArgumentNullException("arr");

            int length = arr.Count();
            if (length > 1)
            {
                bool isSorted = false;

                // 迴圈n-2次,每迴圈完一次,冒泡的一個最大值
                for (int i = 0; i < length - 1; i++)
                {
                    // 如果一次迴圈沒有發生交換,則說明剩餘的元素是有序的。
                    isSorted = true;

                    for (int j = 1; j <= length - 1 - i; j++)
                    {
                        // 相鄰兩個元素比較,將較大的交換到右邊arr[j]中
                        if (arr[j - 1].CompareTo(arr[j]) > 0)
                        {
                            isSorted = false;

                            Swap(arr, j - 1, j);
                        }
                    }

                    if (isSorted)
                        break;
                }
            }
        }

        /// <summary>
        /// 陣列元素交換
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr">陣列</param>
        /// <param name="i">交換元素1</param>
        /// <param name="j">交換元素2</param>
        static void Swap<T>(IList<T> arr, int i, int j)
        {
            T temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }

示例:

89,-7,999,-89,7,0,-888,7,-7

排序的過程:

-7 89 -89 7 0 -888 7 -7 [999]

-7 -897 0 -888 7 -7 [89] 999

……

……

-888 [-89] -7 -7 0 7 7 89 999

(二)演算法複雜度

1.時間複雜度:O(n^2)

氣泡排序耗時的操作有:比較 + 交換(每次交換兩次賦值)。時間複雜度如下:

1)最好情況:序列是升序排列,在這種情況下,需要進行的比較操作為(n-1)次。交換操作為0次。即O(n)

2)最壞情況:序列是降序排列,那麼此時需要進行的比較共有次。交換運算元和比較運算元一樣。即

O(n^2)

3)漸進時間複雜度(平均時間複雜度):O(n^2)

2.空間複雜度:O(1)

從實現原理可知,氣泡排序是在原輸入陣列上進行比較交換的(稱“就地排序”),所需開闢的輔助空間跟輸入陣列規模無關,所以空間複雜度為:O(1)

(三)穩定性

氣泡排序是穩定的,不會改變相同元素的相對順序。

(四)優化改進

1.有序優化:在進行相鄰元素比較時,可以記錄下迴圈中沒有發生交換的多個連續索引對(起始索引和結束索引),在下次輪詢時直接對有序區間的最大值進行比較。

2.雙向冒泡:參考資料過程中看到了雙向冒泡,不同之處在於“從左至右與從右至左兩種冒泡方式交替執行”,個人認為不能提高演算法效率並且增加程式碼複雜度。

快速排序

(一)概念及實現

思想:分治策略。

快速排序的原理:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序。

"保證列表的前半部分都小於後半部分"就使得前半部分的任何一個數從此以後都不再跟後半部分的數進行比較了,大大減少了數字間的比較次數。

具體如下(實現為升序)

設陣列為a[0n]

1.陣列中找一個元素做為基準(pivot),通常選陣列的第一個數。

2.對陣列進行分割槽操作。使基準元素左邊的值都小於pivot,基準元素右邊的值都大於等於pivot

3.pivot值調整到分割槽後的正確位置。

4.將基準兩邊的分割槽序列,分別進行步驟1~3。(遞迴)

5.重複步驟1~4,直到排序完成。

實現程式碼:

        /// <summary>
        /// 快速排序
        /// </summary>
        /// <param name="arr">待排序陣列</param>
        /// <param name="left">左邊界索引</param>
        /// <param name="right">右邊界索引</param>
        /// <param name="SelectPivot">選擇基準元素委託,並且將基元素與左邊界元素交換</param>
        private static void DoSort<T>(IList<T> arr, int left, int right
            , Action<IList<T>, int, int> SelectPivot) where T : IComparable<T>
        {
            count++;
            if (left < right)
            {
                // 選擇基準元素委託
                if (SelectPivot != null)
                    SelectPivot(arr, left, right);

                // 臨時儲存基準元素,以讓其他陣列元素來填充該位置
                T pivot = arr[left];
                int low = left;
                int high = right;

                while (low < high)
                {
                    // 從右向左找第一個小於 基數 的數  
                    while (low < high && arr[high].CompareTo(pivot) >= 0)
                        high--;
                    if (low < high)
                        arr[low++] = arr[high];

                    // 從左向右找第一個大於等於 基數 的數
                    while (low < high && arr[low].CompareTo(pivot) < 0)
                        low++;
                    if (low < high)
                        arr[high--] = arr[low];
                }
                arr[low] = pivot;   // 此時 low = high

                // 兩個分割槽遞迴。基準元素無需在參與下一次快速排序
                // 加入if判斷可以減少50%-55%的遞迴次數
                if (left < low - 1)
                    DoSort<T>(arr, left, low - 1, SelectPivot);
                if (low + 1 < right)
                    DoSort<T>(arr, low + 1, right, SelectPivot);
            }
        }

   特別注意在遞迴前的判斷語句,他減少了50%-55%的遞迴次數。

示例:

89,-7,999,-89,7,0,-888,7,-7

排序的過程:

(以陣列第一個元素做為基準值。藍色代表被分割槽出來的子陣列,綠色代表本次分割槽基準值)

image

(二)演算法複雜度

1.時間複雜度:O(nlog2n)

快速排序耗時的操作有:比較 + 交換(每次交換兩次賦值)。時間複雜度如下:

1)最好情況:選擇的基準值剛好是中間值,分割槽後兩分割槽包含元素個數接近相等。因為,總共經過x次分割槽,根據2^x<=n得出x=log2n,每次分割槽需用n-1個元素與基準比較。所以O(nlog2n)

2)最壞情況:每次分割槽後,只有一個分割槽包含除基準元素之外的元素。這樣就和氣泡排序一樣慢,需O(n^2)

3)漸進時間複雜度(平均時間複雜度):O(nlog2n)

2.空間複雜度:O(1)

從實現原理可知,快速排序是在原輸入陣列上進行比較分割槽的(稱“就地排序”),所需開闢的輔助空間跟輸入陣列規模無關,所以空間複雜度為:O(1)

(三)穩定性

快速是不穩定的,會改變相同元素的相對順序。如示例,以第一個基準89排序時,首先將最後一個元素-7移到了第一個分割槽的第一個位置上。改變了與第二個-7的相對順序。

相關推薦

面試氣泡排序快速排序

本博文介紹兩個最常被提起的排序演算法:氣泡排序和快速排序。氣泡排序是入門排序演算法,思路比較常規,但確是最耗時的排序演算法,所以聽到氣泡排序笑一笑就好了,千萬不要拿來裝B。另一個是被譽為的面試必知演算法快速排序,以及針對陣列特徵進行優化的“隨機快排”和“平衡快排”。 氣泡排序 (一)概

氣泡排序快速排序java實現

氣泡排序 Bubble Sort 在基於 “交換” 進行排序的方法中,氣泡排序是比較簡單的一種。 /** * 氣泡排序 * 時間複雜度為O(n^2),空間複雜度為O(1) */ public static int[] bubbleSort(int[] array){

歸併排序快速排序三十二

        上節我們學習了氣泡排序和希爾排序,本節我們繼續學習歸併排序和快速排序。         1、歸並排序:將兩個或兩個以上的有序序列

【資料結構與演算法】內部排序之四:歸併排序快速排序含完整原始碼

前言      之所以把歸併排序和快速排序放在一起探討,很明顯兩者有一些相似之處:這兩種排序演算法都採用了分治的思想。下面來逐個分析其實現思想。歸併排序實現思想       歸併的含義很明顯就是將兩個或者兩個以上的有序表組合成一個新的有序表。歸併排序中一般所用到的是2-路歸併

算法系列排序演算法中篇--歸併排序快速排序

在算法系列(三)排序演算法上篇 一文中,介紹了氣泡排序,插入排序和選擇排序演算法。這篇文章繼續講解排序演算法。 概述 氣泡排序,插入排序和選擇排序演算法這些演算法的時間複雜度都是O(N^2),是否有更

排序演算法之氣泡排序快速排序Java版

轉自:http://www.cnblogs.com/0201zcr/p/4763806.html  作者:Whywin 1、氣泡排序 演算法如下(排序後,由小到大排列): /** * 氣泡排序 * 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。

1.交換排序氣泡排序快速排序

交換排序的基本思想:兩兩比較關鍵字,當兩個記錄的次序相反時進行交換,直到完成排序為止。 (1)氣泡排序 基本思想:相鄰關鍵字間的比較和位置的交換,使關鍵字最小的記錄如氣泡一般逐漸往上“漂浮”直至“水面

交換排序氣泡排序快速排序

交換排序:根據序列中兩個元素關鍵字的比較結果來對換這兩個記錄在序列中的位置。 氣泡排序的基本思想:假設待排序元素表長為size,從前往後(或從後往前)兩兩比較相鄰元素的值,若為逆序(即arr[j]>arr[j+1]),則交換他們,直至整個元素表有序。 // 氣

面試|理解堆排序

本文將闡述堆和堆排序的基本原理,通過本文將瞭解到以下內容: 堆資料結構的定義 堆的陣列表示 堆的調整函式 堆排序實踐 1.堆的簡介 堆是電腦科學中的一種特別的樹狀資料結構。若是滿足以下特性,即可稱為堆:給定堆中任意節點P和C,若P是C的母節點,那麼P的值會小於等於C的值。若母節點的值恆小於等於子節點的值,

java線程基礎鞏固---waitsleep的本質區別是什麽,深入分析面試常見問題

是什麽 執行 就是 需要 喚醒 直接 png java線程 解釋 對於wait和sleep貌似都會阻塞線程,但是它們確實是很大的區別的,所以下面一點點來探討: 區別一、Sleep()是線程裏面的方法,而Wait()是Object類的方法。這個比較簡單,直接看代碼便知:

作業系統面試寶典

面試試題 1 解釋作業系統原理中的作業、程序,執行緒、管程各自的定義。 答案: 作業:使用者在一次解題或一個事務處理過程中要求計算機系統所作的集合。它包括使用者程式、所需要的資料及控制命令等。作業是一系列有序的步驟組成的。 程序:一個程

常用設計模式總結面試常問

Singleton(單例模式) 一句話總結:一個類在Java虛擬機器中只有一個物件,並提供一個全域性訪問點。 生活中例子:太陽、月亮、國家主席等。 解決什麼問題:物件的唯一性,效能浪費太多。 專案裡面怎麼用:資料庫連線物件,屬性配置檔案的讀取物件。 模式結構:分為餓漢式和懶漢式(

【javaweb】請求轉發重定向面試經常問

重定向 //之前的寫法 response.setStatus(302); response.setHeader(“Location”, “login_success.html”); //重定向寫法: 重新定位方向 引數即跳轉的位置 response.sendRe

java基礎知識總結面試常遇

redis基本知識: 1.資料型別:字串,列表(lists),雜湊表(hashs),集合(sets),有序集合(sorts sets) 2.redis服務端的預設埠是:6379 3.redis的主從同步(對提高讀取效能非常有益): 主從伺服器的配置 4.

同源、跨域、jsonp面試常問

          提到跨域,就不得不說一下同源策略,同源策略是瀏覽器的一種安全策略,也就說a網站不能隨便讀取b網站的內容,試想一下,如果網站之間都可以隨便讀取互相的檔案,比如一個黑客程式,他利用IF

二叉排序樹的建立查詢面試常考

在眾多查詢方法中,二叉排序樹查詢是比較好的一種查詢,其效率比順序查詢,折半查詢,插值查詢,斐波納契查詢等都要好。 二叉排序樹的建立 首先要了解而叉排序樹如何建立,給定一組陣列,建立一個而叉排序樹 #include <iostream>

集合深淺拷貝以及經常遇到的坑面試常問

之前只是知道淺拷貝只是拷貝地址,深拷貝是內容的拷貝,具體怎麼使用,卻不是很清楚。這篇文章對深淺拷貝做了通俗易懂的講解,還列出了作者踩過的坑,希望對讀者有一些幫助。 引言 根據拷貝內容的不同,分為深淺拷貝 深拷貝:指標賦值,且內容拷貝 淺拷貝:只是簡單的指

新手看——JAVA排序詳解(氣泡排序插入排序)

對於排序,它一直不厭其煩的出現在企業面試初級工程師的筆試題中,不管是氣泡排序還是插入排序,我們經常會在在初級面試題中遇見,就好像它已成為一種面試的標準。而對於程式設計師來說,基本排序就真的這麼重要嗎?當然不,作為一個老司機的我們已經知道,對於新手很心累的各種

Spring MVC相關內容整理面試福利哦

最近有同事問了我很多關於spring mvc的問題,大抵都是用於面試的,平時沒人關注這些的,有些問題把我問的也是一愣一愣的,今天有空順便就整理了下涉及到spring的相關資料問題,不管簡單或者無聊,算是給你們的福利吧。 一、第一個當然是關於spirng mvc的請求解析流程了,說實話,這個需

Handler面試詳解

                                Handler總結多篇部落格,吸取之精華!          一、首先先來上一段Handler的原理:         當應用程式啟動時,Android首先會開啟一個主執行緒 (也就是UI執行緒) , 主執