罗李华:天秤座2016年运势

小说:罗李华:天秤座2016年运势作者:安文更新时间:2019-03-23字数:21243

“被一个连古族虎须都敢扯下来的年轻斗圣惦记上我真不知道是该荣幸还是该暗骂自己倒霉啊。”苏千郁闷的说道,摆在他面前无非就是两条路,第一条迦南学院从此消失异火被带走,第二和刘皓交易,不过一样失去异火,但是却有可能和斗圣攀升关系。

宝宝半夜耳痛为哪般

要同时抵抗住龙格的温柔,并控制住体内的气漩,实在不是一件容易的事,哪怕经过了这么多天的修习,仍有些难以把持,当然,这主要是因为他控制气漩的水平虽然进益不小,但龙格的技巧也在他的指点下益发精妙,让人如同隐入春梦之中,一不留神就不想再醒过来。
所有人包括雄霸在内都在目睹着惊世之战,剑圣和刘皓都站在原地一动不动,不过所有人都知道他们的交锋己经开始了,那灭杀一切的气劲充斥在四周,如果谁不好运的话被波及立刻就会身死。

她的双手结印可是一秒六个印,单手结印同样如此,甚至已经到达了六个印的巅峰,随时有可能达到忍界谁也没有达到过的一秒七个印的地步,从某种程度来说水无月白的很多术都是和角都一样等同于瞬发了,可以说水无月白在结印速度方面的天赋真的很高,达到一秒六个印的人在忍界已经是少得跟凤毛麟角一般。

本文描述了LeetCode 148题 sort-list 的解法。

题目描述如下:
Sort a linked list in O(n log n) time using constant space complexity.

题目要求我们在O(n log n)时间复杂度下完成对单链表的排序,我们知道平均时间复杂度为O(n log n)的排序方法有快速排序、归并排序和堆排序。而一般是用数组来实现二叉堆,当然可以用二叉树来实现,但是这么做太麻烦,还得花费额外的空间构建二叉树,于是不采用堆排序。

故本文采用快速排序和归并排序来对单链表进行排序。

快速排序

在一般实现的快速排序中,我们通过首尾指针来对元素进行切分,下面采用快排的另一种方法来对元素进行切分。

我们只需要两个指针p1和p2,这两个指针均往next方向移动,移动的过程中保持p1之前的key都小于选定的key,p1和p2之间的key都大于选定的key,那么当p2走到末尾时交换p1与key值便完成了一次切分。

图示如下:

代码如下:

public ListNode sortList(ListNode head) {
    //采用快速排序
   quickSort(head, null);
   return head;
}
public static void quickSort(ListNode head, ListNode end) {
    if (head != end) {
        ListNode node = partion(head, end);
        quickSort(head, node);
        quickSort(node.next, end);
    }
}

public static ListNode partion(ListNode head, ListNode end) {
    ListNode p1 = head, p2 = head.next;

    //走到末尾才停
    while (p2 != end) {

        //大于key值时,p1向前走一步,交换p1与p2的值
        if (p2.val < head.val) {
            p1 = p1.next;

            int temp = p1.val;
            p1.val = p2.val;
            p2.val = temp;
        }
        p2 = p2.next;
    }

    //当有序时,不交换p1和key值
    if (p1 != head) {
        int temp = p1.val;
        p1.val = head.val;
        head.val = temp;
    }
    return p1;
}

归并排序

归并排序应该算是链表排序最佳的选择了,保证了最好和最坏时间复杂度都是nlogn,而且它在数组排序中广受诟病的空间复杂度在链表排序中也从O(n)降到了O(1)。

归并排序的一般步骤为:

  1. 将待排序数组(链表)取中点并一分为二;
  2. 递归地对左半部分进行归并排序;
  3. 递归地对右半部分进行归并排序;
  4. 将两个半部分进行合并(merge),得到结果。

首先用快慢指针(快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点)的方法找到链表中间节点,然后递归的对两个子链表排序,把两个排好序的子链表合并成一条有序的链表。

代码如下:

public ListNode sortList(ListNode head) {
    //采用归并排序
    if (head == null || head.next == null) {
        return head;
    }
    //获取中间结点
    ListNode mid = getMid(head);
    ListNode right = mid.next;
    mid.next = null;
    //合并
    return mergeSort(sortList(head), sortList(right));
}

/**
 * 获取链表的中间结点,偶数时取中间第一个
 *
 * @param head
 * @return
 */
private ListNode getMid(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    //快慢指针
    ListNode slow = head, quick = head;
    //快2步,慢一步
    while (quick.next != null && quick.next.next != null) {
        slow = slow.next;
        quick = quick.next.next;
    }
    return slow;
}

/**
 *
 * 归并两个有序的链表
 *
 * @param head1
 * @param head2
 * @return
 */
private ListNode mergeSort(ListNode head1, ListNode head2) {
    ListNode p1 = head1, p2 = head2, head;
   //得到头节点的指向
    if (head1.val < head2.val) {
        head = head1;
        p1 = p1.next;
    } else {
        head = head2;
        p2 = p2.next;
    }

    ListNode p = head;
    //比较链表中的值
    while (p1 != null && p2 != null) {

        if (p1.val <= p2.val) {
            p.next = p1;
            p1 = p1.next;
            p = p.next;
        } else {
            p.next = p2;
            p2 = p2.next;
            p = p.next;
        }
    }
    //第二条链表空了
    if (p1 != null) {
        p.next = p1;
    }
    //第一条链表空了
    if (p2 != null) {
        p.next = p2;
    }
    return head;
}

完整代码放在:
https://github.com/morethink/algorithm/blob/master/src/algorithm/leetcode/SortList.java

参考文档

  1. 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)

编辑:通辛纯海

发布:2019-03-23 15:11:14

当前文章:http://ayzwzx.cn/content/2019-01/26/content_68670.html

家长观念中的误区 姓名谐音搞笑大全 人民大会堂的牛排 易经智慧 如何识破渣男长长的套路? 朱丹,爱自己的你好美 吃饭太晚有7大危险? 也许我的春天终于来了。。。

93456 52552 40227 23388 40232 26929 97320 59937 68594 17833 64468 61676 47401 93287 51910 75254 95087 49156 62911 51554

我要说两句: (0人参与)

发布