1. 程式人生 > >C++ 氣泡排序演算法的實現與改進(含筆試面試題)

C++ 氣泡排序演算法的實現與改進(含筆試面試題)

      氣泡排序(Bubble sort)也是一種簡單直觀的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端 演算法步驟:

1)比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。

2)對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。

3)針對所有的元素重複以上的步驟,除了最後一個。

4)持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。

實現程式碼:包含標準冒泡程式和兩次的改進,並使用了函式的過載、標準庫容器等等

/***************************************************************************
 *  @file       main.cpp
 *  @author     MISAYAONE
 *  @date       24  March 2017
 *  @remark     24  March 2017 
 *  @theme      Bubble Sort 
 ***************************************************************************/

#include <iostream>
#include <vector>
using namespace std;

//傳入陣列首尾指標,標準氣泡排序
void Bubble_sort(int *begin, int *end)
{
	for (auto p1 = begin; p1 != end; ++p1)
	{
		for (auto p2 = begin; p2 != end-1; ++p2)
		{
			if (*p2 > *(p2+1))
			{
				int val_temp = *p2;
				*p2 = *(p2+1);
				*(p2+1) = val_temp;
			}
		}
	}
}

//對函式進行過載,傳入一對迭代器,同時進行第一次改進
//第一次改進:用於標誌某一趟排序過程中是否有資料交換
//如果進行某一趟排序時並沒有進行資料交換,則說明資料已經按要求排列好
//可立即結束排序,避免不必要的比較過程
void Bubble_sort(vector<int>::iterator begin, vector<int>::iterator end)
{
	int flag= 0;
	for (auto p1 = begin; p1 != end; ++p1)
	{
		flag = 0;
		for (auto p2 = begin; p2 != end-1; ++p2)
		{
			if (*p2 > *(p2+1))
			{
				int val_temp = *p2;
				*p2 = *(p2+1);
				*(p2+1) = val_temp;
				flag = 1;//表示此輪迴圈進行了交換				
			}
		}
		if (flag == 0)//上一輪迴圈中未進行交換,直接跳出
		{
			break;
		}
	}
}

//對函式進行過載,傳入陣列指標和陣列大小,同時進行第二次改進
/*第二次改進:傳統氣泡排序中每一趟排序操作只能找到一個最大值或最小值*/
/*我們考慮利用在每趟排序中進行正向和反向兩遍冒泡的方法一次可以得到兩個最終值(最大者和最小者)*/
/*從而使排序趟數幾乎減少了一半*/
void Bubble_sort(int a[],int size)
{
	int low = 0;
	int high = size-1;
	while(high > low)
	{
		for (int i = low; i != high; ++i)//正向冒泡,確定最大值
		{
			if (a[i] > a[i+1])
			{
				int temp = a[i];
				a[i] = a[i+1];
				a[i+1] = temp;
			}
		}
		--high;

		for (int j = high; j != low; --j)//反向冒泡,確定最小值
		{
			if (a[j] < a[j-1])
			{
				int temp = a[j];
				a[j] = a[j-1];
				a[j-1] = temp;
			}
		}
		++low;
	}
}

int main(int argc,char** argv)
{
	int a[10] = {1,5,8,7,9,6,4,3,2,0};
	int b[10] = {1,5,8,7,9,6,4,3,2,0};
	vector<int> vec(a,a+10);
	Bubble_sort(begin(a),end(a));//標準庫的begin()和end()函式
	cout<<"內建陣列氣泡排序後:";
	for (int i = 0; i < 10; ++i)
	{
		cout<<a[i]<<" ";
	}

	Bubble_sort(vec.begin(),vec.end());//標準庫容器的begin()和end()成員函式
	cout<<endl;
	cout<<"第一次改進的氣泡排序後:";
	for (int i = 0; i < 10; ++i)
	{
		cout<<vec[i]<<" ";
	}

	Bubble_sort(b,10);//傳入引數為陣列指標和陣列大小
	cout<<endl;
	cout<<"第二次改進的氣泡排序後:";
	for (int i = 0; i < 10; ++i)
	{
		cout<<b[i]<<" ";
	}

	cin.get();
	return 0;
}


一般我們學到的第一個排序演算法就是氣泡排序,這在面試筆試中是一個很常見的考點,平均時間空間複雜度,最好最壞情況下的時間空間複雜度,在不同情況下每一趟的比較次數,以及加標誌位減少比較次數等,都是需要注意的地方。

複雜度分析:

氣泡排序對 n 個元素需要 O(n^2) 的比較次數,且可以原地排序,無需輔助空間。

氣泡排序僅適用於對於含有較少元素的數列進行排序。

最差時間複雜度 O(n^2)
平均時間複雜度 O(n^2)
最優時間複雜度 O(n)
最差空間複雜度 O(n),輔助空間 O(1)

特點分析:穩定演算法(stable)、in place演算法

例題1:對於整數序列100,99,98,…3,2,1,如果將它完全倒過來,分別用氣泡排序,它們的比較次數和交換次數各是多少?


答:氣泡排序的比較和交換次數將最大,都是1+2+…+n-1=n(n-1)/2=50×99=4545次。

例題2:把一個字串的大寫字母放到字串的後面,各個字元的相對位置不變,不能申請額外的空間

#include <iostream>
#include <vector>
#include <string>
using namespace std;

//傳入首尾迭代器
void Bubble_sort1(string::iterator begin, string::iterator end)
{
	for (auto p1 = begin; p1 != end; ++p1)
	{
		for (auto p2 = begin; p2 != end-1; ++p2)
		{
			if (*p2 >= 'A' && *p2 <= 'Z')//是大寫字母就往後傳遞
			{
				int val_temp = *p2;
				*p2 = *(p2+1);
				*(p2+1) = val_temp;
			}
		}
	}
}

int main(int argc,char** argv)
{
	string test = "sadhiUASVoijiashKUASYUI";
	Bubble_sort1(test.begin(),test.end());
	cout<<test<<endl;
	cin.get();
	return 0;
}