链表问题----将单向链表按某值划分成左边小中间相等右边大的形式

Posted demrystv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表问题----将单向链表按某值划分成左边小中间相等右边大的形式相关的知识,希望对你有一定的参考价值。

将单向链表按某值划分成左边小、中间相等、右边大的形式

  

  给定一个单向链表的头节点head,节点的值类型是整数,再给定一个整数 pivot,实现一个调整链表的函数,使得左半部分的值都是小于pivot的节点,中间部分都是等于pivot的节点,右边部分都是大于pivot的节点,对于左半部分、中间、右半部分内部的顺序没有要求。

  如果对于三部分内部的顺序也是有要求,即内部顺序各个节点的顺序与原来链表中的各个节点的先后顺序相同。

 

  【解析】

  普通问题:

  首先遍历一遍链表,得到链表的长度,将链表元素依次放到数组中,然后利用类似于快速排序中的partition 思想进行分割。

  进阶问题:

  1.将链表分为三部分:small,equal,big

            small:1->2->null

            equal:5->5->null

            big:9->8->null

  2.将small、equal、big三个链表重新串起来

  3.整个过程需要特别注意对null节点的判断和处理

  

package com.test;

import com.test.ListNode;

/**
 * Created by Demrystv.
 */
public class ListNodePartition {

    /**
     * 普通问题
     * 时间复杂度是 O(N),空间复杂度是 O(N)
     */
    /*
    首先遍历一遍链表,得到链表的长度,将链表元素依次放到数组中,然后利用类似于快速排序中的partition 思想进行分割
     */
    public ListNode listPartition1(ListNode head, int pivot){
        if (head == null){
            return head;
        }
        int i = 0;
        ListNode cur = head;
        while (cur != null){
            i++;
            cur = cur.next;
        }

        // 将链表中的每个元素依次放入到数组中
        ListNode[] nodeArr = new ListNode[i];
        i = 0;
        cur = head;
        for (i = 0; i != nodeArr.length; i++){
            nodeArr[i] = cur;
            cur = cur.next;
        }
        // 进行类似快速排序的partition
        arrPartition(nodeArr,pivot);

        // 重新连接各个链表节点
        for (i = 1; i != nodeArr.length; i++){
            nodeArr[i - 1].next = nodeArr[i];
        }
        nodeArr[i - 1].next = null;
        return nodeArr[0];
    }

    public void arrPartition(ListNode[] nodeArr, int pivot){
        int small = -1;
        int big = nodeArr.length;
        int index = 0;
        while (index != big){
            if (nodeArr[index].val < pivot){
                swap(nodeArr, ++small, index);
            }else if (nodeArr[index].val == pivot){
                index++;
            }else {
                swap(nodeArr, --big, index);
            }
        }
    }

    public void swap(ListNode[] nodeArr, int a, int b){
        ListNode temp = nodeArr[a];
        nodeArr[a] = nodeArr[b];
        nodeArr[b] = temp;
    }


    /**
     *  进阶问题: 保证各部分内部的顺序与原来链表中各个节点的顺序相同
     *  时间复杂度是 O(N),空间复杂度是 O(1)
     *  考察 利用有限的几个变量来调整链表的代码实现能力。
     */
    /*
    1.将链表分为三部分:small,equal,big
                      small:1->2->null
                      equal:5->5->null
                      big:9->8->null
    2.将small、equal、big三个链表重新串起来
    3.整个过程需要特别注意对null节点的判断和处理
     */
    public ListNode listPartition2(ListNode head, int pivot){

        // 将链表分为small、equal、big
        ListNode sH = null;
        ListNode sT = null;
        ListNode eH = null;
        ListNode eT = null;
        ListNode bH = null;
        ListNode bT = null;
        ListNode next = null;// 保存下一个节点

        //将所有的节点依次保存在三个链表中
        while (head != null){
            // 将head节点独立出来
            next = head.next;
            head.next = null;

            if (head.val < pivot){
                if (sH == null){
                    sH = head;
                    sT = head;
                }else {
                    sT.next = head;
                    sT = head;
                }
            }else if (head.val == pivot){
                if (eH == null){
                    eH = head;
                    eT = head;
                }else {
                    eT.next = head;
                    eT = head;
                }
            }else {
                if (bH == null){
                    bH = head;
                    bT = head;
                }else {
                    bT.next = head;
                    bT = head;
                }
            }
            head = next;
        }

        // 小的和相等的重新连接
        if (sT != null){
            sT.next = eH;
            eT = eT == null ? sT : eT;
        }
        // 所有的重新连接
        if (eT != null){
            eT.next = bH;
        }

        // 判断头节点是否为空
        return sH != null ? sH : eH != null ? eH :bH;
    }
}

 

以上是关于链表问题----将单向链表按某值划分成左边小中间相等右边大的形式的主要内容,如果未能解决你的问题,请参考以下文章

链表问题-----排序

每日一题 为了工作 2020 0323 第二十一题

关于链表的一个小程序

在 C++ 中使用链表按字母顺序对字符串进行排序

将单向链表进行分组

华为OD机试 - 单向链表中间节点(Java & JS & Python)