交换排序小结

冒泡排序

思想:

就像冒泡排序的名字一样,冒泡。每一个比较中的较大的数,会向后交换一次,这样,每一轮比较下来,最大的数就会像气泡一样,飘到最后(或者,将数组立起来,最大的数向上冒泡),第一轮比较全部的数,将最大的数冒泡到最后,第二轮比较除最后的那个最大的数之外的元素,将次大的数冒泡到最后-1的位置,以此类推。

关键点:

  • 两层循环,第二层循环的尽头需要注意,详情看下面代码

代码:

public void bubbleSort(int[] nums){
    int end=nums.length-1;
    for(int i=0;i<nums.length;i++){
        for(int j=0;j<end-i;j++){//这里,i每一轮下j循环的尽头不同,因为数组后i个数据已经排序好了(较大数据),所以不需要再比较
            if(nums[j]>nums[j+1]){
                swap(nums,j,j+1);
            }
        }
    }
}
private void swap(int[] nums,int index1,int index2){
    int temp=nums[index1];
    nums[index1]=nums[index2];
    nums[index2]=temp;
}

快速排序

思路:

快排的思路和插入排序中希尔排序(见上一篇)很像,排序较有序的数组,时间复杂度会减少,采用分治思想,可以将数组分解成若干个小组,每一个小组中排好序,进而整个大数组就有序了。
这里重点就成了如何分组,快排选择的方式比较特别:选择一个数据(轴元素),排序使得数组中这个数据左边的都比这个数据小,右边都比这个数据大(反之亦可,取决于想得到升序还是降序数组),然后对这个数据左侧、右侧使用相同方法排序,最终就可得到一个完全有序的数组。

关键点:

  • 如何选择选定数据(轴元素):下面代码每次选择数组的第一个元素作为选定数据,但是这是有一定风险的,如果数组为倒序(最坏情况),选择第一个数据,会导致轴元素两侧极不平衡,导致算法效率下降。优化的快排在选择轴元素这个地方有各种选择,随机也是可能的。
  • 如何排序产生数组中一个数据,在它左侧的数都比它小,在它右侧的数都比他大:这里使用了两个指针start、end,指向数组的开始和结束,这里有两种策略。
    1. 从数组的end位置开始向前面遍历,end指针停在第一个比选定数据(轴元素)小的数的位置;之后从数据的start位置开始向后遍历,start停在第一个比选定数据(轴元素)大的数的位置;交换start、end位置的数据,继续遍历的流程,直到start>end,最后将选定数据(轴元素)与数组end位置数据交换。至此,完成一轮排序。
    2. 从数据end位置开始向前遍历,end指针停在第一个比选定数(轴元素)小的数的位置,这时将选定数据与数组end位置数交换,然后从数组start位置开始向后遍历数组,start停在第一个比选定数(轴元素)大的数的位置,将start位置的数与end位置的数(选定数据)交换,继续遍历流程,指导start>end。完成一轮排序。
  • 如何进行多轮排序:下面代码使用了递归,对轴元素左侧、右侧数据进行相同操作,递归可以借助栈改为循环,但是不易理解。

代码:

public  void quickSort(int[] nums,int start,int end){
        int midden=partition(nums,start,end);//先进行一次排序分割,得到轴元素更新的位置
        if(start<midden)//如果轴元素不是start元素的话(轴元素左侧有元素),递归调用,排序左侧
            quickSort(nums,start,midden-1);//注意midden-1,
        if(end>midden)//轴元素右侧有元素的话,递归右侧
            quickSort(nums,midden+1,end);//注意midden+1

    }
private  int partition(int[] nums,int start,int end){
    int midden=nums[start];
    int left=start,right=end;
    while(left<right){
        while(left<=right && nums[left]<=midden){//从前向后遍历直到碰到比选中元素(轴元素)大的元素
            left++;
        }
        while(left<=right && nums[right]>midden){//从后向前遍历直到碰到比轴元素小的元素
            right--;
        }
        if(left<right){//交换上面遍历得到的二者
            swap(nums,left,right);
            left++;
            right--;
        }
    }
    swap(nums,start,right);//更新轴元素位置
    return right;//返回轴元素新位置
}
private  void swap(int []nums,int index1,int index2){
    int temp=nums[index1];
    nums[index1]=nums[index2];
    nums[index2]=temp;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值