1. 程式人生 > >資料結構——排序與查詢(3)——氣泡排序(C++實現)

資料結構——排序與查詢(3)——氣泡排序(C++實現)

交換排序演算法

所謂交換,意思是說根據所給的序列,對其中的兩個元素進行大小比較,若為逆序,那麼我們就交換它。這樣就達到了排序的目的。接下來介紹最簡單的交換排序——氣泡排序。

氣泡排序的原理

氣泡排序的原理很簡單,它反覆遍歷要排序的列表,比較每對相鄰的專案,如果它們的順序錯誤則交換它們。 重複遍歷列表,直到不需要交換,這表示列表已排序。我們可以從後往前(或者從前往後)兩兩比較相鄰的元素,若為逆序,則交換他們。(這跟插入排序不同,插入排序一開始是區域性排序,也就是說一開始排完的數字的位置,有可能下次排序的時候還會變動,而氣泡排序是全域性排序,一旦位置排好就是固定位置)。
舉個例子來說說氣泡排序的步驟:
假設我們對 5 1 4 2 8

這一組資料進行排序,那麼第一趟的過程如下:
在這裡插入圖片描述
如果這個時候我們將圖倒過來看,就會發現5就像從底下往上冒的水泡,這也是為什麼這個演算法稱為氣泡排序的原因。
好,接下來我們看看第二趟會發生什麼:
在這裡插入圖片描述
那麼我們對5排完之後,應該對誰排序呢?當然是對 1 了,因為我們是遍歷要排序的序列的,得按順序來。於是發現1比後面的都小,於是不用交換,保留原地不動。(這個時候就注意了,1是不動沒錯,那麼就意味著它真的不動?當然不是,它還是得跟其他元素遍歷比較,否則我怎麼知道它比其他的元素都要小?所以這是一種對時間資源的浪費)。
排完之後,對4排序,重複第一步的演算法,如圖所示;
排完之後,對2排序,(實際上這個時候,我們的排序已經完成,但是對於演算法來說它並不知道此時的序列已經處於有序狀態
,因此它依舊執行比較操作,依舊執行遍歷,直到所有要排序的元素都已經處於有序狀態)
下面貼一個動態圖(來自維基百科),直觀的描述這一過程:
在這裡插入圖片描述

氣泡排序的C++實現

下面我們用C++語言來寫一下這個演算法

#include <iostream>
#include <vector>
using namespace std;
/*函式宣告*/
void bubbleSort(vector<int> &vec);
void swap(int &i, int &j);
/*主函式*/
int main() {
	vector<int> vec;
	cout << "請輸入待排序的序列" << endl;
	//假設我們對5個數進行排序
	for (int i = 0; i < 5; i++) {
		int n;
		cin >> n;
		vec.push_back(n);
	}
	
	bubbleSort(vec);//使用希爾排序對vector進行排序
	//輸出結果
	cout << "氣泡排序後:" << endl;
	for (int k = 0; k < vec.size(); k++) {
		cout << vec[k] << " ";
	}
	return 0;
}
//氣泡排序的實現,由小到大
void bubbleSort(vector<int> &vec) {
	//遍歷序列中的每個元素
	for (int i = 0; i < vec.size() - 1; i++) {
		bool IsSwap = false; //設立是否交換的標記
		for (int j = vec.size() - 1; j > i; j--) { //一趟排序
			if (vec[j - 1] > vec[j]) { //後面的大於左邊的大於右邊的數,交換
				swap(vec[j - 1], vec[j]);
				IsSwap = true;//交換標記為true
			}
		}
		//當交換標記為flase的時候,意味著本次遍歷沒有發生交換,跳出迴圈
		if (IsSwap = false) return;
	}

}
//交換兩個數的函式
void swap(int &i, int &j) {
	int temp = j;
	j = i;
	i = temp;
}

複雜度分析

顯然這種做法造成了極大的時間浪費,做了很多不必要的操作。考慮極端的情況,當被排數列有序的時候,要進行n - 1次比較。(最後一次不用比較,因為已經排好)。當為逆序的時候,進行N-1次排序,並且,第I趟要進行N-I次比較,複雜度為O(n^2).
另外一種用的最廣泛的交換排序,叫快速排序,我之前寫過我就不再贅述了,連結貼上:C++抽象程式設計——演算法分析(6)——快速排序演算法