java常用排序算法(冒泡,插入,快速)等

快速排序:
算法描述:对于一组给定的记录,通过一趟排序后,将原序列分为两部分,其中前一部分的所有记录均比后一部分的所有记录小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中的所有记录均有序为止。
快速排序的原理:选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。一般选择序列的第一个元素。
一次循环:从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换。找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,
如果没有继续比较下一个,直到找到第一个比基准值大的值才交换。直到从前往后的比较索引>从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两边就是有序的了。接着分别比较左右两边的序列,重复上述的循环。
public class QuickSort {
    public void sort(int[] a,int low,int high){
         int start = low;
         int end = high;
         int key = a[low];
         while(end>start){
             //从后往前比较
             while(end>start&&a[end]>=key)  //如果没有比关键值小的,比较下一个,直到有比关键值小的交换位置,然后又从前往后比较
                 end--;
             if(a[end]<=key){
                 int temp = a[end];
                 a[end] = a[start];
                 a[start] = temp;
             }
             //从前往后比较
             while(end>start&&a[start]<=key)//如果没有比关键值大的,比较下一个,直到有比关键值大的交换位置
                start++;
             if(a[start]>=key){
                 int temp = a[start];
                 a[start] = a[end];
                 a[end] = temp;
             }
         //此时第一次循环比较结束,关键值的位置已经确定了。左边的值都比关键值小,右边的值都比关键值大,但是两边的顺序还有可能是不一样的,进行下面的递归调用
         }
         //递归
         if(start>low) sort(a,low,start-1);//左边序列。第一个索引位置到关键值索引-1
         if(end<high) sort(a,end+1,high);//右边序列。从关键值索引+1到最后一个
     }
     
}
    public static void main(String[] args) {
        int[] a = { 49, 38, 65, 97, 76, 13, 27, 50 };
        quickSort(a);
    }
}
冒泡排序:
冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复n 次,
先从第一个数开始,如果第一个数比第二个数小那么两个数交换位置,然后再比较第二个数与第三个数如果比小就交换位置否则依次,直到把最大的数放在最后一个,
冒出最大的一个放在最后一个然后下次比较n-1次冒出下一个大的在倒数第二个。
冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。
//冒泡排序实现
       for(int i=0;i<a.length-1;i++){
            for(int j=0;j<a.length-i-1;j++){
                if(a[j]>a[j+1]){
                    int temp = a[j];
                    a[j] = a[j+1];
                   a[j+1] = temp;
                }
            }
      }
选择排序原理:
假设有10个数,第一轮循环,第一个数和第二个数比较,如果第一个数大,第一个数和第二个数交换位置,否则不动;接着第一个数和第三个数比较,如果第一个数大,第一个数和第三个数交换位置,否则不动……第一个数和第十个数比较,如果第一个数大,第一个数和第十个数交换位置,否则不动。第一轮循环结束,最小的数挪到了第一个数的位置,比较进行了9次。 
第二轮循环,第二个数和第三个数比较,如果第二个数大,第二个数和第三个数交换位置,否则不动……第二个数和第十个数比较,如果第二个数大,第二个数和第十个数交换位置,否则不动。第二轮循环结束,第二小的数挪到了第二个数的位置,比较进行了8次。 
…… 
第九轮循环,第九个数和第十个数比较,如果第九个数大,第九个数和第十个数交换位置,否则不动。第九轮循环结束,倒数第二小的数挪到了倒数第二个的位置,比较进行了1次。
 for (int j = 0; j <length- 1;j++) {
            for (int i = j; i < length- 1; i++) {
                if (a[j] > a[i + 1]) {
                    // change
                    temp = a[j];
                    a[j] = a[i + 1];
                    a[i + 1] = temp;
                }
            }
        }

插入排序:
这个算法从数组的第二个元素开始循环,将选中的元素与之前的元素一一比较,如果选中的元素小于之前的元素,则将之前的元素后移,最后再将选中的元素放在合适的位置。在这个算法执行的过程中,总是保持着索引i之前的数组是升序排列的。
工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
来看一下插入排序算法的思路:将需排序的数据分成已排序和未排序两部分,从第一个元素开始,并将该元素看做已排序。
取得下一个元素,即第二个元素,在已排序的序列中由后向前扫描,找出合适的位置将该元素插入。
重复上述步骤,直到最后一个元素被插入到已排序序列中。
排序完成。
 public static void sort(int[] numbers){
        for (int i = 1; i < numbers.length; i++) { //i前面是已经排好序的 i是下一个需要排序的
            int currentNumber = numbers[i];
            int j = i - 1; //j就是已经排好序的,每次排序就会空出一个位置如果后面的有小于前面的一个一个往后移
            while (j >= 0 && numbers[j] > currentNumber) {
                numbers[j + 1] = numbers[j]; //如果大于要排序的需要交换位置往后移
                j--;
            }
            numbers[j + 1] = currentNumber;
        }
归并排序:
归并排序将一个长度为n的数组平均分为两个n/2的数组分别进行处理,因此,在sort方法中又调用了两次sort方法自身。当数组大小为1时,则认为该数组为已经为排好序的数组。因此在sort方法中,需要end与pos相差大于2时,才需要进一步拆分,这也是递归的终止条件。

归并排序的基本步骤就是
1.先把一个数组以二分法的方式递归的分组,(分)
2.然后再将相邻的两个数组进行作对比,把两个已排序好的子数组中的数字由小到大(由大到小)地放到辅助数组temp[]中,(合)
3.最后再把辅助数组中的元素复制到原数组中返回。

这种排序的时间复杂度为O(NlgN),同时需要O(N)的辅助空间——保存N个元素。
这是一种稳定的算法。

分而治之(divide - conquer);每个递归过程涉及三个步骤
第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.
第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作
第三, 合并: 合并两个排好序的子序列,生成排序结果.
例如数组A有七个数据,分别是83,25,56,67,43,75,26
初始值:[83],[25],[56],[67],[43],[75],[26]
看成由长度为7的子序列组成
第一次合并之后:[25,38],[56,67],[43,75],[26]
看成由长度为1或者2的4子序列组成
第二次合并之后:[25,38,56,67],[26,43,75]
看成由长度为4或者3的两个子序列组成
第三次合并之后:[25,26,38,43,56,67,75]

public static void mergeSort(int[] nums) {
        //创建与原数组相同长度的数组
        int[] temp = new int[nums.length];
        mergeSort(nums, temp, 0, nums.length-1);
    }

    private static void mergeSort(int[] nums, int[] temp, int left, int right) {

        if(left < right) {
            //从中间将数组分成两半
            int mid = (left + right) >> 1;
            mergeSort(nums, temp, left, mid);
            mergeSort(nums, temp, mid+1, right);
            //将两个数组重新合并
            merge(nums, temp, left, mid+1, right);
        }
    }

    private static void merge(int[] nums, int[] temp, 
            int leftPos, int rightPos, int rightEnd) {
        
        int leftEnd = rightPos - 1;
        int tmpPos = leftPos;
        int numElements = rightEnd - leftPos + 1;
        //对比左右两个数组并将较小的数先放到辅助数组
        while(leftPos <= leftEnd && rightPos <= rightEnd) {
            if(nums[leftPos] <= nums[rightPos]) {
                temp[tmpPos++] = nums[leftPos++];
            }else {
                temp[tmpPos++] = nums[rightPos++];
            }
        }
        //把左边数组剩下的原数放到辅助数组
        while(leftPos <= leftEnd) {
            temp[tmpPos++] = nums[leftPos++];
        }
        //把右边数组剩下的原数放到辅助数组
        while(rightPos <= rightEnd) {
            temp[tmpPos++] = nums[rightPos++];
        }
        //把辅助数组复制到原数组
        for(int i = 0; i < numElements; i++,rightEnd--) {
            nums[rightEnd] = temp[rightEnd];
        }
    }

猜你喜欢

转载自blog.csdn.net/zpflwy1314/article/details/94876349