排序--Bubble的優化和性能(算法時間、空間複雜度、穩定性)分析

 

一、算法基本思想

(1)基本思想

冒泡排序的基本思想就是:從無序序列頭部開始,進行兩兩比較,根據大小交換位置,直到最後將最大(小)的數據元素交換到了無序隊列的隊尾,從而成爲有序序列的一部分;下一次繼續這個過程,直到所有數據元素都排好序。

算法的核心在於每次通過兩兩比較交換位置,選出剩餘無序序列裏最大(小)的數據元素放到隊尾。

二、算法實現

void BubbleSort(int *arr, int len)
{
	assert(arr);
	int i = 0;
	int j = 0;
	int tmp = 0;
	for (i = 0; i < len - 1; i++)     //n-1趟
	{
		for (j = 0; j < len -i- 1; j++)       
		{
			if (arr[j]>arr[j + 1])
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

    冒泡排序還有三種優化方式:(以下都是以升序爲例)

例如要排序下面這組數據: 0  1  2  3  4  5  6   7  9  8

     經過第一趟冒泡排序已經有序了,下面的幾趟已經是多餘的,這時我們可以加一個標誌位flag,若那一趟沒有交換數據,這這時已經有序,我們就可以退出排序,不必進行下來的幾趟。

算法實現:
 

void BubbleSort(int *arr, int len)
{
	assert(arr);
	int i = 0;
	int j = 0;
	int flag = 0;
	int tmp = 0;
	for (i = 0; i < len - 1; i++)
	{
		flag = 1;                             
		for (j = 0; j < len - i - 1; j++)     //每排序一趟,則必然後面有一個已經有序,可以縮小排序的範圍
		{
			if (arr[j]>arr[j + 1])             //只要要交換數據,則flag就會被修改
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;                   //只要還未完全有序,則修改flag爲0
			}
		}
		if (flag)                            
		{
			break;
		}
	}
}

冒泡再次優化的方法!!!

例如要排序下面這組數據:1  4  3  2  6  7  8  9 

     經過第一趟冒泡排序比較了,發現後面數據沒有交換已經有序,接下來幾趟比較後面的數據已經是多餘的,這時我們可以記錄每一次交換的位置,下一次從第一個數據比較到最後一次交換位置即可,不必再次比較後面的數據。

算法實現:

void BubbleSort(int *arr, int len)
{
	assert(arr);
	int i = 0;
	int j = 0;
	int flag = 0;
	int tmp = 0;
	int m = 0;                  //用來記錄最後一次交換的位置
	int k = len-1;
	for (i = 0; i < len - 1; i++)
	{
		m = 0;
		flag = 1;
		for (j = 0; j < k; j++)       //無序區的範圍只從第一個元素,到上一趟最後一次交換的位置k
		{
			if (arr[j]>arr[j + 1])
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;                   
				m = j;
			}
		}
		if (flag)                          
		{
			break;
		}
		k = m;                             //將k置成最後一次交換的位置
	}
}

冒泡排序還有第三種優化方式:

    對下面這組這組數進行排序:2  3  4  5  6  7  8  9  10  1

     只有後面兩個數據無序,前面已經有序,按照以上優化冒泡需要進行多次。這時,我們採用正反交替掃描,正着找最大值,翻着找最小值,一趟就可以使數據有序。

void BubbleSort(int *arr, int len)
{
	assert(arr);
	int i = 0;
	int j = 0;
	int flag = 0;
	int m = 0;       //記錄最後一次交換的位置
	int n = 0;
	int k = len - 1;
	for (i = 0; i < len - 1; i++)
	{
		m = 0;
		flag = 1;
		//正序掃描找最大值
		for (j = n; j < k; j++)       //無序區的範圍只從第一個元素,到上一趟最後一次交換的位置k
		{
			if (arr[j]>arr[j + 1])
			{
 
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;                    
				m = j;
			}
		}
		k = m;
		if (flag)             
		{
			break;
		}
		//反序掃描找最小值
		for (j = k; j>n; j--)       //無序區的範圍只從第一個元素,到上一趟最後一次交換的位置k
		{
			if (arr[j]<arr[j - 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j - 1];
				arr[j - 1] = tmp;
				flag = 0;                  
			}
		}
		n++;
		if (flag)                   
		{
			break;
		}                           //將k置成最後一次交換的位置
	}
}

若比較的數據不是整形是其他類型怎麼處理,這是我們需要支持泛型編程。

基礎知識:

void * :通用指針(無符號指針)或叫做泛型指針,它的特點有:

(1)它用於臨時存儲地址

(2)它不能解引用

(3)它不能進行算術運算,因爲呢,它就是臨時的盒子,所以呀,不能依賴它進行計算,總不可能依賴一個通用的盒子計算有   類型的數據吧

算法實現:

//4.泛型冒泡
typedef int(*PCmp)(void *vp1, void *vp2);//泛型比較
void Swap(void* vp1, void*vp2,int size)
{
	void* temp = malloc(size);
	memcpy(temp, vp1, size);
	memcpy(vp1, vp2, size);
	memcpy(vp2, temp, size);
	free(temp);
}
void BubbleSort(void* arr, int len, int elemsize, PCmp cmp)
{
	void* var1;
	void* var2;
	int k = len - 1;
	int m = 0;
	bool flag = 1;
	for (int i = 0; i < len - 1; ++i)
	{
		for (int j = 0; j < k; ++j)
		{
			var1 = (char*)arr + j*elemsize;
			var2 = (char*)arr + (j + 1)*elemsize;
			if (cmp(var1, var2)>0)
			{
				Swap(var1, var2, elemsize);
				m = j;
				flag = 0;
			}
			
		}
		if (flag) break;
		k = m;
	}
}
int Cmp_int(void *vp1, void *vp2)
{
	return *(int *)vp1 - *(int *)vp2;
}

int Cmp_str(void *vp1, void *vp2)
{
	return strcmp(*(char **)vp1, *(char **)vp2);
}

void Test()
{
	int arr[] = { 3, 5, 7, 9, 0, 12, 45, 6, 78, 23, 44, 10 };
	BubbleSort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), Cmp_int);

	char *brr[] = { "abc", "aaa", "bcd", "xyz", "ccccc", "hhh" };
	BubbleSort(brr, sizeof(brr) / sizeof(brr[0]), sizeof(char *), Cmp_str);
	
	getchar();

}
int main()
{
	Test();
	
}

運行結果:

三、性能(算法時間、空間複雜度、穩定性)分析

 (1)時間複雜度

當原始序列“正序”排列時,冒泡排序總的比較次數爲n-1,移動次數爲0,也就是說冒泡排序在最好情況下的時間複雜度爲O(n);

當原始序列雜亂無序時,冒泡排序的平均時間複雜度爲O(n^2)。

(2)空間複雜度

冒泡排序排序過程中需要一個臨時變量進行兩兩交換,所需要的額外空間爲1,因此空間複雜度爲O(1)。

(3)穩定性

冒泡排序在排序過程中,元素兩兩交換時,相同元素的前後順序並沒有改變,所以冒泡排序是一種穩定排序算法。

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