CodeTop089 手撕堆排序

这个的话没什么好说的 就是手撕排序算法.这里买一送一,先手撕一个快排.

//快排
    public static void QuickSort(int[] nums){
        if (nums.length<=0) return;
        QuickSort(nums,0,nums.length-1);
    }

    public static void QuickSort(int[] nums,int left,int right){
        if (left>=right) return;
        int random = (int) Math.random()*(right-left+1);
        swap(nums,left+random,right);
        int[] func = func(nums,left,right);
        QuickSort(nums,left,func[0]);
        QuickSort(nums,func[1],right);
    }

    public static int[] func(int[] nums,int left,int right){
        int low = left-1;
        int high = right;

        while (left<high){
            if (nums[left]<nums[right]){
                swap(nums,++low,left++);
            }else if (nums[left]>nums[right]){
                swap(nums,--high,left);
            }else{
                left++;
            }
        }

        swap(nums,high,right);
        return new int[]{low,high+1};
    }

    public static void swap(int[] nums,int i,int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

*堆排序正式开始:首先堆排序中的几个重要概念:

  • (因为是前序遍历)在数组中i位置的左孩子是(2^i)+1 右孩子是(2^i)+2
  • 任意位置index的父节点是(index-1)/2
  • 堆排序最重要的两个过程,一个是向上走,一个是想下走.分别对应于heapInsert()和heapify()

具体看代码:

//堆排序 在数组中i位置的左孩子是(2^i)+1 右孩子是(2^i)+2  (因为是前序遍历)
    //因此任意位置index的父节点是(index-1)/2
    public static void heapSort(int[] arr) {
        if (arr==null || arr.length<2) return;

        //先得到一个大顶堆
        for (int i=0;i<arr.length;i++){
            heapInsert(arr,i);
        }

        //在得到大根堆后 对顶元素就是最大值 将它交换到尾部去
        int size = arr.length;
        swap(arr,0,--size);//将大顶堆最大位置和最后一个位置做交换  然后size--

        while (size>0){
            //将剩下的元素进行调整 继续维持大根堆
            heapify(arr,0,size);
            //在得到大根堆后 对顶元素就是最大值 将它交换到尾部去
            swap(arr,0,--size);
        }
    }


    //某个数现在处于index位置,往上继续移动  (往上走)
    public static void heapInsert(int[] arr,int index){
        //和自己的父节点作比较 只要大于父节点就做交换
        while (arr[index]>arr[(index-1)/2]){
            swap(arr,index,(index-1)/2);
            index = (index-1)/2;
        }
    }

    //将新的节点调整为大顶堆  某个数现在index位置,能否往下移动  (往下走)
    public static void heapify(int[] arr,int index,int heapsize){
        int left = index*2+1;//左孩子的下标
        while(left<heapsize){
            //找到左右孩子中的最大值  left+1就是右孩子
            int largest = (left+1<heapsize) && arr[left]<arr[left+1] ? left+1:left;
            /*
            注意!!!!如果写成largest = (left+1arr[left+1] ? left:left+1;就会出错
            arr[left]>arr[left+1] ? left:left+1这一段的逻辑是没有问题的.但是前面还有一个右节点判断的问题(left+1

            //父和最大的孩子之间,谁的值大,就把下标给largest
            largest = arr[largest]>arr[index]? largest:index;

            if (largest==index){
                break;
            }

            swap(arr,largest,index);//较大的孩子和父做交换
            index = largest;
            left = index*2+1;//左孩子的下标
        }


    }

你可能感兴趣的:(CodeTop刷题笔记,深度优先,leetcode,算法,排序算法,java)