快速排序,归并排序
来源:互联网 发布:星星网络在线星盘 编辑:程序博客网 时间:2024/05/21 07:11
#include<stdio.h>
void _partition(int arr[],int l,int mid,int r){ //归并的核心代码
int aux[r - l + 1];//辅助的数组,演示的下面的示例
//aux的赋值,aux是冲0开始的,但是arr不是从0开始的,因为递归传上来的数,不已定是从0开始的,先左到n,在左右到n递归,所以不一定l就是为0
for(int i = l ; i <= r ; i++)
aux[i - l] = arr[i];
int i = l,j = mid + 1;//演示中i,j指向的位置,k为arr后赋值过来归并好的数组
for(int k = l ; k <= r ; k++){ //k从L开始,不然的话会数组重叠
if(i > mid){
arr[k] = aux[j - l];
j++;
}
else if(j > r){
arr[k] = aux[i - l];
i++;
}
else if(aux[i - l] < aux[j - l]){
arr[k] = aux[i - l];
i++;
}
else{
arr[k] = aux[j - l];
j++;
}
}
}
void _mergeSort(int arr[],int l,int r){ //进行递归函数的编写,分和归
//递归的编写必须要有退出的条件
if(l >= r){
return ;
}
int mid = (l + r) / 2;
_mergeSort(arr,l,mid); //可以优化
_mergeSort(arr,mid + 1,r);
if(arr[mid] > arr[mid + 1]) //当时逆序的时候 才进行归并的排序
_partition(arr,l,mid,r);
}
void mergeSort(int arr[],int n){
_mergeSort(arr,0,n - 1); // 闭区间
}
int main(){
int arr[7] = {5,9,10,3,2,1,4};
mergeSort(arr,7);
for(int i = 0 ; i < 7 ; i++)
printf("%d ",arr[i]);
return 0;
}
另一个(ologn)的排序算法是快速排序(QuickSort),它与归并排序一样,都是采用了相同的思想(分治的思想)
该算法的主要的思想是:
1:从数列中取出一个数作为基数,当然这个数可以为任何数,在QuickSort的优化中,通常我们会使用random取数列中的随机数作为基数
2:分区过程,将比这个基数大的放在右边,比这个数的基数小的数放在左边,其中会出现一个等于该基数的数,此时如果该数多的话,我们可以使用3路快速排序,从而减少时间的损耗,因为快速排序是一个不稳定的排序方法,他的期望是(nlogn)的时间复杂度,所以应该避免它的分层不平衡从而增加他的时间复杂度
3:运用递归的方法,再对左右区间第二部,知道区间只有一个数
挖坑填数+分治法
0
1
2
3
4
5
6
7
8
9
72
6
57
88
60
42
83
73
48
85
初始的时候,i等于0,j等于9,X等于a[i] = 72;
初始时,i = 0; j = 9; X = a[i] = 72
由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。
从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8]; i++; 这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[8]=a[3]; j--;
数组变为:
0
1
2
3
4
5
6
7
8
9
48
6
57
88
60
42
83
73
88
85
i = 3; j = 7; X=72
再重复上面的步骤,先从后向前找,再从前向后找。
从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3] = a[5]; i++;
从i开始向后找,当i=5时,由于i==j退出。
此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将X填入a[5]。
数组变为:
0
1
2
3
4
5
6
7
8
9
48
6
57
42
60
72
83
73
88
85
可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。
对该挖坑填数的总结:
1:i = L,j = R,将基准数挖出形成第一个坑a【i】;
2: j--由后向前找比它小的数,找到后挖出此数前的一个坑a【i】,特别注意:该基数不会因为变化位置导致基数的变化
3:i++由前到后找比它大的数,找到后也挖出此数填充到前一个坑中a【i】中
4:递归要有退出的条件,再重复2,3的步骤,知道i == j,将基数填入a【i】中
核心代码
#include<stdio.h>
void _quickSort(int arr[],int l,int r){
if(l < r){ //进入该函数的条件
int i = l,j = r,x = arr[l];
while(i < j){ //退出的条件
while(i < j && arr[j] >= x) //作用是偏移,移动到可以交换的位置,在下面进行交换
j--;
if(i < j){
arr[i] = arr[j];
i++;
}
while(i < j && arr[i] < x)
i++;
if(i < j){
arr[j] = arr[i];
j--;
}
}
arr[i] = x;
_quickSort(arr,l,i - 1);
_quickSort(arr,i + 1,r);
}
}
void quickSort(int arr[],int n){
_quickSort(arr,0,n - 1);
}
int main(){
int arr[7] = {5,2,3,9,7,6,1};
quickSort(arr,7);
for(int i = 0 ; i < 7 ; i++)
printf("%d ",arr[i]);
return 0;
}
以上为2路快速排序
当然还有很多可以减少时间复杂度的方法,例如3路的快排,以及用随机的方法进行选取基数,因为快速排序是一个不稳定的(nlogn)的算法排序,目的是为了让两边更加平衡,不使其变得不那么混乱,时间复杂度范围最大来(n*n);
3路的快速排序主要是为了解决存在多个等于该基数的数,减少2路快排的所需的时间,减少时间复杂度
#include<stdio.h>
void swap(int a,int b){
int temp = a;
a = b;
b = temp;
}
void _quickSort3way(int arr[],int l,int r){
if(l < r){
int v = arr[l];
int lt = l; //arr[l + 1.....lt] < v
int gt = r + 1;//arr[gt.....r] > v
int i = l + 1;//arr[lt + 1.....i] == v
while(i < gt){ //退出的条件
if(arr[i] < v){
swap(arr[i],arr[lt + 1]);
lt++;
i++;
}
else if(arr[i] > v){
swap(arr[i],arr[gt - 1]);
gt--;
}
else{
i++;
}
}
swap(arr[l],arr[lt]);
_quickSort3way(arr,l,lt - 1);
_quickSort3way(arr,gt,r);
}
}
void quickSort3way(int arr[],int n){
_quickSort3way(arr,0,n - 1);
}
int main(){
int arr[7] = {5,2,3,9,7,6,1};
quickSort3way(arr,7);
for(int i = 0 ; i < 7 ; i++)
printf("%d ",arr[i]);
return 0;
}
- 快速排序&归并排序
- 快速排序,归并排序
- 快速排序、归并排序
- 快速排序&&归并排序
- 归并排序+快速排序
- 快速排序 归并排序
- 快速排序&归并排序
- 快速排序 && 归并排序
- 归并排序 快速排序
- 快速排序&归并排序
- 快速排序 && 归并排序
- 快速排序,归并排序
- 快速排序和归并排序
- 归并排序和快速排序
- 归并排序和快速排序
- 归并排序和快速排序
- 排序之归并、快速排序
- 快速排序与归并排序
- eclipse 怎么开启断言
- 随便写点
- Central Europe Regional Contest 2014 [Gym
- ARP攻击
- I/O多路复用之水平触发和边沿触发模式
- 快速排序,归并排序
- Pandas:DataFrame对象的基础操作
- (转)先锋伯格:选择一条少有人走的路,所有的不同由此开始
- blade模板使用总结1
- ProjectEuler-Problem22-Names scores
- 接口抽象类的区别
- Spring(一)
- ARM板实现触控幻灯片
- 逆转链表 删除链表非尾节点