二叉樹中的和為某一值的路徑


一,問題描述

給定一棵二叉樹 和 一個整數,打印出二叉樹中結點值的和為給定的整數的所有路徑。注意:路徑是指:從二叉樹的根結點開始的,往下一直到葉子結點過程中 所經過的結點(包括根結點(起點)和葉子結點(終點))。

其中,關於二叉樹相關知識可參考:二叉查找的遞歸實現及遞歸分析(http://www.cnblogs.com/hapjin/p/5390451.html)

 

二,算法分析

應用了遞歸的先序遍歷。先序遍歷每個結點,將先序遍歷的每個結點的和相加,相加的結果是給定的整數,則找到一條路徑並打印之。

定義一個整型變量currentSum,保存當前訪問到的路徑上的結點之和;定義一個棧用來保存當前的路徑。為什么用棧?因為這樣可以與遞歸的先序遍歷同步。

用了棧之后,如何打印路徑?JAVA的LinkedList類的 descendingIterator()方法返回一個可以逆序遍歷鏈表的迭代器。

結點中的值,即可以為正數 也可以為負數嗎?答案是可以。因為,路徑必須是從根到葉子結點,且整個遞歸調用會一直調用到葉子后才會返回。

代碼實現如下:

 1 public void findExpectedSumPath(BinaryNode root, int expectedSum){
 2         if(root == null)
 3             return;
 4         LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>();
 5         int currentSum = 0;
 6         findExpectedSumPath(root, expectedSum, currentSum, stack);
 7     }
 8     private void findExpectedSumPath(BinaryNode root, int expectedSum, int currentSum, LinkedList<BinaryNode> stack){
 9         currentSum += root.element;
10         stack.push(root); // visit root
11         
12         boolean isLeaf = (root.left == null && root.right == null);
13         if(currentSum == expectedSum && isLeaf){//print path
14             Iterator<BinaryNode> it = stack.descendingIterator();//逆序遍歷List(Stack)
15             while(it.hasNext())
16                 System.out.print(it.next().element + " ");
17             
18             System.out.println();
19         }//end if
20         
21         if(root.left != null)//visit left sub tree
22             findExpectedSumPath(root.left, expectedSum, currentSum, stack);
23         if(root.right != null)//visit right sub tree
24             findExpectedSumPath(root.right, expectedSum, currentSum, stack);
25         
26         stack.pop();//當某結點左右孩子均為null時, 回退
27     }

可以看出:上面的代碼是一個二叉樹的先序遍歷的典型應用!第9,10行表示:訪問根結點[然后進行了一系列的處理(12-19行)]第21、22行表示訪問根的左子樹第23、24行表示訪問根的右子樹。

當遍歷到葉子結點時,在第26行,保存路徑的棧會 pop,這相當於路徑的回退。

 

三,擴展

如果給定的樹中的結點值都是正數,且路徑只需要從根結點開始,路徑的終點不一定是葉子結點

這里,當currentSum > expectedSum時,就不需要再向下進行遞歸調用了。因為,結點值都是正數,再向下遞歸調用只會是currentSum越來越大。

比如,expectedSum為 13,當遍歷到結點6時,currentSum=8+6=14 了,就不需要再向下進行遍歷了。

如果expectedSum=14,那么遍歷到6之后,也不需要再向下遍歷了。總之,只有當currentSum 小於 expectedSum時,才需要向下進行遍歷。代碼實現如下:

 1 public void findExpectedSumPath2(BinaryNode root, int expectedSum){
 2         if(root == null)
 3             return;
 4         LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>();
 5         int currentSum = 0;
 6         findExpectedSumPath2(root, expectedSum, currentSum, stack);
 7     }
 8     private void findExpectedSumPath2(BinaryNode root, int expectedSum, int currentSum, LinkedList<BinaryNode> stack){
 9         currentSum += root.element;
10         stack.push(root);
11         
12 //        boolean isLeaf = (root.left == null && root.right == null);
13         if(currentSum == expectedSum){//print path
14             Iterator<BinaryNode> it = stack.descendingIterator();//逆序遍歷List(Stack)
15             while(it.hasNext())
16                 System.out.print(it.next().element + " ");
17             
18             System.out.println();
19         }//end if
20         
21         //當currentSum > expectedSum時 再往下遞歸沒有意義了
22         if(currentSum < expectedSum){
23             if(root.left != null)
24                 findExpectedSumPath2(root.left, expectedSum, currentSum, stack);
25             if(root.right != null)
26                 findExpectedSumPath2(root.right, expectedSum, currentSum, stack);
27         }
28         
29         stack.pop();//當某結點左右孩子均為null時, 回退
30     }

 

完整代碼如下:

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

public class ExpectedSumPath {
    
    private class BinaryNode{
        int element;
        BinaryNode left;
        BinaryNode right;
        
        public BinaryNode(int ele) {
            element = ele;
            this.left = this.right = null;
        }
    }
    
    private BinaryNode root;//樹根
    
    public void insert(int element){
        root = insert(element, root);
    }
    private BinaryNode insert(int element, BinaryNode root){
        if(root == null)
            return new BinaryNode(element);
        if (element > root.element)
            root.right = insert(element, root.right);
        else if(element < root.element)
            root.left = insert(element, root.left);
        else
            ;
        return root;
        /**
        if(Math.random() > 0.5)//insert a node randomly in left nodes
            root.left = insert(element, root.left);
        else
            root.right = insert(element, root.right);
        return root;
        */
    }
    
    public void printTree(BinaryNode root){
        if(root == null)
            return;
        Queue<BinaryNode> queue = new LinkedList<>();
        
        int current;//當前層 還未打印的結點個數
        int next;//下一層結點個數
        
        queue.offer(root);
        current = 1;
        next = 0;
        while(!queue.isEmpty()){
            BinaryNode currentNode = queue.poll();
            System.out.printf("%-4d", currentNode.element);
            current--;
            
            if(currentNode.left != null){
                queue.offer(currentNode.left);
                next++;
            }
            if(currentNode.right != null){
                queue.offer(currentNode.right);
                next++;
            }
            if(current ==0){
                System.out.println();
                current = next;
                next = 0;
            }
        }
    }
    
    
    public void findExpectedSumPath(BinaryNode root, int expectedSum){
        if(root == null)
            return;
        LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>();
        int currentSum = 0;
        findExpectedSumPath(root, expectedSum, currentSum, stack);
    }
    private void findExpectedSumPath(BinaryNode root, int expectedSum, int currentSum, LinkedList<BinaryNode> stack){
        currentSum += root.element;
        stack.push(root);
        
        boolean isLeaf = (root.left == null && root.right == null);
        if(currentSum == expectedSum && isLeaf){//print path
            Iterator<BinaryNode> it = stack.descendingIterator();//逆序遍歷List(Stack)
            while(it.hasNext())
                System.out.print(it.next().element + " ");
            
            System.out.println();
        }//end if
        
        if(root.left != null)
            findExpectedSumPath(root.left, expectedSum, currentSum, stack);
        if(root.right != null)
            findExpectedSumPath(root.right, expectedSum, currentSum, stack);
        
        stack.pop();//當某結點左右孩子均為null時, 回退
    }
    
    
    public void findExpectedSumPath2(BinaryNode root, int expectedSum){
        if(root == null)
            return;
        LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>();
        int currentSum = 0;
        findExpectedSumPath2(root, expectedSum, currentSum, stack);
    }
    private void findExpectedSumPath2(BinaryNode root, int expectedSum, int currentSum, LinkedList<BinaryNode> stack){
        currentSum += root.element;
        stack.push(root);
        
//        boolean isLeaf = (root.left == null && root.right == null);
        if(currentSum == expectedSum){//print path
            Iterator<BinaryNode> it = stack.descendingIterator();//逆序遍歷List(Stack)
            while(it.hasNext())
                System.out.print(it.next().element + " ");
            
            System.out.println();
        }//end if
        
        //當currentSum > expectedSum時 再往下遞歸沒有意義了
        if(currentSum < expectedSum){
            if(root.left != null)
                findExpectedSumPath2(root.left, expectedSum, currentSum, stack);
            if(root.right != null)
                findExpectedSumPath2(root.right, expectedSum, currentSum, stack);
        }
        
        stack.pop();//當某結點左右孩子均為null時, 回退
    }
    
    public static void main(String[] args) {
        ExpectedSumPath tree = new ExpectedSumPath();
        int[] elements = {20,18,4,19,22};
        for (int i : elements) {
            tree.insert(i);
        }
        tree.findExpectedSumPath2(tree.root, 42);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM