天天看點

CC150小結資料結構

數組與字元串

二叉堆可以用數組來表示

如大頂堆,建構的過程為從下到上。每次出現子節點大于父節點,旋轉,然後對目前節點的子樹進行遞歸處理,列印出排序的堆的時間複雜度為,nlog(n).

1.1确定一個字元串的所有字元是否全都不同。

思路:采用boolean數組進行緩存,ASCII與Unicode,考慮進去長度的因素256個,大于肯定會出現重複,時間複雜度O(n)。

1.2用c或者c++實作void reverse(char* str),反轉一個null結尾的字元串。

思路:不使用額外的空間就可以實作,這個是雙指針。

這裡給出程式

void reverse(char *str){
    char *end = str;
    char temp;
    if (str){
        while(*end){
            ++end;
        }
        --end;
        while (str < end){
            temp = *str;
            *str++ = *end;
            *end-- = temp;
        }
    }
}
           

1.3給定兩個字元串,請編寫程式,确定其中一個字元串重新排列後能否變成另外的一個字元串。

思路:先去定細節,變位詞Dog與God疏忽是同一個字元串,空格出現算不算,String.trim()去除首尾的空格。

解法1:可以先對字元串進行排序處理,String.toCharArray(),java.util.Arrays.sort()方法

解法2:假設為ASCII碼,那麼用int數組記錄第一個字串出現的次數,當第二字元串字元出現次數大于第一個出現次數時,傳回false。第一個字元串使用toCharArray的方法,第二個使用charAt()。

1.4編寫方法,将字元串中的空格全部替換為“%20”。

思路:字元串的操作,這個要進行兩次周遊,先進行一次得到數組中空字元串的個數,然後再進行處理。從尾部開始,避免資料丢失。

這裡給出代碼:

public void replaceSpace(char[] str, int length){
    int spacenum = , newlength, i;
    for(i = ; i < length; i++){
        if (str[i] == ' '){
            spacenum++;
        }
    }
    newlength = length + spacenum * ;
    str[newlength] = '\n';//結束标志位
    int index = newlength - ;
    for (i = length - ; i > ; i--){
        if (str[i] != ' '){
            str[index--] = str[i];
        } else {
            str[index--] = '0';
            str[index--] = '2';
            str[index--] = '%';
        }
    }
}
           

1.5利用字元重複出現的次數,編寫一個方法,實作基本的字元串的壓縮功能。比如,字元串“aabcccccaaa”會變為a2b1c5a3。若壓縮後沒有變短,就傳回原字元串。

思路:采用StringBuffer,按照規則進行統計,最後進行長度統計。

1.6給定一幅N*N矩陣表示的圖像,其中每個像素的大小為4個位元組,編寫一個方法,将圖像旋轉90度。不占用額外的空間。

思路:進行一層層的旋轉,對每一層進行環狀旋轉。用first來定義每一個環的最小下标,last表示最小标志,offset做緩存。

public static void rotate(int[][] num) {
         int len = num.length;
         for (int layer = ; layer < len / ; layer++){
             int first = layer;
             int last = len -  - first;
             for (int i = first; i < last; i++){
                 int offset = i - first;
                 int top = num[first][i];
                 //左轉上
                 num[first][i] = num[last - offset][first];
                 //下轉左
                 num[last - offset][first] = num[last][last - offset];
                 //右轉下
                 num[last][last - offset] = num[i][last];
                 //上轉右
                 num[i][last] = top; 
             }
         }
    }
           

1.7編寫一個方法,若M*N矩陣中某個元素為0,則将其所在的行與列清零。

思路:這是一個陷阱題,首先用兩個booelan類型的數組進行歸零行以及列的标記,下一步再進行清零操作。

1.8假定有一個方法isSubString,給定兩個字元串s1與s2,編寫代碼檢查s2是否由s1旋轉組成,隻能調用一次isSubString的方法。

思路:out of box方法,假定s1 = xy = waterbottle,x = wat, y = terbottle,s2 = yx =erbottlemat,yx 肯定是xyxy的子串。先進行長度的判定,長度不同,肯定傳回false,然後利用子串進行判定。

public boolean isRotation(String s1, String s2) {
    if (s1 == null && s2 == null) return false;
    if (s1 == null || s2 == null) return true;
    int len = s1.length();
    if (len == s2.length() && len > ) {
        String s1s1 = s1 + s1;
        return isSubstring(s1s1, s1);
    }
    return false;
}
           

連結清單

連結清單這塊需要注意dummy的使用

2.1 編寫代碼,移除未排序連結清單中的重複節點。進階:如果不使用緩沖區,該怎麼解決?

思路:利用散清單記錄,有一個函數需要掌握,containsKey(),同時注意連結清單的删除操作,要有previous的緩存。

public void deleteDups(LinkedListNode n){
    Hashtable table = new Hashtable();
    LinkedListNode previous = null;
    while (n != null){
        if (table.containsKey(n.data)){
            previous.next = n.next;
        } else {
            table.put(n.data, true);
            previous = n;
        }
        n = n.next;
    }
}
           

不使用緩存區,就得采用兩個指針進行疊代處理

2.2實作一個算法,找出單向連結清單中倒數第k個結點。

思路:用先行指針的方法

2.3實作一個算法,删除單向連結清單中間的某個結點,假定你隻能通路該結點。

思路:将目前結點的下一個結點的值複制到目前結點,然後删除下一個結點。

2.4編寫代碼,以給定值x為基準将連結清單分割成兩部分,所有小于x的結點排在大于或等于x的結點之前。

思路:這個是采用建立兩個連結清單,然後進行合并處理的方式。

java中的super()方法是針對父類來說的。

2.5給定兩個用連結清單表示的整數,每個節點包含一個數位。這些數位是反向存放的也就是個位排在連結清單的首部。編寫函數對這兩個整數求和,并利用連結清單形式傳回結果。

示例 : 輸入 (7-> 1 -> 6) + ( 5 -> 9 -> 2) ,即617 + 295 與普通的加法保持一緻 輸出 2-> 1-> 9 ,即912.

這個采用的是普通的加法進行處理。

進階 :假設這些數位是正向存放的,請再做一遍。

這個是要用到遞歸進行處理,需要注意兩個數的位數不相等。

2.6給定一個有環連結清單,實作一個算法傳回環路的開頭結點。

有環連結清單的定義,在連結清單中的某個結點的next元素指向在它前面出現過的結點,則表明連結清單存在環路。

示例

輸入: A->B ->C->D->E->C (C結點出現了兩次)

那麼傳回:C 結點

思路:設定兩個指針,fast與slow,假設從第s個結點,進入到環路,那麼當slow在s結點的時候,fast處于2s結點,讓大S為 S = s mod loop_size,此時,fast與slow相差S步,在loop_size - S 步以後,fast 與 slow相遇,碰撞結點距離環路開始的位置為S,(對于slow來說,走了loop_size - S步,那麼loop_size- (loop_size- S))此時碰撞結點距離環路起始處的距離為s個結點,連結清單開始位置也是距離起始處s個結點,那麼兩個指針方向同時出發,會相交于環路起始結點。

public static LinkedListNode getBegainHead(LinkedListNode head){
        LinkedListNode fast = head;
        LinkedListNode slow = head;
        while (fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if (fast == slow){
                break;
            }
        }
        if (fast == null || fast.next == null){
            return null;
        }
        slow = head;
        while (slow != fast){
            slow = slow.next;
            fast = fast.next;
        }
        return fast;
    }
           

這是一個很經典的方法。

2.7 編寫一個函數,檢查連結清單是否為回文。

思路:先行指針,取到中間位置的數,用stack來存儲資料,注意長度為奇數,根據fast指向的内容即可判斷。

棧與隊列

3.2請設計一個棧,除push與pop方法,還支援min方法,可傳回棧元素中的最小值。push、pop、min方法的時間複雜度為O(1)。

思路:1.新封裝 一個對象,對象中包含 value 以及 min,在stack中進行存儲。注意super.調用父類方法,peek()檢視棧頂元素

2.與以上類似,設計子類,繼承Stack,子類中增加新的Stack用于存儲出現變化的最小值,入棧操作時進行比較,出棧操作時進行更新。

3.4經典漢諾塔問題

思路:利用stack的資料類型做資料存儲

遞歸方法求解:

public void moveDisks(int n, Tower origin, Tower destination, Tower buffer){
    if (n <= ) return;
    moveDisks(n -, origin, buffer, destination);
    moveTop(origin, destination);
    moveDisks(n - , buffer, destination, origin);
}
           

3.5實作一個MyQuene類,該類用兩個棧來實作一個隊列

思路:兩個棧,一個為new,另外一個為old。隊列add資料為new push資料,隊列出資料,從old pop資料,如果old 為空,則将new出棧,old入棧。

兩個隊列實作棧的話,

class MyStack {
    private Queue<Integer> inquene = new LinkedList<Integer>();
    private Queue<Integer> outquene = new LinkedList<Integer>();
    int temp =;
    // Push element x onto stack.
    public void push(int x) {
        inquene.add(x);
    }
    // Removes the element on top of the stack.
    public void pop() {
      if ( inquene.isEmpty()){
          while (!outquene.isEmpty()){
              temp = outquene.peek();
              outquene.poll();
              if( !outquene.isEmpty() ){
                  inquene.add(temp);
              }
          }  
      } else {
            while (!inquene.isEmpty()){
                 temp = inquene.peek();
                  inquene.poll();
                  if( !inquene.isEmpty() ){
                      outquene.add(temp);
                  }
            }
        }
    }
    // Get the top element.
    public int top() {
        if( inquene.isEmpty() ){
            while( !outquene.isEmpty() ){
                  temp = outquene.peek();
                  outquene.poll();
              }
            return temp;
        }else{
             while(  !inquene.isEmpty() ){
                temp = inquene.peek();
                inquene.poll();
                outquene.add(temp);
            }
             return temp;
        }       
    }
    // Return whether the stack is empty.
    public boolean empty() {
        return inquene.isEmpty()&&outquene.isEmpty();
    }
}
           

3.6經典的stack排序問題,按照升序對棧進行排序。最多隻能使用一個額外的棧存放臨時資料。

思路:建立一個棧,

//注意給定兩個while指針的使用
public Stack<Integer> stackSort(Stack<Integer> s1){
    Stack<Integer> s2 = new Stack<Integer>();
    while (!s1.isEmpty()){
        Integer temp = s1.pop();
        while(!s2.isEmpty() && s2.peek() > temp){// 本次while循環保證temp是目前s2裡面最小的那個
            s1.push(s2.pop());
        }
        s2.push(temp);// 
    }
    return s2;
}
           

樹與圖

樹的三種周遊方式,前序周遊,中序周遊,後序周遊等,遞歸形式的實作以及使用棧與隊列疊代形式的實作。用V表示父節點,L表示左子節點,R表示右子節點,則VLR表示先序周遊,LVR表示中序周遊,LRV表示後序周遊。在處理時,按照遞歸的思想,對每一個結點都進行順序上的檢查處理。前序,中序,後序是根據中間結點被通路的相對順序來說的。

判斷圖是否有環:

針對無向圖可以采用并查集來判斷是否有環:
class GraphCycle{
     int V, E;    // V-> no. of vertices & E->no.of edges
     Edge edge[]; // /collection of all edges

     class Edge {//edges
         int src, dest;
     };

     // Creates a graph with V vertices and E edges
     GraphCycle(int v,int e){
         V = v;
         E = e;
         edge = new Edge[E];
         for (int i=; i<e; ++i)
             edge[i] = new Edge();
     }

     // A utility function to find the subset of an element i
     int find(int parent[], int i){
         if (parent[i] == -)
             return i;
         return find(parent, parent[i]);
     }

     // A utility function to do union of two subsets
     void Union(int parent[], int x, int y){
         int xset = find(parent, x);
         int yset = find(parent, y);
         parent[xset] = yset;
     }


     // The main function to check whether a given graph
     // contains cycle or not
     int isCycle( GraphCycle graph) {
         // Allocate memory for creating V subsets
         int parent[] = new int[graph.V];

         // Initialize all subsets as single element sets
         for (int i=; i<graph.V; ++i)
             parent[i]=-;

         // Iterate through all edges of graph, find subset of both
         // vertices of every edge, if both subsets are same, then
         // there is cycle in graph.
         for (int i = ; i < graph.E; ++i) {
             int x = graph.find(parent, graph.edge[i].src);
             int y = graph.find(parent, graph.edge[i].dest);

             if (x == y && x != -)
                 return ;
             graph.Union(parent, x, y);
         }
         return ;
     }  
           
針對有向圖,采用的是dfs加上标記位來做
      public boolean canFinish(int numCourses, int[][] prerequisites) {
            HashSet<Integer>[] edges = new HashSet[numCourses];
            for (int i =  ; i < numCourses; i++) {
                edges[i] = new HashSet<Integer>();
            }
            for (int[] temp : prerequisites) {
                HashSet a = edges[temp[]];
                a.add(temp[]);
            }
            for (int i = ; i < numCourses; i++) {
                boolean[] visit = new boolean[numCourses];
                boolean[] resTack = new boolean[numCourses];
                Arrays.fill(visit, false);
                Arrays.fill(resTack, false);
                if (isRecyle(i, edges, visit, resTack)) {
                    return false;
                }
            }
            return true;
      }
      public boolean isRecyle(int i,HashSet<Integer>[] edges, boolean[] visit, boolean[] resTack) {
          if (visit[i] == false) {
              visit[i] = true;
              resTack[i] = true;
              HashSet<Integer> pre = edges[i];
              for (int id : pre) {
                  if (! visit[id] && isRecyle(id,edges, visit, resTack) ) {
                      return true;
                  } else if (resTack[id]) {
                      return true;
                  }
              }
          }
          resTack[i] = false;
          return false;
      }
           

圖的周遊

深度優先搜尋

// 遞歸版本
void DFSsearch(Node root){
    if (root == null){
        return;
    }
    visit(root);
    root.isvisited = true;
    foreach (Node n in root.adjacent){
        search(n);
    }
}
//疊代版本,與樹的前序周遊類似,先通路本節點的内容,右邊入棧,左邊入棧
void DFSearch(Node root){
    if (root == null){
        return; 
    }
    Stack<Node> stack = new Stack(root);
    stack.push(root);
    Node temp = null;
    while(stack.size() > ){
        temp = stack.pop();
        if (root.right != null){
            stack.push(root.right)
        }
        if (root.left != null){
            stack.push(root.left);
        }
    }
}
//廣度優先的話,就采用隊列的形式
void search(Node root){
    if (null == root){
        return;
    }
    Quene<Node> que = new LinkedList<Node>();
    root.visited = true;
    visit(root);
    que.add(root);
    Node temp = null;
    while (que.size() > ){
        temp = que.remove();
        for (Node n in temp.adjacent){
            visit(n);
            n.visited = true;
            que.add(n);
        }
    }
}
           

注意substring(a, b);從0開始,包含a,但是不包含b。

遞歸版樹的周遊

前序vlr

public void trvelPre(TreeNode root){
    if (null == root){
        retrun;
    }
    visit(root.data);
    trvelPre(root.left);
    trvelPre(root.right);
}
中序lvr以及後續lrv隻是修改遞歸的後三條語句就可以

           

疊代版的周遊

前序周遊
public void trvelPre(TreeNode root){
    if (null == root){
        return;
    }
    Stack<TreeNode> stack = new Stack<TreeNode>();
    stack.push(root);
    while(!stack.isEmpty()){
        TreeNode temp = stack.pop();
        visit(temp);
        if (null != temp.right){
            stack.push(temp.right);
        }
        if (null != temp.left){
            stack.push(temp.left);
        }
    }
}
中序周遊,對于完備的樹,可以得到parent,空間複雜度為O(),非完備的就先不這樣處理
public void trvelIn(TreeNode root){
        if (null == root){return;}
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode temp = root;
        //中序周遊方式有所不同,碰到左節點就入棧,左節點通路完成後,轉向右子節點
        while (true){
            if (temp != null){
                stack.push(temp);
                temp = temp.left;
            } else if (!stack.isEmpty()){
                temp = stack.pop();
                System.out.print(temp.val);
                temp = temp.right;
            } else {
                break;
            }
        }
}
後序周遊
public void vistiafter(TreeNode root) {  
        if (null == root ){return;}
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode temp = root;
        stack.push(temp);
        while (!stack.isEmpty()){
            if ((stack.peek().left != temp) && (stack.peek().right != temp)){
                //目前temp結點既不表示棧頂元素的左節點也不表示右節點,
                //temp棧頂元素的左兄弟結點或者是root結點
                // 表示切換子樹
                getHLVFL(stack.peek(), stack);
            }
            temp = stack.pop();
            System.out.print(temp.val);
        }
    }
    public void getHLVFL(TreeNode temp, Stack<TreeNode> stack){
        while(null != temp){
            if (null != temp.left){
                if (null != temp.right){
                    stack.push(temp.right);
                }
                stack.push(temp.left);
            } else {
                stack.push(temp.right);
            }
            temp = stack.peek();
        }
        stack.pop();
    }
    後序周遊結束
           

根據vlr以及lvr,得到lrv,構造出樹

public TreeNode getaf(String pre, String in ,int len){
        TreeNode node = new TreeNode();
        if(len == ){
            return null;
        }
        char root = pre.charAt();
        int index = ;
        for(int i = ; i < len; i++){
            if(root == in.charAt(i)){
                index = i;
                break;
            }
        }
        node.val = root;
        node.left = getaf(pre.substring(,index + ), in.substring(, index), index );
        node.right = getaf(pre.substring(index + , len), in.substring(index + , len), len - index - );
        System.out.println(root);//這條語句放的位置,可以輸出不同的周遊順序,現在是後序,最上面是前序,放到中間就是中序
        return node;
    }
//root.right = bulidHelp(pre, in, preroot + index - left + 1, index + 1, right);對兩邊的進行處理
           

圖的DFS深度優先周遊,BFS廣度優先周遊,要使用到隊列

4.1檢查二叉樹是否平衡,任意一個結點,其兩棵子樹的高度差不超過1

思路:遞歸得到樹的高度,遞歸判斷每一個結點是否平衡

public int checkHeight(TreeNode root){
    if (null == root){
        return ;
    }
    int leftHeight = checkHeight(root.left);
    if (leftHeight == -){
        return -;
    }
    int rightHeight = cheakHeight(root.right);
    if (rightHeight == -){
        return -;
    }
    if (Math.abs(leftHeight - rightHeight) > ){
        return -;
    } else {
        return Math.max(leftHeight, rightHeight) + ;
    }
}
public boolean isBlance(TreeNode tree){
    if (checkHeight(tree) == -){
        return fasle;
    } else {
        return true;
    }
}
           

4.2給定一個有向圖,找出兩個節點之間是否存在一條路徑

廣度優先搜尋适合查找最短路徑

public enum State{
    Unvisited, Visited, Visiting;
}
public static boolean search(Graph g, Node start, Node end){
    if (null == g || null == start){
        return false;
    }
    LinkedList<Node> list = new LinkedList<Node>();
    for (Node u : g.getNodes()){
        u.state = State.Unvisited;
    }
    list.add(start);
    start.state = State.Visiting;
    Node u = null;
    while(!list.isEmpty()){
        u = q.removeFirst();
        if (u != null){
            for (Node v : u.getAdjacent()){
                if (v.state == State.Unvisited){
                    if (v == end){
                        return true;
                    } else {
                        v.state = State.Visiting;
                        q.add(v);
                    }
                }
            }
            u.state = State.Visited;
        }
    }
    return false;
}
           

4.3給定一個有序整數數組,元素個不相同,并且按照升序排列,編寫算法建立高度最小的二叉查找樹。

使處于中間位置上的元素更靠近根節點。

public TreeNode createMin(int nums, int start, int end){
    if (start > end){
        return null;
    }
    int mid = start + ((end - start) >> );
    TreeNode temp = new TreeNode(nums[mid]);
    temp.left = createMin(nums, start, mid - );
    temp.right = createMin(nums, mid + , end);
    return temp;
}
public TreeNode createMinBFS(int[] nums){
    return createMin(nums, , nums.length - );
}
           

4.4給定一個二叉樹,建立含有某一深度上的所有結點的連結清單,比如一棵樹的深度為D,建立D個連結清單。

思路:對廣度優先的算法進行稍微修改,一層一層增加即可。

4.5檢查一課二叉樹是否為二叉查找樹

思路:1.如果不存在相等的樹,所有左結點小于等于目前結點,目前結點小于右結點,current.left.val<= current.val < current.right.val(程式也可以這麼寫)。改進,遞歸

public static int last_printed = integer.MIN_VALUE;
public boolean checkBFS(TreeNode root){
    if (null == root){return true;}
    if (!checkBFS(root.left)){
        return false;
    }
    if (root.val <= last_printed){// 右側的必須大于
        return false;
    }
    last_printed = temp.val;
    if (!checkBFS(root.right)){
        return false;
    }
    return true;
}
           

思路2,利用最大最小算法,遞歸,限定目前結點的數的範圍,與數學上的夾逼準則類似

public boolean checkMaxMinBFS(TreeNode root, int min, int max){
    if (null == root){return true;}
    if (root.val <= min || root.val > max){
        return false;
    }
    if (!checkMaxMinBFS(root.left, min, root.val) || !checkMaxMinBFS(root.right, root.val, max)){
        return false;
    }
    return true;
}
public boolean checkBFS(TreeNode root){
    return checkMaxMinBFS(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
#
           

4.6找出二叉查找樹的下一個結點(可以得到父節點)

思路:也就是中序周遊的下一個結點,此時要分開讨論

public TreeNode leftMostChild(TreeNode root){
    if (null == root){return null;}
    while(root.left != null){
        root = root.left;
    }
    return root;
}
public TreeNode inorderSucc(TreeNode n){
    if (null == n){return null;}
    if(n.right != null){
        return leftMostChild(n.right);
    } else {
        TreeNode cu = n;
        TreeNode pa = cu.parent;
        while (pa != null && pa.left != cu){
            cu = pa;
            pa = cu.parent;
        }
        return pa;
    }
}
           

4.7 找出二叉樹中兩個結點的第一個共同祖先。不得将額外的結點存儲在資料結構中

思路:1.從根結點調用cover方法,先檢查是否都在根結點中,不在的話傳回null,然後依次調用,left與right,

2.遞歸,優化常數時間 傳回值依次為 傳回p,root子樹包含p不包含q;傳回q,root子樹中包含q不包含p;傳回null,都不包含;否則傳回 p與q的共同祖先。

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q)  return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left != null && right != null)   return root;
        return left != null ? left : right;
    }
     // 非遞歸版本的,時間複雜度挺高的。
       public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        Map<TreeNode, TreeNode> parents = new HashMap<TreeNode, TreeNode>();
        Queue<TreeNode > queue  = new LinkedList<>();
        parents.put(root, null);
        queue.offer(root);
        TreeNode temp = null;
        while (!parents.containsKey(p) || !parents.containsKey(q)) {
            temp = queue.poll();
            if (temp.left != null) {
                parents.put(temp.left, temp);
                queue.offer(temp.left);
            }
            if (temp.right != null) {
                parents.put(temp.right, temp);
                queue.offer(temp.right);               
            }
        }
        Set<TreeNode> anc = new HashSet<>();
        while (p != null) {
            anc.add(p);
            p = parents.get(p);
        }
        while (!anc.contains(q)) {
            q = parents.get(q);
        }
        return q;
    }
           

4.8你有一顆非常大的二叉樹:T1,有幾百萬個結點;T2有幾百個結點。設計一個算法,判斷T2是不是T1的子樹

思路1:對兩個樹前序以及中序周遊,判斷T2是不是T1的子串,注意null補全特殊的字元

2:遞歸調用

public boolean treeMatch(TreeNode a, TreeNode b){
    if (a == null && b == null){
        return true;
    }
    if (a == null || b == null){
        return false;
    }
    if (a.val != b.val){
        return false;
    }
    return (treeMatch(a.left, b.left) && treeMatch(a.right, b.right));
}
public boolean isSubTree(TreeNode t1, TreeNode t2){
    if (null == t1 && null == t2){
        return true;
    }
    if (t1 == null){
        return false;
    }
    if (t1.val == t2.val){
        if (treeMatch(t1, t2)){return true;}
    }
    return (isSubTree(t1.left, t2) || isSubTree(t1.right, t2));
}
           

4.9給定一個二叉樹,其中每一個結點都含有一個數值。設計一個算法,列印某個結點數值總和等于某個給定值的所有路徑。

思路:從根節點出發進行計算