针对前面讨论的八大经典排序算法:冒泡排序、插入排序、选择排序、堆排序、归并排序、快速排序、希尔排序、桶排序。
关于各种什么时间复杂度,空间复杂度的对比总结,网上一大堆,别人也总结的很好,这里就不赘述了,这里主要通过对大量数据进行排序测试,测试各排序算法的运行时间,来比较各排序之间优劣(时间上)。
先贴出测试程序:最后会给出各数据量的情况下,各算法的运行时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | typedef void(*SortFun)(int Arr[], int length);  
  double SortTest(SortFun fp) { 	int Arr[LENGTH]; 	for (int i = 0; i < LENGTH; ++i) 		Arr[i] = rand() % MAXNUM; 	clock_t beginTime = clock(); 	fp(Arr, LENGTH); 	double diffTime = double(clock() - beginTime) / CLOCKS_PER_SEC;
  	return diffTime;
  }
   | 
 
上面的 LENGTH 和 MAXNUM 宏定义在另外一个头文件中(因为桶排序中需要用到 MAXNUM),LENGTH 为待排数据的量,MAXNUM 为待排数据数值的最大值。
为了方便调用函数指针,这里在原排序程序的基础上添加了一个通用的函数接口。为方便理解,这里重新贴出各排序程序
1、选择排序
思想:每次找一个最小值
特点:不稳定排序,in-place sort
最坏时间情况:O(N^2)
最好时间情况:O(N^2)
空间复杂度:O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | void SelectSort(int Array[], int length) { 	int i, j; 	int Minindex;
  	for (i = 0; i < length - 1; ++i)     	{ 		Minindex = i; 		for (j = i + 1; j < length; ++j) 		{ 			if (Array[j] < Array[Minindex]) 				Minindex = j;          		} 		swap(Array[i], Array[Minindex]);    	}
  }
   | 
 
2、桶排序
思想:类似于哈希表的分离链表法,定义一个映射函数,将关键字划入对应的桶中
特点:稳定排序
最坏时间情况:全部分到一个桶中O(N^2),一般情况为O(NlogN)
最好时间情况:每个桶中只有一个数据时最优O(N)
空间复杂度:典型地以空间换时间,和哈希表类似,看要多少桶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
   | typedef struct Node { 	int data; 	struct Node *next; }node;
  void AddtoBucket(node *&pNode, int value) { 	node *pHead = NULL; 	int tempValue;
  	node *pNew = new node; 	pNew->data = value; 	pNew->next = NULL; 	  	if (NULL == pNode) 	{ 		pNode = pNew; 	} 	else 	{ 		pHead = pNode; 		while ((pNode->data <= value) && (pNode->next != NULL)) 			pNode = pNode->next; 	  		if (pNode->data <= value) 		{ 			pNode->next = pNew; 		} 		else 		{ 			 			 			tempValue = pNode->data; 			pNode->data = pNew->data; 			pNew->data = tempValue; 			 			pNew->next = pNode->next; 			pNode->next = pNew; 		} 		pNode = pHead;   	}
  }
  void BucketSort(int Arr[], int length, int MaxNum) { 	node **list = new node*[length];    	for (int i = 0; i < length; ++i) 		list[i] = NULL;
  	int index; 	  	for (int i = 0; i < length; ++i) 	{ 		index = (Arr[i] * length) / (MaxNum + 1);   		AddtoBucket(list[index], Arr[i]); 	} 	  	 	for (int i = 0, j = 0; i < length; ++i) 	{ 		while (list[i] != NULL) 		{ 			Arr[j++] = list[i]->data; 			list[i] = list[i]->next; 		} 	} 	
  }
 
  void BucketSortTest(int Arr[], int length) { 	BucketSort(Arr, length, MAXNUM); } 3、
   | 
 
希尔排序
思想:分割成子序列,然后用直接插入排序
特点:不稳定排序算法
平均时间复杂度:O()
空间复杂度:O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   | void ShellSort(int Array[], int length) { 	int i, j, gap; 	int temp;
  	for (gap = length / 2; gap > 0; gap /= 2) 	for (i = 0; i < gap; ++i) 	{ 		//下面为直接插入排序,排序的是数组里间隔gap的元素 		for (j = i + gap; j < length; j += gap) 		{ 			int k = j - gap; 			temp = Array[j]; 			while (k >= 0 && Array[k] > temp) 			{ 				Array[k + gap] = Array[k]; 				k -= gap; 			} 			Array[k + gap] = temp; 		} 	}
  }
   | 
 
4、插入排序
思想:将无序区的元素比较插入到有序区适当位置,是移动不是交换,所以是稳定排序算法
特点:稳定排序算法,in-place sort
时间复杂度:最坏O(N^2),最优O(N)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | void InsertSort(int Array[], int length) { 	int i, j; 	int temp;
  	for (i = 1; i < length; ++i) 	{ 		j = i - 1; 		temp = Array[i];          //待插入数据,即无序区的第一个元素 	  		while ((j >= 0) && (temp < Array[j]))  //跳出循环的两个条件 		{ 			Array[j + 1] = Array[j];    //数据后移 			 		} 		Array[j + 1] = temp; 	}
  }
   | 
 
5、归并排序
思想:分治法
特点:稳定排序算法
时间复杂度:O(NlogN)
空间复杂度:O(N+logN)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
   | void Merge(int unsorted[], int first, int mid, int last, int sorted[]) { 	int i = first, j = mid; 	int k = 0;
  	while (i < mid && j < last) 	{ 		if (unsorted[i] < unsorted[j]) 			sorted[k++] = unsorted[i++]; 		else 			sorted[k++] = unsorted[j++]; 	} 	  	while (i < mid) 		sorted[k++] = unsorted[i++]; 	  	while (j < last) 		sorted[k++] = unsorted[j++]; 	  	
  	for (int v = 0; v < k; ++v) 		unsorted[v + first] = sorted[v];
  }
 
  void MergeSort(int unsorted[], int first, int last, int sorted[]) { 	if (first + 1 < last) 	{ 		int mid = first + ((last - first) >> 1);  		MergeSort(unsorted, first, mid, sorted); 		MergeSort(unsorted, mid, last, sorted); 		Merge(unsorted, first, mid, last, sorted); 	} }
 
  void MergeSortTest(int Arr[], int length) { 	int *sorted = new int[length]; 	MergeSort(Arr, 0, length, sorted); } 6、
   | 
 
堆排序
思想:最大堆(最小堆)
特点:不稳定排序算法
时间复杂度:O(NlogN)
空间复杂度:O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
   | #define PARENT(x) ((x-1) >> 1)
  #define LEFT(x)   ((x << 1) + 1)
  #define RIGHT(x)  ((x << 1) + 2)
 
  //调整最大堆 void MaxHeapify(int Array[], int Index, int HeapSize) { 	int L = LEFT(Index);   //Index为父节点索引 	int R = RIGHT(Index); 	int Largest;
  	//选择三(两个)个元素(“血缘关系”)的最大值 	if (L <= HeapSize && Array[L] > Array[Index]) 		Largest = L; 	else 		Largest = Index; 	  	if (R <= HeapSize && Array[R] > Array[Largest]) 		Largest = R; 	  	if (Largest != Index) 	{ 		swap(Array[Largest], Array[Index]);  //最大值与父节点位置交换 		MaxHeapify(Array, Largest, HeapSize); 		
  	}
  }
  //构建最大堆 void BuildHeapify(int Array[], int HeapSize) { 	for (int i = PARENT(HeapSize); i >= 0;  		MaxHeapify(Array, i, HeapSize);       //必须单步向前 }
  void HeapSort(int Array[], int length) { 	int HeapSize = length - 1;
  	BuildHeapify(Array, HeapSize); 	  	for (int i = HeapSize; i >= 0;  	{ 		swap(Array[0], Array[i]); 		 		MaxHeapify(Array, 0, HeapSize); 		//删除根节点后,,有一棵子树满足最大堆,有一棵不满足,只需调整一棵子树 	}
  }
   | 
 
7、快速排序
思想:分治,化整为零,与基准比较
特点:不稳定排序算法
时间复杂度:O(NlogN),如果数据本来是排序好的,最坏O(N^2)
空间复杂度:O(logN)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
   | int Partition(int Array[], int left, int right) { 	int L = left, R = right; 	int pivot = Array[L];
  	while (L < R) 	{ 		while ((L < R) && (Array[R] > pivot)) 			--R; 		if (L < R) 		{ 			Array[L] = Array[R];    			++L; 		} 	  		while ((L < R) && (Array[L] < pivot)) 			++L; 		if (L < R) 		{ 			Array[R] = Array[L]; 			--R; 		} 	} 	  	Array[L] = pivot;     	return L;
  }
  void QuickSort(int Array[], int left, int right) { 	if (left < right) 	{ 		int pos = Partition(Array, left, right); 		QuickSort(Array, left, pos - 1);            		QuickSort(Array, pos + 1, right); 	} }
 
  void QuickSortTest(int Arr[], int length) { 	QuickSort(Arr, 0, length - 1); }
   | 
 
8、冒泡排序
思想:冒泡
特点:稳定排序算法
时间复杂度:O(N^2)
1 2 3 4 5 6 7 8 9
   | void BubbleSort(int Array[], int length) { 	for (int i = 0; i < length - 1; ++i) 	for (int j = 1; j < length - i; ++j)     	{ 		if (Array[j - 1] > Array[j]) 			swap(Array[j - 1], Array[j]); 	} }
   | 
 
主程序:
避免长久的等待,将冒泡排序置最后。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | int main() { 	cout << "BucketSort:  " << SortTest(BucketSortTest) << endl; 	cout << "HeapSort  :  " << SortTest(HeapSort) << endl; 	cout << "InsertSort:  " << SortTest(InsertSort) << endl; 	cout << "MergeSort :  " << SortTest(MergeSortTest) << endl; 	cout << "QuickSort :  " << SortTest(QuickSortTest) << endl; 	cout << "SelectSort:  " << SortTest(SelectSort) << endl; 	cout << "ShellSort :  " << SortTest(ShellSort) << endl; 	cout << "BubbleSort:  " << SortTest(BubbleSort) << endl;
  	return 0;
  }
   | 
 
结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | #define LENGTH 20000   
  #define MAXNUM 10000   
  #define LENGTH 10000   
  #define MAXNUM 10000   
  #define LENGTH 5000   
  #define MAXNUM 10000   
  #define LENGTH 50000   
  #define MAXNUM 100000   
   | 
 
这里的冒泡排序需要等很久
上面运行时间的计算,受很多因素的影响,这里只是对比各大排序的排序时间。毫无疑问快速排序是最快的。