Sort List[leetcode] 由归并排序的递归和循环,到本题的两种解法

归并排序可以有两种思路----top-down 和 bottom-up

top-down:

递归实现,将数组分成两半,分别处理;再合并。

伪代码如下:

split ( A[], l, r)
{
	if ( r - l < 2) return;
	m = (r + l) / 2;
	split ( A, l, m); //split A[l…m-1]
	split ( A, m, r); //split A[m…r-1]
	merge ( A, l, m, e); //merge A[l…m-1] and A[m…e-1]
}

bottom-up:

循环实现,将数组看做n个长度为1的组数组。

用width控制每次merge的子数组长度,width每次翻倍

伪代码如下:

sort ( A[], n)
{
	for (width = 1; width < n; width *= 2)
	{
		for (i = 0; i < n; i += 2 * width)
		{
			merge(A, i, min(i + w, n), min(i + 2 * w, n));
		}
	}
}

Sort list中使用链表,不能在O(1)的时间内访问任意节点,同时注意要处理尾部节点的next,置为NULL

和上面的伪代码类似,首先实现merge函数:

    ListNode * merge(ListNode * h1, int s1, ListNode * h2, int s2)
    {
        if (h2 == NULL) return h1;
        ListNode * h;
        if (h1->val < h2->val)
            h = advance(h1, s1);
        else
            h = advance(h2, s2);
        ListNode * cur = h;
        while (s1 && s2)
        {
            if (h1->val < h2->val)
                cur->next = advance(h1, s1);
            else
                cur->next = advance(h2, s2);
            cur = cur->next;
        }
        if (s1)
        {
            cur->next = h1;
            while(s1) advance(h1, s1);
        }
        if (s2)
        {
            cur->next = h2;
            while(s2) advance(h2, s2);
        }
        return h;
    }

    ListNode * advance(ListNode * (& n), int & size)
    {
        ListNode * temp = n;
        if (size == 1)  n->next = NULL;
        n = n->next;
        size--;
        return temp;
    }

同时实现工具函数,访问任意位置节点

ListNode * getNode(ListNode * head, int len)
    {
        while (len -- && head) head = head->next;
        return head;
    }

循环版本主函数如下:

ListNode *sortList(ListNode *head) {
        ListNode * cur = head;
        int size = 0;
        while (cur)
        {
            size ++;
            cur = cur->next;
        }

        ListNode * pre;
        for (int w = 1; w <= size; w *= 2)
        {
            cur = head;
            for (int i = 0; i < size; i+= w*2)
            {
                ListNode * h1 = cur, * h2 = getNode(cur, w), * next = getNode(cur, 2 * w);
                cur = merge(h1, min(w, size - i), h2, min(w, size - i - w));
                if (i == 0)
                    head = cur;
                else
                    pre->next = cur;
                pre = getNode(cur, min(2 * w, size - i) - 1);
                cur = next;
            }
        }
        return head;
    }

递归版本主函数如下:

    ListNode *sortList(ListNode *head) {
        ListNode * cur = head;
        int size = 0;
        while (cur)
        {
            size ++;
            cur = cur->next;
        }
        return sort(head, size - size / 2, getNode(head, size - size / 2), size / 2);
    }

    ListNode * sort(ListNode * h1, int s1, ListNode * h2, int s2)
    {
        if (s1 == 0) return h2;
        if (s2 == 0) return h1;
        h1 = sort(h1, s1 - s1 / 2, getNode(h1, s1 - s1 / 2), s1 / 2);
        h2 = sort(h2, s2 - s2 / 2, getNode(h2, s2 - s2 / 2), s2 / 2);
        return merge(h1, s1, h2, s2);
    }
时间: 2024-10-25 22:38:13

Sort List[leetcode] 由归并排序的递归和循环,到本题的两种解法的相关文章

[LeetCode] Validate Binary Search Tree (两种解法)

Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than the node's key. The right subtree of a node contains only nodes with keys

Gas Station [leetcode] 的两种解法

由于gas总量大于cost总量时,一定可以绕所有城市一圈. 第一种解法: 假设一开始有足够的油,从位置i出发,到位置k时剩余的油量为L(i,k). 对任意的k,L(i,k)根据i的不同,只相差常数. 我们只需要找到最小的L(0, k)对应的k,k+1为所求. 代码如下: int canCompleteCircuit(vector<int> &gas, vector<int> &cost) { int start = 0; int curGas = 0, minGas

迭代、递归替代循环

循环(迭代)与递归的区别 1. 递归算法与迭代算法的设计思路区别在于:函数或算法是否具备收敛性,当且仅当一个算法存在预期的收敛效果时,采用递归算法才是可行的,否则,就不能使用递归算法. 当然,从理论上说,所有的递归函数都可以转换为迭代函数,反之亦然,然而代价通常都是比较高的. 但从算法结构来说,递归声明的结构并不总能够转换为迭代结构,原因在于结构的引申本身属于递归的概念,用迭代的方法在设计初期根本无法实现,这就像动多态的东西并不总是可以用静多态的方法实现一样.这也是为什么在结构设计时,通常采用递

4.比较排序之归并排序(递归)

归并排序里运用到算法里很重要的一个思想——分治法:将原问题分解为几个规模较小但类似于原问题的子问题——<算法导论>.在每一层递归中都有3个步骤: 1.分解问题 2.解决问题 3.合并问题的解 举例待排序数组:{6, 5, 3, 1, 7, 2, 4},将它原始序列做分解. 可以经过不断的递归分解可以看到已经把原始数组序列不断分解为最小单位,接下来不妨将它们看做是二叉树的叶子节点. 将他们进行两两归并排序形成二叉树(也称为2路归并算法),可见二叉树的根节点即为最终序列.在这个过程中我们完成了剩余

归并排序的递归与非递归实现java

package com.edu.hpu.sort.merge; import com.edu.hpu.sort.Sort; public class MergeSort extends Sort { @Override public int[] doSort(int[] arr) { return mergeSort2(arr, 0, arr.length - 1); } @SuppressWarnings("unused") private int [] mergeSort(int

归并排序(非递归,Java实现)

归并排序(非递归): public class MergeSort { /** * @param arr 待排序的数组 * @param left 本次归并的左边界 * @param mid 本次归并的中间位置,也就是分界线 * @param right 本次归并的右边界 * @param <T> 泛型 * @local aux 辅助空间(Auxiliary Space) */ private static <T extends Comparable<? super T>&g

归并排序 分治+递归

0      1    2     3     4     5     6     7     8   //下标 {  9  ,  4  ,  3  ,  7  ,  3  ,  8  ,  2  ,  4  ,  8  }//通过mergesort函数递归 来切 开始的时候fir=0, las=8, mid=4  所以下标0-4,分为前组   5-8分为后组 {  9  , 4   ,  3  ,  7  ,  3 }{ 8   , 2   , 4  ,  8  } {  9   , 4  ,

Sort Colors leetcode java

题目: Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, we will use the integers 0, 1, and 2 to represent the color red, white, an

【HackerRank】Insertion Sort Advanced Analysis(归并排序求数列逆序数对)

Insertion Sort is a simple sorting technique which was covered in previous challenges. Sometimes, arrays may be too large for us to wait around for insertion sort to finish. Is there some other way we can calculate the number of times Insertion Sort