排序按某一种规则可分为比较类与非比较类两种
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),其时间复杂度和空间复杂度类似于低关键码优先。
排序算法的性能比较