排序算法专题——数组链表排序

本文探讨了快速排序和堆排序两种高效排序算法,通过代码实例展示如何利用随机化partition和最大堆构建进行排序,包括partition过程、交换操作及递归调用。涉及的关键技术有随机化选择、堆数据结构和链表排序的优化方法。

排序算法专题

数组排序

快速排序
  • 每次partition之后,partition的节点位置已经定好,需要对[start, partition-1] 和[partition + 1, end]再排序
  • 如果start >= end后跳出循环,说明排序结束
class Demo{
  private int randomIndex(int start, int end) {
        int index = new Random().nextInt(end - start + 1);
        return start + index;
    }

    private void swap(int[] nums, int index1, int index2) {
        int tmp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = tmp;
    }

    private int partition(int[] nums, int start, int end) {
        if (start > end || nums == null) {
            return -1;
        }
        int small = start - 1;
        int index = randomIndex(start, end);
        swap(nums, end, index);
        for (int i = start; i < end; i++) {
            if (nums[i] < nums[end]) {
                small++;
                if (small != i) {
                    swap(nums, small, i);
                }
            }
        }
        small++;
        swap(nums, end, small);
        return small;
    }

    public void quickSort(int[] nums, int start, int end) {
        if (start >= end) {
            return;
        }
        int partition = partition(nums, start, end);
        quickSort(nums, start, partition - 1);
        quickSort(nums, partition + 1, end);
    }  
}   

堆排序
class HeapSort {

    private void swap(int[] nums, int index1, int index2) {
        int tmp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = tmp;
    }

    public void buildMaxHeap(int[] nums) {
        int end = nums.length - 1;
        for (int i = end / 2; i >= 0; i--) {
            downToHeap(nums, i, end);
        }
    }


    // 对下标为i的节点,将其构造为i的最大堆
    public void downToHeap(int[] nums, int i, int end) {
        while (i * 2 + 1 <= end) {
            int left = i * 2 + 1;
            int right = i * 2 + 2;
            int max;
            if (left <= end && nums[left] > nums[i]) {
                max = left;
            } else {
                max = i;
            }
            if (right <= end && nums[right] > nums[max]) {
                max = right;
            }
            if (max != i) {
                swap(nums, max, i);
                i = max;
            } else {
                break;
            }
        }
    }

    public void heapSort(int[] nums) {
        buildMaxHeap(nums);
        int end =  nums.length - 1;
        for (int i = end; i >= 1; i--) {
            swap(nums, i, 0);
            end--;
            downToHeap(nums, 0, end);
        }
    }
}
堆排序
class MergeSort {

    int[] tmp;
    public int[] sortArray(int[] nums) {
        tmp = new int[nums.length];
        mergeSort(nums, 0, nums.length - 1);
        return nums;
    }

    private void mergeSort(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        int mid = (left + right) / 2;
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);
        int index = 0;
        int l = left;
        int r = mid + 1;
        while (l <= mid && r <= right) {
            if (nums[l] < nums[r]) {
                tmp[index++] = nums[l++];
            } else {
                tmp[index++] = nums[r++];
            }
        }
        while (l <= mid) {
            tmp[index++] = nums[l++];
        }
        while (r <= right) {
            tmp[index++] = nums[r++];
        }
        for (int i = 0; i < right - left + 1; i++) {
            nums[i + left] = tmp[i];
        }
    }
}

链表排序

快速排序
public static ListNode quickSort(ListNode begin, ListNode end) {
    //判断为空,判断是不是只有一个节点
    if (begin == null || end == null || begin == end)
        return begin;
    //从第一个节点和第一个节点的后面一个几点
    //begin指向的是当前遍历到的最后一个<= nMidValue的节点
    ListNode first = begin;
    ListNode second = begin.next;

    int nMidValue = begin.val;
    //结束条件,second到最后了
    while (second != end.next && second != null) {//结束条件
        //一直往后寻找<=nMidValue的节点,然后与fir的后继节点交换
        if (second.val < nMidValue) {
            first = first.next;
            //判断一下,避免后面的数比第一个数小,不用换的局面
            if (first != second) {
                int temp = first.val;
                first.val = second.val;
                second.val = temp;
            }
        }
        second = second.next;
    }
    //判断,有些情况是不用换的,提升性能
    if (begin != first) {
        int temp = begin.val;
        begin.val = first.val;
        first.val = temp;
    }
    //前部分递归
    quickSort(begin, first);
    //后部分递归
    quickSort(first.next, end);
    return begin;
}
归并排序
public ListNode mergeSort(ListNode head){
        if(head==null || head.next==null)    return head;
 
        ListNode mid = getMid(head);//获取链表中间节点
 
        //把链表从之间拆分为两个链表:head和second两个子链表
        ListNode second = mid.next;
        mid.next = null;
 
        //对两个子链表排序
        ListNode left = mergeSort(head);
        ListNode right = mergeSort(second);
 
        return merge(right,left);      
    }
 
    //两个有序链表的归并
    private ListNode merge(ListNode l1,ListNode l2){
      //辅助节点,排好序的节点将会链接到dummy后面
        ListNode dummy = new ListNode(0);
 
        ListNode tail = dummy;//tail指向最后一个排好序的节点
        while(l1!=null&&l2!=null){
            if(l1.val<=l2.val){
                tail.next = l1;
                l1 = l1.next;
            }else{
                tail.next = l2;
                l2 = l2.next;
            }
            tail = tail.next; //移动tail指针        
        }
 
        if(l1!=null)
            tail.next = l1;
        else
            tail.next = l2;
 
        return dummy.next;
 
    }
 
    //返回链表之间节点
    private ListNode getMid(ListNode head){
        if(head==null ||head.next==null)    return head;
 
        ListNode slow = head;
        ListNode faster = head.next;
        while(faster!=null&&faster.next!=null){
            slow = slow.next;
            faster = faster.next.next;
        }
        return slow;
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值