一些常见的排序算法(二)

一、堆排序

如果还不了解满二叉树完全二叉树最大堆(或大顶堆)的话,可以先了解一下。因为大顶堆要求根节点的元素大于其孩子,这样得到大顶堆的堆顶的元素肯定是

序列中的最大值。清楚这些,就很容易理解堆排序了:先构造大顶堆,将大顶堆中堆顶元素与序列中末尾元素交换。这样序列尾部的发生交换的元素是排列过的,剩下的未排列的元素重新构造大顶堆,继续执行上面步骤。

用简单的图来表示

import java.util.Arrays;

public class HeapSort {

    public static void main(String[] args) {
        
        int[] array = {1, 4, 9, 12, 5, 7, 10, 22, 11, 32};
    
        //1、构造大顶堆:从最后一个非叶子节点开始,从按从右至左、从下到上的顺序遍历
        for(int i = array.length/2 - 1; i >= 0; i--) {
            heapSort(array, array.length, i);
        }
        
        for (int i = array.length - 1; i > 0; i--) {
            //2、最后一个非叶子节点和头结点交换
            swap(array, i, 0);
            //3、将余下的数组重新构造大顶堆
            heapSort(array, i, 0);
        }
  
        System.out.println(Arrays.toString(array));
    }
    
    /**
     * 排序:(在length长度内)将父节点和其子节点比较,将最大值放到父节点
     * @param array
     * @param length 要排序的数组的长度
     * @param i    索引为i的父节点
     */
    public static void heapSort(int[] array, int length, int i) {
        //最大值指针
        int big = i;
        //左孩子
        int left = 2 * i + 1; 
        //右孩子
        int right = left + 1; 
        if(left <= length - 1 && array[left] > array[big]) {
            big = left;
        }
        if(right <= length - 1 && array[right] > array[big]) {
            big = right;
        }
        //指针指向交换的位置,递归
        if(array[i] != array[big]) {
            swap(array, i, big);
            heapSort(array, length, big);
        }
    }
    
    public static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b]= temp; 
    }
}

二、快速排序

快速排序其实是一种分治法的思想,将问题分解和原问题类似的但规模小的问题,递归求解。快速排序直接说算法的思想感觉不是很好理解,我是这样看快速排序的:总是将一组序列的第一个值作为中间值(序列中中间值左边的数都比中间值小,右边的数都比中间值大),将中间值放到序列中正确的位置。下面我们再看快速排序的具体实现:

1、取一个数作为中间数

2、将序列中比它大的数全放右边,比它小的数全放左边

3、对中间数的左右边的小序列重复执行第二步,直到小序列中只有一个数

只对序列进行一次取中间值排序:

代码:

import java.util.Arrays;

public class QuickSort {

    /**
     * 序列中比某个数(arr[l])大的放arr[l]一边,比它小的放arr[l]另一边,然后返回这个数的索引下标
     * @param arr
     * @param l 从左开始的索引下标
     * @param r    从右开始的索引下标
     * @return 
     */
    public static int position(int[] arr, int l, int r) {
        int pointer = arr[l];
        while (l < r) {
            while (l < r && arr[r] >= pointer) {
                r--; 
            }
            //这个数比pointer小,把这个数放arr[l]另一边
            if (arr[r] < pointer) {
                arr[l] = arr[r];
                l++;
            }
            while (l < r && arr[l] <= pointer) {
                l++;
            }
            //这个数比pointer大,把这个数放arr[l]另一边
            if (arr[l] > pointer) {
                arr[r] = arr[l];
                r--;
            }
        }
        arr[l] = pointer;
        return l;
    }

    /**
     * 分治法思想:将问题分解和原问题类似的但规模小的问题,递归求解
     * @param arr
     * @param i
     * @param j
     */
    public static void sort(int[] arr, int i, int j) {

        if(i < j) {
            int k = position(arr, i, j);
            System.out.println("i:" + i);
            System.out.println("j:" + j);
            sort(arr, i, k - 1);
            sort(arr, k + 1, j);
        }
    }

    public static void main(String args[]) {
        int arr[] = { 6, 10, 3, 8, 9, 1, 9 };
        int n = arr.length;
        //position(arr, 0, arr.length - 1);
        sort(arr, 0, n - 1);

        System.out.println(Arrays.toString(arr));
    }

}

猜你喜欢

转载自www.cnblogs.com/CCLi/p/10110113.html