排序算法
- 本文将列举常用的线性表的排序算法的c++ 实现 供读者参考。涉及到的排序算法有:插入排序(3种)、交换排序(2种)、归并排序
(假设小于为正序) - 详细介绍:
- 直接插入排序:
该算法采用朴素的比较方式,在有序序列中寻找待插入元素的位置,为节省运算采用从后往前的方式进行查找(每次将正序序列元素后移一位) .
这种方式是稳定的。
//straight insert
void StraightInsertSort(int * n,int start,int end){
for(int i = start+1;i<=end;i++){
int k = n[i],j;//记录
for(j = i-1;j>=start;j--){
if(n[j]>k){
n[j+1] = n[j];
}else{
n[j+1] = k;
break;
}
}
if(j<start)n[start]=k;
}
}
- 折半插入排序:
该算法的思路是基于直接插入排序的,采用二分的方法在有序序列中查找到待插入的元素的位置,进行插入,优化了比较次数。 这种方式是也稳定的。
//binaryinsert
void BinaryInsertSort(int * n,int start,int end){
for(int i = start+1;i<=end;i++){
int k = n[i];//记录
///binary find first index that below index==k
int left = start,right = i-1;
while(left<=right){
int mid = left+(right-left)/2;
if(n[mid]>k)right = mid-1;
else left = mid+1;
}
for(int j = i-1;j>=left;j--)n[j+1] = n[j];
n[left] = k;
}
}
- 希尔排序:
希尔排序本质上也是直接排序,只不过将序列按照一定间隔(n/2)划分然后对每一部分进行直接插入排序,之后减小间隔(一直到间隔为1为止)重复以上过程。 这种方式是不稳定的。
//sheel
void ShellSort(int * num,int start,int end){
int n = end-start+1;
int d = n/2;
while(d>=1){
for(int k = 0;k<d;k++){// the Kth group
for(int i = start+k+d;i<=end;i+=d){
int index = num[i];
for(int j = i-d;j>=start;j-=d){
if(num[j]>index)num[j+d] = num[j];
else {
num[j+d] = index;
break;
}
}
}
}
d /=2;
}
}
- 快速排序:
c++ stl 库自带的sort 函数则采用的是本算法。它采用简单的递归实现排序,将序列划分为比轴大,比轴小的两部分,然后对这两部分进行类似划分,直到无法划分为止(片段元素个数为1).其核心算法是划分算法,具体有两种。
第一种划分方式:
//Partiton way 1
int Partition1(int * n,int start,int end){
int l = start;int r = end;
int axis = n[start];//轴
while(l<r){
while(l<r&&n[r]>axis)r--;
n[l] = n[r]; // l 位置其实已经记录过了所以它相当于是空的,所以可以存放元素
while(l<r&&n[l]<=axis)l++;
n[r] = n[l]; //在移动 r 的过程中 r 位置的元素已经换走 r 位置相当于是空 所以可以用来存放元素
}
//end in l == r; 结束时候 l == r
n[l] = axis;
return l;
}
第二种划分方式
//Partition way 2
int Partition2(int * d,int start,int end){
int left = start;int right = end;
int axis = d[start];
while(left<=right){
while(left<=right&&d[left]<= axis)left++;
while(left<=right&&d[right]>axis)right--;
if(left<right){
int temp = d[left];
d[left] = d[right];
d[right] = temp;
left++;right--;
}
}
//end in right = left -1; 结束条件是 r == l -1
int temp = d[start];
d[start] = d[right];
d[right] = temp;
return right;
}
在有了划分函数之后快速排序就十分简单了(但是人就可能会出现爆栈等问题/这是由于机器决定的,毕竟是递归?)。同时这种方式是不稳定的。
void qsort(int * n ,int start,int end,int ch = 0){
if(start>=end)return;
int axis;
if(ch == 0)axis = Partition1(n,start,end);
else axis = Partition2(n,start,end);
qsort(n,start,axis-1,ch);
qsort(n,axis+1,end,ch);
}
- 冒泡排序:
作为最朴素的交换排序方式,冒泡经常被人调侃,原理十分简单,乱序则交换。这种方式是稳定的。
//Bubble sort
void BubbleSort(int * d,int start,int end){
bool flag = true;//优化冒泡
for(int i = end;i>start&&flag;i--){
flag = false;
for(int j = start;j<i;j++){
if(d[j]>d[j+1]){
int temp = d[j];
d[j] = d[j+1];
d[j+1] = temp;
flag = true;
}
}
}
}
- 归并排序:
归并排序采用合并有序序列的思路,原理也是十分简单的,它同样是采用递归实现的。这种方式是稳定的。
合并函数
//mergesort
void Merge(int * d,int start,int mid,int end){
int len1 = mid-start+1;
int len2 = end-mid;
int * left = new int[len1];
int * right = new int[len2];
for(int i = 0;i<len1;i++)left[i] = d[start+i];
for(int i = 0;i<len2;i++)right[i] = d[mid+1+i];
int i =0, j = 0;
int k = start;
while(i<len1&&j<len2){
if(left[i]<right[j]){
d[k] = left[i];
i++;
}else{
d[k] = right[j];
j++;
}
k++;
}
while(i<len1)d[k++] = left[i++];
while(j<len2)d[k++] = right[j++];
delete []left;
delete []right;
}
在有了合并函数之后,归并排序实现如下:
void Mergesort(int * n,int start,int end){
if(start>=end)return;
int mid = (start+end)/2;
Mergesort(n,start,mid);//左半部分有序
Mergesort(n,mid+1,end);//右半部分有序
Merge(n,start,mid,end);//合并两部分
}
- 当然除此之外还有别的排序方式,如:堆排序,基数排序等。这些排序方式在这里就不再叙述了