1.冒泡排序2.选择排序3.插入排序4.希尔排序5.归并排序6.快速排序

常见的十种排序算法:

冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序

排序算法
【1】在面试和以后工作中可能用到的算法:      
*冒泡排序*选择排序*插入排序*希尔排序*归并排序*快速排序
【2】算法是为了求解一个问题,需要遵循的、被清楚指定的简单命令的集合
【3】数据换位:排序的核心是“对比大小”,并将顺序不符合的其中两个元素换位,经过多次的
对比和必要的换位,达到“结果是有序的”效果。
int a=7; int b=1; int temp;
temp = a;  a = b; b = temp;
第二种:int a=7;int b=1;
a=a+b; b=a-b; a=a-b;  但是不直观

compareCount  对比次数
swapCount 换位次数

1.【冒泡排序】(Bubble sort)

原理:反复对比相邻的两个元素,如果与预期的顺序不符,则换位。
拿升序举例,每比较一轮可以保证“将最大的数字元素移到最右侧”,第一个元素自然就是最小了
比较长度-1就可以了,因为每轮都能将最大的数字移到右侧,后续的轮次就不必对该数字进行换位
所以每轮比较的次数-1
循环次数=数组长度-当前轮次
在编码时,一般使用0作为初始值,那么循环次数=数组长度-当前轮次-1
总结:使用嵌套循环实现,外层循环表示轮次,数组的长度-1
初始条件:int i=0;循环条件:i<array.length-1;
内层循环用于对比和换位
循环条件:array.length-当前轮次-1
升序具体代码:
 int[] array = {1,8,5,4,7,3,6,2,9,0};
        for (int i=0;i< array.length-1;i++) {
            for (int j = 0; j < array.length-1-i; j++) {
                if (array[j]>array[j+1]){
                    int temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                } 
            }
        }
        System.out.println(Arrays.toString(array));

2.【选择排序】(Selection sort)
原理:拿第一个元素跟后面每个元素做对比,如果与预期的顺序不符,则换位。
总结:使用嵌套循环实现,外层循环表示轮次,数组的长度-1
初始条件:int i=0;循环条件:i<array.length-1;
内层循环用于对比和换位
初始条件:int j = i+1
循环条件:j<array.length
升序具体代码:
int[] array = {1,8,5,4,7,3,6,2,9,0};
        for (int i = 0; i < array.length-1; i++) {
            for (int j = i+1; j < array.length; j++) {
                    if (array[i]>array[j]){
                        int temp = array[i];
                        array[i] = array[j];
                        array[j] = temp;
                    }
            }
        }
        System.out.println(Arrays.toString(array));

3.【插入排序】(Insertion sort)

原理:假设第一个数字是最小的(升序排列),从第二个数字开始,依次插入到它
应该放的顺序。从下标为1的元素开始,反复对比左侧元素
插入排序要明显高于冒泡排序和选择排序
总结:使用嵌套循环实现,外层循环表示轮次,数组的长度
初始条件:int i=1;循环条件:i<array.length;
内层循环用于对比和换位
初始条件:int j = i;
循环条件:while(j>0)
升序具体代码:
  int[] array = {1,8,5,4,7,3,6,2,9,0};
        for (int i = 1;i< array.length;i++){
            int j = i;
            while (j>0){
                if (array[j]<array[j-1]){
                    int temp = array[j];
                    array[j] = array[j-1];
                    array[j-1] = temp;
                    j--;
                }else {
                    break;
                }
            }
        }
        System.out.println(Arrays.toString(array));

4.【希尔排序】(Shell sort)
原理:习惯默认增量(gap)为length/2,第一个元素跟1+增量个元素对比,以升序为例
较小在左侧,排完之后整租依旧是无序,接下来增量/2,在进行对比,以此类推。
对于局部有序的数组,插入排序的算法效率是最高的。所以在对比时选取插入排序
最外层循环: 缩减增量
初始条件:int gap = array.length/2;循环条件:gap>0;  条件自变: gap/=2
中间层循环:从与增量大小相等的下标位置开始,向右循环
初始条件:int  i=gap;   
循环条件:i<array.length;
条件自变:i++;
最内层循环: 表示向左找同组元素尝试对比及必要的换位
j:左侧同组元素的下标,即被对比元素的下标,因为可能有多个所以需要循环
初始条件:int j = i-gap; 
循环条件:j>=0;
条件自变:j-=gap;
循环体最内部代码判断对比和换位
升序具体代码:
 int[] array = {1,8,5,4,7,3,6,2,9,0};
        System.out.println(Arrays.toString(array));
        for (int gap = array.length/2; gap >0 ; gap/=2) {
            for (int i = gap; i <array.length ; i++) {
                for (int j = i-gap; j >=0; j -= gap) {
                    if (array[j]>array[j+gap]){
                        int temp = array[j];
                        array[j] = array[j+gap];
                        array[j+gap] = temp;
                    }else {
                        break;
                    }
                }
            }
        }
        System.out.println(Arrays.toString(array));

5.【归并排序】(Merge sort)
原理:将数组一分为二,逐个拆分,直到每个数组长度为1,再重新排序
中间点:上级数组第一个下标+(上级数组最大下标-上级数组第一个下标)/2
左侧:上级数组第一个下标~中间点
右侧:中间点+1~上级数组最大下标。
总结:采用递归思想拆分数组
自定义一个方法返回值为int[]的数组参数为上个数组,起始坐标,结束坐标 
在重新排序合并成新的数组
代码:
public class MergeSort {
    public static void main(String[] args) {
       int[] array = {1,8,5,4,7,3,6,2,9,0};
        System.out.println(Arrays.toString(array));
       int[] finalArray =  mergeSort(array,0, array.length-1);
        System.out.println(Arrays.toString(finalArray));
    }

    /**
     * 这是一个自定义数组
     * @param array 原数组
     * @param start 原数组起始元素下标
     * @param end 原数组末尾元素下标
     * @return 合并后有序的新数组
     */
    public static int [] mergeSort(int[] array,int start,int end){
        if (start==end){
            return new int[]{array[start]};
        }
        int mid = start+(end-start)/2;
        int[] leftArray = mergeSort(array, start, mid);
        int[] rightArray = mergeSort(array,mid+1,end);
        int[] newArray = new int[leftArray.length+rightArray.length];
        int l = 0,r = 0,n = 0;
        while (l < leftArray.length && r < rightArray.length){
            newArray[n++] = leftArray[l]<=rightArray[r]?leftArray[l++]:rightArray[r++];
        }
            while (l<leftArray.length){
                newArray[n++] = leftArray[l++];
            }
            while (r<rightArray.length){
                newArray[n++] = rightArray[r++];
            }
        return newArray;
    }
}
6.【快速排序】(Quick sort)
原理:选取数组中的某个元素,它将作为所有元素排列大小的分界值
将把小于枢纽元的元素放在左侧,其次反之,并不关心放的顺序。在使用分治策略继续划分
最后合并
会有三个区域左侧区域 枢纽元 右侧区域
作为分界值的数组元素称之为:枢纽元(pivot)也可以称之为:主元
将原数组根据枢纽元划分开来的过程称之为:分区
x表示最左侧区域的最大下标
最直观的代码:
public class QuickSort {
    public static void main(String[] args) {
        int[] array = {1,8,5,4,7,3,6,2,9,0};
        quickSort(array,0, array.length-1);
        System.out.println(Arrays.toString(array));
    }

    /**
     * 快速排序本质上没有拆出新数组,也不需要合并,所以该方法没有返回值
     * @param array 原数组
     * @param start 需要被拆分的区间的起始元素下标
     * @param end 需要被拆分的区间的末尾元素下标
     */
    public static void quickSort(int[] array,int start,int end){
         int pivot = array[end];
         int x = start-1;
         for (int i=start;i<end;i++){
             if (array[i]<=pivot){
                 if (i-x>1){
                     int temp = array[i];
                     array[i] = array[x+1];
                     array[x+1] = temp;
                     x++;
                 }else {
                     x = i;
                 }
             }
         }
         if (pivot<array[x+1]){
             array[end] = array[x+1];
             array[x+1] = pivot;
         }
         if (x>start){
             quickSort(array,start,x);
         }
         if (end-x-1>1){
             quickSort(array,x+2,end);
         }
    }
}
另一种方式:
x表示左侧区域的最大下标,y表示右侧区域的最小下标。
public class QuickSort2 {
    public static void main(String[] args) {
        int[] array = {1,8,5,4,7,3,6,2,9,0};
        quickSort(array,0, array.length-1);
        System.out.println(Arrays.toString(array));
    }

    /**
     * 快速排序本质上没有拆出新数组,也不需要合并,所以该方法没有返回值
     * @param array 原数组
     * @param start 需要被拆分的区间的起始元素下标
     * @param end 需要被拆分的区间的末尾元素下标
     */
    public static void quickSort(int[] array,int start,int end){
         int pivot = array[end];
         int x = start;
         int y = end;
         while (x<y){
             while (x<y&&array[y]>pivot){
                 y--;
             }
             while (x<y&&array[x]<pivot){
                 x++;
             }
             if (x<y&&array[x]==array[y]){
                 x++;
             }else {
                 int temp = array[x];
                 array[x] = array[y];
                 array[y] =temp;
             }
             if (x-1>start){
                 quickSort(array,start,x-1);
             }
             if (y+1<end){
                 quickSort(array,y+1,end);
             }
         }
    }
}

**********关于枢纽元的选取*******

第一:随机数

第二:三数中值分割法
int pivot = array[end];

if(end-start>2){

int a = array[start],b = array[(end-start)/2];c = array[end];

if((a-b)*(a-c)<=0){

pivot =a ;

}else if((c-a)*(c-b)<=0){

pivot = c;

}else{

pivot = b;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值