排序是计算机中常常进行的操做,目的在于将一组无序的数据元素调整为有序的数据元素。
序列:1,20,45,5,2,12
排序后:1,2,5,12,20,45算法
若是序列中的两个元素R[i]、R[j],关键字分别为K[i]、K[j],而且在排序以前R[i]排在R[j]前面,若是排序操做后,元素R[i]仍然排在R[j]前面,则排序方法是稳定的;不然排序是不稳定的。数组
比较:任意两个数据元素经过比较操做肯定前后次序。
交换:数据元素须要交换才能获得预期的结果。数据结构
A、时间性能
主要性能差别体如今比较和交换的数量
B、辅助存储空间
为完成排序操做须要的额外的存储空间
必要时能够空间换时间
C、算法的实现复杂性
过于复杂的排序算法影响可读性和可维护性ide
class Sort:public Object { private: Sort(); Sort(const Sort& other); Sort& operator = (const Sort& other); template <typename T> static void Swap(T& a, T& b) { T temp; temp = a; a = b; b = temp; } }
每次(第i次,i=1,2,3,...,n-2)从后面n-i个待排序的数据元素中选出关键字最小的元素,做为有序序列的第i个元素。
第i次选择排序示例:
选择排序实例:函数
选择排序的实现:性能
/****************************************** * 排序方式:选择排序 * array:序列 * len:序列中元素个数 * min2max:按从小到大进行排序 * ***************************************/ template <typename T> static void Select(T array[], int len, bool min2max = true) { for(int i = 0; i < len; i++) { int min = i;//从第i个元素开始 //对待排序的元素进行比较 for(int j = i + 1; j < len; j++) { //按排序的方式选择比较方式 if(min2max?(array[min] > array[j]):(array[min] < array[j])) { min = j; } } if(min != i) { //元素交换 Swap(array[i], array[min]); } } }
选择排序的时间复杂度为O(n^2)。
选择排序是不稳定的排序方法。ui
当插入第i(i>=1)个元素时,前i-1个元素已经排序好,用第i个元素的关键字与前i-1个元素的关键字分别进行比较,找到位置后将第i个元素插入,原来位置上的元素向后顺移。
第i次插入排序示例:
插入排序实例:3d
/****************************************** * 排序方式:插入排序 * array:序列 * len:序列中元素个数 * min2max:按从小到大进行排序 * ***************************************/ template <typename T> static void Insert(T array[], int len, bool min2max = true) { for(int i = 1; i < len; i++) { int k = i; T temp = array[i]; for(int j = i -1; (j > 0) && (min2max?(array[j] > temp):(array[j] < temp)); j--) { array[j + 1] = array[j]; k = j; } if(k != i) { array[k] = temp; } } }
插入排序的时间复杂度为O(n^2)
插入排序是稳定的排序方法。代理
每次从后向前进行(第i次),j=n-1,n-2,...,i,比较V[j-1]和V[j]的关键字,若是发生逆序,则交换V[j-1]和V[j]。
第i次冒泡排序示例:
冒泡排序实例:code
/********************************************** * 排序方式:冒泡排序 * array:序列 * len:序列中元素个数 * min2max:按从小到大进行排序 * *******************************************/ template <typename T> static void Bubble(T array[], int len, bool min2max = true) { bool exchange = true; //遍历全部元素 for(int i = 0; (i < len) && exchange; i++) { exchange = false; //将尾部元素与前面的每一个元素做比较交换 for(int j = len - 1; j > i; j--) { if(min2max?(array[j] < array[j-1]):(array[j] > array[j-1])) { //交换元素位置 Swap(array[j], array[j-1]); exchange = true; } } } }
冒泡排序的时间复杂度为O(n^2)
冒泡排序是稳定的排序方法。
将待排序序列划分为若干组,在每一组内进行插入排序,以使整个序列基本有序,而后再对整个序列进行插入排序。
将n个数据元素分红d个子序列,划分方法以下:
d为增量,d的值在排序过程当中由大到小逐渐缩小,直至最后一趟排序减为1。
/****************************************** * 排序方式:希尔排序 * array:序列 * len:序列中元素个数 * min2max:按从小到大进行排序 * ***************************************/ template <typename T> static void Shell(T array[], int len, bool min2max = true) { int d = len; do { d = d/3 + 1; for(int i = d; i < len; i += d) { int k = i; T temp = array[i]; for(int j = i -d; (j >= 0) && (min2max?(array[j] > temp):(array[j] < temp)); j -= d) { array[j+d] = array[j]; k = j; } if(k != i) { array[k] = temp; } } }while(d > 1); } };
希尔排序经过分组的方法进行屡次插入排序,是一种不稳定的排序方法,时间复杂度为O(n^(3/2))。
将两个或两个以上的有序序列合并成一个新的有序序列。
将2个有序序列归并为一个新的有序序列,称为2路归并。
将N个有序序列归并为一个新的有序序列,称为N路归并。
2路归并实例:
template <typename T> static void Merge(T src[], T helper[], int begin, int mid, int end, bool min2max=true) { int i = begin; int j = mid + 1; int k = begin; while((i <= mid) && (j <= end)) { if(min2max ? (src[i] < src[j]) : (src[i] > src[j])) { helper[k++] = src[i++]; } else { helper[k++] = src[j++]; } } while(i <= mid) { helper[k++] = src[i++]; } while(j <= end) { helper[k++] = src[j++]; } //拷贝辅助空间的结果到源序列空间 for(i = begin; i <= end; i++) { src[i] = helper[i]; } } template <typename T> static void Merge(T src[], T helper[], int begin, int end, bool min2max=true) { if(begin < end) { int mid = (begin + end) / 2; //左边路进行归并排序 Merge(src, helper, begin, mid, min2max); //右边路进行归并排序 Merge(src, helper, mid+1, end, min2max); //二路归并排序 Merge(src, helper, begin, mid, end, min2max); } } /****************************************** * 排序方式:归并排序 * array: 序列 * len:序列中元素个数 * min2max:按从小到大进行排序 * ***************************************/ template <typename T> static void Merge(T* array, int len, bool min2max=true) { //辅助空间申请 T* helper = new T[len]; if(helper != NULL) { Merge(array, helper, 0, len-1, min2max); } delete [] helper; }
归并排序是一种稳定排序,须要额外的辅助空间完成,空间复杂度为O(n),时间复杂度为O(nlogn)。
任取序列中的某个数据元素做为基准将整个序列划分为左右两个子序列。左侧子序列中全部的数据元素都小于或等于基准元素,右侧子序列中全部元素都大于基准元素,基准元素排在两个子序列中间。
分别对两个子序列进行从新划分,直到全部的数据元素都排在相应位置上为止。
快速排序示例:
快速排序实例:
/****************************************** * 快速排序的区域划分函数 * array:序列 * begin:序列的起始位置 * end:序列的结束位置 * min2max:按从小到大进行排序 * ***************************************/ template <typename T> static int Partition(T array[], int begin, int end, bool min2max) { T pv = array[begin]; while(begin < end) { while((begin < end) && (min2max ? (array[end] > pv): (array[end] < pv))) { end--; } Swap(array[begin], array[end]); while((begin < end) && (min2max ? (array[end] <= pv): (array[end] > pv))) { begin++; } Swap(array[begin], array[end]); } array[begin] = pv; return begin; } /****************************************** * 快速排序功能函数 * array: 序列 * begin:序列的起始位置 * end: 序列的结束位置 * min2max:按从小到大进行排序 * ***************************************/ template <typename T> static void Quick(T array[], int begin, int end, bool min2max) { if(begin < end) { //对序列进行区域划分 int pivot = Partition(array, begin, end, min2max); //对基准左侧的区域进行快排序 Quick(array, begin, pivot, min2max); //对基准右侧的区域进行块排序 Quick(array, pivot+1, end, min2max); } } /****************************************** * 排序方式:快速排序 * array: 序列 * len:序列中元素个数 * min2max:按从小到大进行排序 * ***************************************/ template <typename T> static void Quick(T array[], int len, bool min2max=true) { Quick(array, 0, len-1, min2max); }
快速排序经过递归的方式对排序问题从新划分,是一种不稳定的排序方法,时间复杂度为O(nlogn)。
template <typename T> static void Select(Array<T>& array, bool min2max=true) { Select(array.array(), array.length(), min2max); } template <typename T> static void Insert(Array<T>& array, bool min2max=true) { Insert(array.array(), array.length(), min2max); } template <typename T> static void Bubble(Array<T>& array, bool min2max=true) { Bubble(array.array(), array.length(), min2max); } template <typename T> static void Shell(Array<T>& array, bool min2max=true) { Shell(array.array(), array.length(), min2max); } template <typename T> static void Merge(Array<T>& array, bool min2max=true) { Merge(array.array(), array.length(), min2max); } template <typename T> static void Quick(Array<T>& array, bool min2max=true) { Quick(array.array(), array.length(), min2max); }
排序过程当中不可避免的须要进行交换操做,交换操做的本质为数据元素间的相互复制,若是序列的规模巨大时,交换操做将耗时巨大。经过使用代理模式,为待排序元素设置代理对象,对代理对象组成的序列进行排序,须要访问有序序列元素时,经过访问待序列完成。经过使用空间换时间提升算法效率。