冒泡,選擇,插入排序

冒泡排序:(bubble sort)

冒泡排序的本質在於交換,即每次通過交換的方式把當前剩餘元素的最大值移動到某一端,而當剩餘元素減少爲零時,排序結束。爲了使排序的過程更加清晰,舉一個例子。

現在有一個數組a,其中有五個元素,分別爲a[0] = 3、a[1] = 4、a[2] = 1、a[3] = 5、a[4] = 2。現在要求把它們按從小到大的順序排列。下面的過程中,每趟將最大數交換到最右邊,即升序排列。

(1)      第一趟。

a[0]與a[1]比較(3和4比較),a[1]大,因此不動,此時序列爲{3,4,1,5,2};

3

4

1

5

2

 

a[1]與a[2]比較(4和1比較),a[1]大,因此把a[1]和a[2]交換,此時序列爲{3,1,4,5,2};

3

1

4

5

2

 

a[2]與a[3]比較(4和5比較),a[3]大,因此不動,此時序列爲{3,1,4,5,2};

3

1

4

5

2


a[3]與a[4]比較(5與2比較),a[4]大,因此把a[3]和a[4]交換,此時序列爲{3,1,4,2,5};

3

1

4

2

5

 

到此,第一趟排序結束,共進行了四次比較。

(2)      第二趟。

a[0]和a[1]比較(3與1比較),a[0]大,因此把a[0]和a[1]交換,此時序列爲{1,3,4,2,5};

1

3

4

2

5

 

a[2]和a[1]比較(4和3比較),a[2]大,因此不動,此時序列爲{1,3,4,2,5,};

1

3

4

2

5

 

a[3]和a[2]比較(2和3比較),a[2]大,因此把a[2]和a[3]交換,此時序列爲{1,3,2,4,5};

1

3

2

4

5

 

到此,第二趟排序結束,共進行了三次比較。

(3)      第三趟。

a[0]與a[1]比較(1和3比較),a[1]大,因此不動,此時序列爲{1,3,2,4,5};

1

3

2

4

5

 

a[1]與a[2]比較(3和2比較),a[1]大,因此把a[1]和a[2]交換,此時序列爲{1,2,3,4,5};

1

2

3

4

5

 

到此,第三趟排序結束,共進行了兩次比較。

(4)      第四趟。

a[0]與a[1]比較(1和2比較),a[1]大,因此不動,此時序列爲{1,2,3,4,5};

1

2

3

4

5

 

終於,我們用四趟排序結束這個過程。前面介紹過,冒泡排序的本質在於交換,因此先掌握如何交換兩個數。一般來說,交換兩個數需要藉助中間變量,即先定義一箇中間變量temp,存放其中一個數a,然後再把另一個數b賦給已經轉移值的a,最後再把存有a的中間變量temp賦值給b,這樣a和b就完成了交換。下面這段代碼能實現這個功能

#include <iostream>

using namespace std;

int main()

{

         inta = 1, b = 2;

         cout<< a << " " << b << endl;

         inttemp = a;

         a= b;

         b= temp;

         cout<< a << " " << b << endl;

         return0;

}輸出結果:

                            12

                            21

然後來實現冒泡排序。從上面的例子可以看出,整個過程執行n-1趟,每一趟從左到右依次比較相鄰的兩個數,如果大的數在左邊,則交換這兩個數的位置。當該趟結束後,該趟最大數被移動到當前剩餘數的最右端。具體實現如下:

#include <iostream>

using namespace std;

int main()

{

         inta[100];

         intn;                                                                                             //n是要進行排列的元素個數。

         cin>> n;

         for(int i = 0; i < n; i++)

         {

                   cin>> a[i];                                                                //輸入要排序的元素。

         }

         for(int i = 1; i < n; i++)                                           //進行n-1趟排序。

                   for(int j = 0; j < n - i; j++)

                   {

                            if(a[j] > a[j + 1])                                    //這裏變成大於號,元素排序就可以單調遞減。

                            {

                                     inttemp = a[j];

                                     a[j]= a[j + 1];

                                     a[j+ 1] = temp;

                            }

                   }

         for(int i = 0; i < n; i++)

                   cout<< a[i] << " ";

         cout<< endl;

         return0;

}

選擇排序(selectsort)

選擇排序也是最簡單的算法之一,這裏介紹最常用的簡單選擇排序。簡單選擇排序是指,對一個序列A中元素的A[0]至A[n](假設數組A中有n個元素),令i從0到n-1枚舉,進行n-1趟操作,每趟從待排序部分[i,n-1]中選擇最小的元素,令其與待排序部分的第一個元素交換,這樣元素A[i]就會與當前有序區間[0,i-1]形成新的有序區間[0,i]。於是在n趟操作後,所有的元素就會是有序的。

下面

A[0]

···

A[i-1]

A[i]

A[i+1]

···

A[n-1]

灰色部分是已經排好的次序,而當前要做的是從[i,n-1]中選出最小值,與A[i]交換。交換之後如下圖所示:

A[0]

···

A[i-1]

A[i]

A[i+1]

···

A[n-1]

於是算法的邏輯就很明顯了:總共需要進行n趟操作(1≤i≤n),每趟操作選出待排序的部分[i,n-1]中最小的元素,令其與A[i]交換。因此總複雜度爲O(n2),選擇排序具體的實現代碼:

#include<iostream>

using namespace std;

int main()

{

    int a[10] = { 1, 4, 3, 2, 7, 6, 5, 8, 9, 10};

    for (int i = 0; i < 10; i++)

    {

        int k = i;

        for (int j = i; j < 10; j++)

        {

            if (a[k] < a[j])

                k = j;

        }

        int temp = a[k];

        a[k] = a[i];

        a[i] = temp;

    }

    for (int i = 0; i < 10; i++)

        cout << a[i] << "";

    cout << endl;

    return 0;

}

另外,有同學認爲A[k]與A[i]交換的條件是I != k,事實上在具體實現時,即便I = k成立,也可以進行交換(並不會額外的消耗很多時間),因此上面的代碼中並沒有加上這個交換的條件。

總的來說,冒泡排序和選擇排序在某種程度上還是很相似的,都需要進行交換這一步驟。但是我個人比較喜歡選擇排序,因爲它在比較元素的時候邏輯相對簡單。並且單從代碼量上來看,選擇排序也更加簡潔。

插入排序(insert sort)

插入排序也是基礎的一類排序方法,相對於前兩種方法稍微有點難,反正我是這樣覺得。這裏介紹最直觀的直接插入排序

直接插入排序是指,對於序列A的n個元素A[0]至A[n-1],令i從1到n-1枚舉,進而進行n-1趟操作。假設某一趟操作是,序列A的前i-1個元素已經有序,而A[i]至A[i-1]還未有序,那麼該趟從已有序範圍中尋找某個位置j,使得將A[i]插入位置j之後,範圍[0,i]有序。下面舉一個例子來說明這個過程。

假設現在有一個序列A[6]={5,2,4,6,3,1},共有六個元素。因此需要進行6-1趟操作,所以分別將2、4、6、3、1插入初始已有序部分{5}中。

(1)      第一趟:當前已有序部分爲{5},需要把元素A[1]插入已有序部分中。顯然插入位置爲1號位,插入後已有序部分爲{2,5}。

2

5

4

6

3

1

 

(2)      第二趟:當前已有序部分爲{2,5},需要把元素A[2]插入已有序部分中,顯然插入位置爲2號位,插入後已有序部分爲{2,4,5}。

2

4

5

6

3

1

 

(3)      第三趟:當前已有序部分爲{2,4,5},需要把元素A[3]插入已有序部分中,顯然插入位置爲4號位(元素5後面,此時不需要改動元素位置),插入後已有序部分爲{2,4,5,6}。

2

4

5

6

3

1

 

(4)      第四趟:當前已有序部分爲{2,4,5,6,},需要把元素A[4]插入已有序部分中,顯然插入位置爲2號位,插入後已有序部分爲{2,3,4,5,6}.

2

3

4

5

6

1

 

(5)      第五趟:當前已有序部分爲{2,3,4,5,6},需要把元素A[5]插入已有序部分中,顯然插入位置爲1號位,插入後已有序部分爲{1,2,3,4,5,6},至此,五趟操作完畢,算法結束。

1

2

3

4

5

6

 

通過上面的例子,應當對直接插入排序的過程有一個清晰的瞭解。可以看到,插入排序是將待插入元素一個個初始已有序部分中的過程,而插入位置的選擇遵循了使插入後仍然保持有序的原則,具體做法是從後往前枚舉已有序部分來確定插入位置。下面給出具體實現:

#include <iostream>

using namespace std;

int main()

{

         inta[5] = { 3, 4, 5, 8, 1 };

         for(int i = 1; i < 5; i++)

         {

                   inttemp = a[i], j = i;

                   while(j > 0 && temp < a[j - 1])

                   {

                            a[j]= a[j - 1];

                            j--;

                   }

                   a[j]= temp;

         }

         for(int i = 0; i < 5; i++)

                   cout<< a[i] << " ";

         cout<< endl;

         return0;

}

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