排序按某一种规则可分为比较类与非比较类两种
no.1 比较类排序
内部排序(插入类排序、选择类排序和交换类排序)
插入类排序基本思想:在一个已排好序的记录子集的基础上,每一步将下一个待排序的记录有序插入到已排好序的记录子集中,直到将所有待排记录全部插入为止。
交换类排序基本思想:通过一系列交换逆序元素进行排序的方法,主要有冒泡排序法和快速排序法。
针对于快速排序,有以下3种排序方法:
//方式1.Horn
int Partion1(int* array,int left,int right)
{
//优化处理
int mid = GetMidIndex(array,left,right);
if(mid != right)
std::swap(array[mid],array[right]); //其中下标为right的数组元素为基准值
int basedata = array[right];
int begin = left;
int end = right;
while(begin < end){
while(begin < end && array[begin] <= basedata)
begin++;
while(begin < end && array[end] >= basedata)
end--;
if(begin < end)
std::swap(array[begin],array[end]);
}
if(begin != right)
std::swap(array[begin],array[right]);
return begin;
}
//方式2.挖坑法
int Partion2(int* array,int left,int right)
{
//优化处理
int mid = GetMidIndex(array,left,right);
if(mid != right)
std::swap(array[mid],array[right]); //其中下标为right的数组元素为基准值
int basedata = array[right];
int begin = left;
int end = right;
while(begin < end){
while(array[begin] <= basedata)
begin++;
if(begin < end)
array[end--] = array[begin];
while(array[end] >= basedata)
end--;
if(begin < end)
array[begin++] = array[end];
}
array[begin] = basedata;
return begin;
}
//方式3.使用pcur和prev
int Partion3(int* array,int left,int right)
{
//优化处理
int mid = GetMidIndex(array,left,right);
if(mid != right)
std::swap(array[mid],array[right]); //其中下标为right的数组元素为基准值
int basedata = array[right];
int pcur = left;
int prev = pcur-1;
while(pcur < right){
if(array[pcur] < basedata && ++prev != pcur) //在这种情况下交换,具体分析可得
std::swap(array[prev],array[pcur]);
pcur++; //当array[pcur]<basedata不满足时,仅pcur++,会产生++prev!=pcur的情况
}
std::swap(array[pcur],array[++prev]);
return prev;
}
//使用栈实现非递归快排 void QuickSort_Nor(int* array,int size) { stack<int> s; s.push(0); s.push(size-1); while(!s.empty()){ int right = s.top(); s.pop(); int left = s.top(); s.pop(); if(left < right){ int mid = Partion3(array,left,right);//返回处理后的基准值 //右半区间 s.push(mid+1); s.push(right); //左半区间 s.push(left); s.push(mid-1); } } }
选择类排序的基本思想:每一趟在n-i+1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录,在简单选择排序的基础上,给出其改进算法——锦标赛排序和堆排序。
针对堆排序,有以下程序代码:
//*********************************堆排序******************************* //**** 堆排序不稳定,时间复杂度为o(nlog2n) //**** 若升序,建大堆,降序,建小堆 //向下调整 void HeapAdjust(int* array,int root,int size) { int child = 2*root+1; int parent = root; while(child < size) { if(child+1 < size && array[child+1] > array[child]) child+=1; if(array[child] > array[parent]) { std::swap(array[child],array[parent]); parent = child; child = 2*parent+1; }else break; } } //HeapSort(建大堆) void HeapSort(int* array,int size) { //最后一个非叶结点开始 for(int idx = (size-1-1)/2;idx >= 0;idx--) HeapAdjust(array,idx,size); //堆中最后一个元素 int end = size-1; while(end > 0) { std::swap(array[0],array[end]); HeapAdjust(array,0,end); //end指调整size-1个元素,每次减少一个元素(最大值) end--; } }
外部排序
归并排序基本思想:基于合并,将两个或两个以上有序表合并成一个新的有序表,需开辟一段辅助空间。
2-路归并排序 时间复杂度:
空间复杂度:
归并排序主要用于外部排序,适用于数据量大,大到内存无法一次加载完数据的情况;
外部排序步骤:(1)将待排序记录分批读入内存,用某种方法在内存排序,组成有序的子文件,再存入外存;
(2)将子文件进行多路归并,生成较长有序子文件,再存入外存,如此反复,直到整个待排序文件有序。
no.2 非比较类排序
计数排序(鸽巢原理),时间复杂度:
,空间复杂度:
,稳定性:稳定
基数排序
低关键码优先(LSD)时间复杂度:
,空间复杂度:
高关键码优先(MSD),其时间复杂度和空间复杂度类似于低关键码优先。
排序算法的性能比较