java 基本排序

/**
 * 快速排序
 * 分治、递归思想
 * 如果要排序数组中下标从 p 到 r 之间的一组数据,我们选择 p 到 r 之间的任意一个数据作为 pivot (分区点)。 我们遍历 p 到 r 之间的数据,将小于 pivot 的放到左边,将大于 pivot 的放右边,pivot 放到中间。经过这一步骤之后,数组 p 到 r 之间的数据就被分成了三个部分,前面 p 到 q-1 之间都是小于pivot的,中间是pivot,后面的q+1到r之间是大于pivot的,根据分治、递归思想,我们可以用递归排序下标从p到q-1之间的数据和下标q+1到r之间的数据,直到区间缩小为1,就说明所有的都是有序了
 * 最好和平均复杂度为 O(nlogn),最坏时间复杂度为O(n²),不稳定的原地排序算法
 *
 * @param data
 */
public static void quickSort(int[] data){
    quickSortInternally(data,0,data.length - 1);
}

private static void quickSortInternally(int[] data,int p,int r){
    if(p>=r) return;
    int midden = getMidden(data,p,r);
    quickSortInternally(data,p,midden - 1);
    quickSortInternally(data,midden + 1,r);
}

private static int getMidden(int[] data,int p,int r){
    int i = p;
    int pivot = data[r];
    for (int j=p;j<r ;j++){
        if(data[j]<pivot){
            int temp = data[i];
            data[i] = data[j];
            data[j] = temp;
            i++;
        }
    }
    int temp = data[i];
    data[i]= data[r];
    data[r] = temp;
    System.out.println("i="+i);
    return i;
}

/**
 * 归并排序
 * 分治、递归思想
 * 要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分进行排序,然后将排序好的两部分合并
 * 最好、最坏、平均时间复杂度都为 O(nlogn),需要空间复杂度为O(n),是稳定的非原地算法
 * @param data
 * @param p
 * @param r
 */
public static void mergeSort(int[] data,int p,int r){
    //终止条件
    if(p>=r) return;
    //防止 p和r过大,(p+r)溢出
    int q = p +(r- p)/2;
    //分治递归
    mergeSort(data,p,q);
    mergeSort(data,q + 1,r);
    // 将A[p...q]和A[q+1...r]合并为A[p...r]
    merge(data,p,q,r);
}

private static void merge(int[] data,int p,int q,int r){
    int i= p;
    int j = q +1;
    int k = 0;
    int[] temp = new int[r-p + 1];
    while (i<=q && j<=r){
        if(data[i]<=data[j]){
            temp[k++] = data[i++];
        }else {
            temp[k++] = data[j++];
        }
    }
    // 判断哪个子数组中有剩余的数据
    int start = i;
    int end = q;
    if(j<=r){
        start = j;
        end = r;
    }
    // 将剩余的数据拷贝到临时数组tmp
    while (start <= end){
        temp[k++]=data[start ++];
    }
    //将临时变量拷贝回a[p..r]
    for (i=0;i<=r-p;i++){
        data[p+i] = temp[i];
    }
}

/**
 * 冒泡排序,只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求,如果不满足就让他互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复n次,就完成了n个数据的排序工作
 * 为原地稳定算法,时间复杂度为n²,最好时间复杂度为n,平均和最坏情况为n²
 * @param data
 */
public static void bubbleSort(int[] data){
    if(data ==null || data.length <= 1) return;
    int n = data.length;
    for (int i=0;i<n;i++){
        //提前退出标识
        boolean flag =false;
        for(int j=0;j<n-i-1;j++){
            if(data[j]>data[j+1]){
                int temp = data[j];
                data[j]  = data[j+1];
                data[j+1] = temp;
                flag = true;
            }
        }
        if(!flag) break;
    }
}

/**
 * 插入排序
 * 首先我们将数组中数据分为两个区间,已排序和未排序区间。初始化时已排序区间只有一个元素,就是数组的第一个元素。插入算法的核心思想是取未排序算法中的元素,在已排序算法中找到合适的插入位置将其插入
 * 原地稳定算法,时间复杂度为O(n2),但它赋值次数比冒泡的少(插入赋值一次,冒泡3次),所以效率比冒泡的高
 * @param data
 */
public static void insertSort(int[] data){
    if(data == null || data.length <= 1) return;
    for (int i=1;i<data.length;i++){
        int val = data[i];
        int j = i - 1;
        //查找插入的位置
        for(; j>=0 ;j--){
            if(data[j]>val){
                //数据移动
                data[j+1] = data[j];
            }else {
                break;
            }
        }
        //找到位置插入
        data [j + 1] = val;
    }
}

public static void main(String[] args) {
    int[] data ={6,11,3,9,8};
    quickSort(data);
    System.out.println("快排结果为"+ Arrays.toString(data));
    data =new int[]{6,11,3,9,8};
    mergeSort(data,0,data.length-1);
    System.out.println("归并排序结果为"+ Arrays.toString(data));
    data =new int[]{6,11,3,9,8};
    bubbleSort(data);
    System.out.println("冒泡排序结果为"+ Arrays.toString(data));
    data =new int[]{6,11,3,9,8};
    insertSort(data);
    System.out.println("插入排序结果为"+ Arrays.toString(data));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章