常見鏈表操作-兩個有序表的合併(JAVA實現)

問題

將兩個有序單鏈表A和B,合併成C,如下圖。

解決思路

同時從兩個鏈表的頭節點開始遍歷,比較當前節點大小,將小的節點添加到C鏈表中,然後遍歷。

非遞歸寫法

/**
 * 鏈表ADT
 * 
 * @author wangtao
 * @param <T>
 */
public class LinkADT<T> {

    /**
     * 單鏈表節點
     * 
     * @author wangtao
     * @param <T>
     */
    private static class SingleNode<T> {
        public SingleNode<T> next;
        public T data;

        public SingleNode(T data) {
            this.data = data;
        }

        public T getNextNodeData() {
            return next != null ? next.data : null;
        }
    }
    
    /**
     * 有序鏈表合併,非遞歸
     * 
     * @param nodeA
     * @param nodeB
     * @return
     */
    public static SingleNode<Integer> mergeV1(SingleNode<Integer> nodeA, SingleNode<Integer> nodeB) {
        if (nodeA == null) {
            return nodeB;
        } else if (nodeB == null) {
            return nodeA;
        }

        // 初始化nodeC
        SingleNode<Integer> nodeC = new SingleNode<Integer>(null);
        // 定義當前節點
        SingleNode<Integer> currentNode = nodeC;

        // 遍歷A和B,直到末尾
        while (nodeA != null || nodeB != null) {
            SingleNode<Integer> nextNode = new SingleNode<Integer>(null);
            // 找出較小的節點
            if (compareNode(nodeA, nodeB) <= 0) {
                nextNode.data = nodeA.data;
                nodeA = nodeA.next;
            } else {
                nextNode.data = nodeB.data;
                nodeB = nodeB.next;
            }

            // 添加較小的節點
            currentNode.next = nextNode;
            currentNode = currentNode.next;
        }

        // 去掉沒有用的頭結點
        nodeC = nodeC.next;
        
        return nodeC;
    }
    
    private static int compareNode(SingleNode<Integer> node1, SingleNode<Integer> node2) {
        if (node1 == null) {
            return 1;
        } else if (node2 == null) {
            return -1;
        }

        if (node1.data == null) {
            return -1;
        } else if (node2.data == null) {
            return 1;
        }

        return node1.data.compareTo(node2.data);
    }
}

這種不是很簡潔,尤其是最後還要去掉一個頭結點,感覺很累贅。

遞歸寫法

與前面重複的代碼就不貼了,直接上核心代碼。

    /**
     * 有序鏈表合併,遞歸
     * 
     * @param nodeA
     * @param nodeB
     * @return
     */
    private static SingleNode<Integer> mergeV2(SingleNode<Integer> nodeA, SingleNode<Integer> nodeB) {
        SingleNode<Integer> result;

        if (nodeA == null) {
            return nodeB;
        } else if (nodeB == null) {
            return nodeA;
        }

        // 找出較小的節點
        if (compareNode(nodeA, nodeB) <= 0) {
            result = nodeA;
            nodeA = nodeA.next;
        } else {
            result = nodeB;
            nodeB = nodeB.next;
        }

        result.next = mergeV2(nodeA, nodeB);
        return result;
    }

遞歸的代碼看起來清爽很多,看起來也比較好理解。

完整代碼請參考:
https://github.com/wanf425/Algorithm/blob/master/src/com/wt/adt/LinkADT.java

博文地址:
https://www.taowong.com/blog/2018/10/14/data-strutctures-and-algorithm-03.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章