生活随笔
收集整理的這篇文章主要介紹了
数据结构树及相关算法题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
樹
定義
樹是一種非線性的數據結構,它是由n(n>=0)個有限結點組成一個具有層次關系的集合。把它叫做樹是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點: 有一個特殊的結點叫根節點,根節點沒有 前驅節點。 除根節點外,其余節點被分為M(M>0)個互不相交的集合T1,T2…Tm,其中每一個集合Ti(1<=i<=m)有是一顆與樹類似的子樹,每顆子樹的根節點有且只有一個前驅,可以有0個或者多個后繼。 樹是遞歸定義的。
重要概念
節點的度:一個節點含有的子樹的個數稱為該節點的度 樹的度:一棵樹中,最大的節點的度稱為樹的度 葉子節點或終端節點:度為0的節點稱為葉節點 雙親節點或父節點:若一個節點含有子節點,則這個節點稱為其子節點的父節點 孩子節點或子節點:一個節點含有的子樹的根節點稱為該節點的子節點 根結點:一棵樹中,沒有雙親結點的結點 節點的層次:從根開始定義起,根為第1層,根的子節點為第2層,以此類推。 樹的高度或深度:樹中節點的最大層次 非終端節點或分支節點:度不為0的節點 兄弟節點:具有相同父節點的節點互稱為兄弟節點 堂兄弟節點:雙親在同一層的節點互為堂兄弟 節點的祖先:從根到該節點所經分支上的所有節點 子孫:以某節點為根的子樹中任一節點都稱為該節點的子孫 森林:由m(m>=0)棵互不相交的樹的集合稱為森林
樹的表示形式
樹有多種表示方式:雙親表示法、孩子表示法、孩子兄弟表示法等。 孩子兄弟表示法:
class Node { int value
; Node firstChild
; Node nextBrother
;
}
二叉樹
一棵二叉樹是結點的一個有限集合,該集合或者為空,或者是由一個根節點加上兩棵別稱為左子樹和右子樹的二叉樹組成。 二叉樹的特點: 每個結點最多有兩棵子樹,即二叉樹不存在度大于 2 的結點 二叉樹的子樹有左右之分,其子樹的次序不能顛倒,因此二叉樹是有序樹
二叉樹的基本形態
從左往右依次是:空樹、只有根節點的二叉樹、節點只有左子樹、節點只有右子樹、節點的左右子樹均存在,一般二叉樹都是由上述基本形態結合而形成的。
滿二叉樹
滿二叉樹: 一個二叉樹,如果每一個層的結點數都達到最大值,則這個二叉樹就是滿二叉樹。也就是說,如果一個二叉樹的層數為K,且結點總數是2k?12^k-1 2 k ? 1 ,則它就是滿二叉樹。
完全二叉樹
完全二叉樹: 完全二叉樹是效率很高的數據結構,完全二叉樹是由滿二叉樹而引出來的。對于深度為K的,有n個結點的二叉樹,當且僅當其每一個結點都與深度為K的滿二叉樹中編號從1至n的結點一一對應時稱之為完全二叉樹。 要注意的是滿二叉樹是一種特殊的完全二叉樹。
二叉樹的性質
若規定根節點的層數為1,則一棵非空二叉樹的第i層上最多有2i?12^{i-1} 2 i ? 1 (i>0)個結點 若規定只有根節點的二叉樹的深度為1,則深度為K的二叉樹的最大結點數是2k?12^k-1 2 k ? 1 (k>=0)
二叉樹的基礎面試題
二叉樹的前序遍歷題目鏈接 前中后序的二叉樹遍歷采用遞歸的方式來寫有一個模板,只需要改變幾行代碼的順序就好。
import java
. util
. LinkedList
;
import java
. util
. List
;
class Solution { static List
< Integer> list
= new LinkedList ( ) ; public List
< Integer> preorderTraversal ( TreeNode root
) { if ( root
== null
) { return new ArrayList < > ( ) ; } List
< Integer> left
= preorderTraversal ( root
. left
) ; List
< Integer> right
= preorderTraversal ( root
. right
) ; List
< Integer> list
= new ArrayList < > ( ) ; list
. add ( root
. val
) ; list
. addAll ( left
) ; list
. addAll ( right
) ; return list
; }
}
方法二:
class Solution { List
< Integer> result
; public void traversalNode ( TreeNode node
) { if ( node
!= null
) { result
. add ( node
. val
) ; if ( node
. left
!= null
) traversalNode ( node
. left
) ; if ( node
. right
!= null
) traversalNode ( node
. right
) ; } return ; } public List
< Integer> preorderTraversal ( TreeNode root
) { result
= new ArrayList < Integer> ( ) ; traversalNode ( root
) ; return result
; }
}
二叉樹的中序遍歷題目鏈接
class Solution { public List
< Integer> inorderTraversal ( TreeNode root
) { if ( root
== null
) { return new ArrayList < > ( ) ; } List
< Integer> left
= inorderTraversal ( root
. left
) ; List
< Integer> right
= inorderTraversal ( root
. right
) ; List
< Integer> list
= new ArrayList < > ( ) ; list
. addAll ( left
) ; list
. add ( root
. val
) ; list
. addAll ( right
) ; return list
; }
}
二叉樹的后序遍歷題目鏈接
class Solution { public List
< Integer> postorderTraversal ( TreeNode root
) { if ( root
== null
) { return new ArrayList < > ( ) ; } List
< Integer> left
= postorderTraversal ( root
. left
) ; List
< Integer> right
= postorderTraversal ( root
. right
) ; List
< Integer> list
= new ArrayList < > ( ) ; list
. addAll ( left
) ; list
. addAll ( right
) ; list
. add ( root
. val
) ; return list
; }
}
檢查兩棵樹是否相同題目鏈接
class Solution { public boolean isSameTree ( TreeNode p
, TreeNode q
) { if ( p
== null
&& q
== null
) { return true ; } else if ( p
== null
|| q
== null
) { return false ; } else if ( p
. val
!= q
. val
) { return false ; } else { return p
. val
== q
. val
&& isSameTree ( p
. left
, q
. left
) && isSameTree ( p
. right
, q
. right
) ; } }
}
方法二:
public static boolean isSameTree ( TreeNode p
, TreeNode q
) { if ( p
== null
&& q
== null
) { return true ; } if ( p
== null
|| q
== null
) { return false ; } return p
. val
== q
. val
&& isSameTree ( p
. left
, q
. left
) && isSameTree ( p
. right
, q
. right
) ; }
另一棵樹的子樹題目鏈接
class Solution { public static boolean isSameTree ( TreeNode p
, TreeNode q
) { if ( p
== null
&& q
== null
) { return true ; } if ( p
== null
|| q
== null
) { return false ; } return p
. val
== q
. val
&& isSameTree ( p
. left
, q
. left
) && isSameTree ( p
. right
, q
. right
) ; } public boolean isSubtree ( TreeNode s
, TreeNode t
) { if ( s
== null
) { return false ; } if ( isSameTree ( s
, t
) ) { return true ; } if ( isSubtree ( s
. left
, t
) ) { return true ; } return isSubtree ( s
. right
, t
) ; }
}
二叉樹最大深度題目鏈接
class Solution { public static int maxDepth ( TreeNode root
) { if ( root
== null
) { return 0 ; } int left
= maxDepth ( root
. left
) ; int right
= maxDepth ( root
. right
) ; return Math
. max ( left
, right
) + 1 ; }
}
class Solution { public static int maxDepth ( TreeNode root
) { if ( root
== null
) { return 0 ; } return Integer
. max ( maxDepth ( root
. left
) , maxDepth ( root
. right
) ) + 1 ; }
}
判斷一顆二叉樹是否是平衡二叉樹題目鏈接
class Solution { public static int getHeight ( TreeNode root
) { if ( root
== null
) { return 0 ; } return Integer
. max ( getHeight ( root
. left
) , getHeight ( root
. right
) ) + 1 ; } public boolean isBalanced ( TreeNode root
) { if ( root
== null
) { return true ; } boolean isLeftBalance
= isBalanced ( root
. left
) ; if ( ! isLeftBalance
) { return false ; } boolean isRightBalance
= isBalanced ( root
. right
) ; if ( ! isRightBalance
) { return false ; } int leftHeight
= getHeight ( root
. left
) ; int rightHeight
= getHeight ( root
. right
) ; int diff
= leftHeight
- rightHeight
; return diff
>= - 1 && diff
<= 1 ; }
}
對稱二叉樹 題目鏈接
class Solution { private static boolean isMirror ( TreeNode p
, TreeNode q
) { if ( p
== null
&& q
== null
) { return true ; } if ( p
== null
|| q
== null
) { return false ; } return p
. val
== q
. val
&& isMirror ( p
. left
, q
. right
) && isMirror ( p
. right
, q
. left
) ; } public boolean isSymmetric ( TreeNode root
) { if ( root
== null
) { return true ; } return isMirror ( root
. left
, root
. right
) ; }
}
二叉樹的進階面試題
二叉樹的構建及遍歷題目鏈接
import java
. util
. ArrayList
;
import java
. util
. Arrays
;
import java
. util
. List
;
import java
. util
. Scanner
;
public class Main { static class TreeNode { char val
; TreeNode left
; TreeNode right
; public TreeNode ( char rootValue
) { this . val
= rootValue
; } @Override public String
toString ( ) { return "TreeNode{" + "val=" + val
+ '}' ; } } private static int index
; private static TreeNode
buildTree3 ( char [ ] preorder
) { if ( index
>= preorder
. length
) { return null
; } char rootValue
= preorder
[ index
++ ] ; if ( rootValue
== '#' ) { return null
; } TreeNode root
= new TreeNode ( rootValue
) ; root
. left
= buildTree3 ( preorder
) ; root
. right
= buildTree3 ( preorder
) ; return root
; } private static TreeNode
buildTree2 ( List
< Character> preorder
) { if ( preorder
. isEmpty ( ) ) { return null
; } char rootValue
= preorder
. remove ( 0 ) ; if ( rootValue
== '#' ) { return null
; } TreeNode root
= new TreeNode ( rootValue
) ; root
. left
= buildTree2 ( preorder
) ; root
. right
= buildTree2 ( preorder
) ; return root
; } static class ReturnType { TreeNode builtRoot
; int used
; } private static ReturnType
buildTree ( List
< Character> preorder
) { if ( preorder
. isEmpty ( ) ) { ReturnType rt
= new ReturnType ( ) ; rt
. builtRoot
= null
; rt
. used
= 0 ; return rt
; } char rootValue
= preorder
. get ( 0 ) ; if ( rootValue
== '#' ) { ReturnType rt
= new ReturnType ( ) ; rt
. builtRoot
= null
; rt
. used
= 1 ; return rt
; } TreeNode root
= new TreeNode ( rootValue
) ; List
< Character> leftSubTreePreorder
= preorder
. subList ( 1 , preorder
. size ( ) ) ; ReturnType leftReturn
= buildTree ( leftSubTreePreorder
) ; root
. left
= leftReturn
. builtRoot
; List
< Character> rightSubTreePreorder
= preorder
. subList ( 1 + leftReturn
. used
, preorder
. size ( ) ) ; ReturnType rightReturn
= buildTree ( rightSubTreePreorder
) ; root
. right
= rightReturn
. builtRoot
; ReturnType rt
= new ReturnType ( ) ; rt
. builtRoot
= root
; rt
. used
= 1 + leftReturn
. used
+ rightReturn
. used
; return rt
; } private static void inorder ( TreeNode root
) { if ( root
== null
) { return ; } inorder ( root
. left
) ; System
. out
. print ( root
. val
+ " " ) ; inorder ( root
. right
) ; } public static void main ( String
[ ] args
) { Scanner scanner
= new Scanner ( System
. in
) ; while ( scanner
. hasNextLine ( ) ) { String s
= scanner
. nextLine ( ) ; char [ ] chars
= s
. toCharArray ( ) ; index
= 0 ; TreeNode root
= buildTree3 ( chars
) ; inorder ( root
) ; System
. out
. println ( ) ; } }
}
二叉樹的分層遍歷題目鏈接
public static void levelOrder ( TreeNode root
) { if ( root
== null
) { return ; } Queue
< TreeNode> queue
= new LinkedList < > ( ) ; Queue
< Integer> levelQueue
= new LinkedList < > ( ) ; queue
. add ( root
) ; levelQueue
. add ( 0 ) ; while ( ! queue
. isEmpty ( ) ) { TreeNode node
= queue
. remove ( ) ; int level
= levelQueue
. remove ( ) ; System
. out
. println ( level
+ ": " + node
. val
) ; if ( node
. left
!= null
) { queue
. add ( node
. left
) ; levelQueue
. add ( level
+ 1 ) ; } if ( node
. right
!= null
) { queue
. add ( node
. right
) ; levelQueue
. add ( level
+ 1 ) ; } } }
public List
< List
< Integer> > levelOrder ( TreeNode root
) { List
< List
< Integer> > list
= new ArrayList < > ( ) ; if ( root
== null
) { return null
; } Queue
< TreeNode> queue
= new LinkedList < > ( ) ; Queue
< Integer> levelQueue
= new LinkedList < > ( ) ; queue
. add ( root
) ; levelQueue
. add ( 0 ) ; int lastLevel
= - 1 ; while ( ! queue
. isEmpty ( ) ) { TreeNode node
= queue
. remove ( ) ; int level
= levelQueue
. remove ( ) ; if ( lastLevel
!= level
) { list
. add ( new ArrayList < > ( ) ) ; } lastLevel
= level
; List
< Integer> rowList
= list
. get ( level
) ; rowList
. add ( node
. val
) ; if ( node
. left
!= null
) { queue
. add ( node
. left
) ; levelQueue
. add ( level
+ 1 ) ; } if ( node
. right
!= null
) { queue
. add ( node
. right
) ; levelQueue
. add ( level
+ 1 ) ; } } return list
; }
給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先題目鏈接
class Solution { public TreeNode
lowestCommonAncestor ( TreeNode root
, TreeNode p
, TreeNode q
) { if ( p
== root
|| q
== root
) { return root
; } boolean pInLeft
= containsNode ( root
. left
, p
) ; boolean qInLeft
= containsNode ( root
. left
, q
) ; if ( pInLeft
&& ! qInLeft
) { return root
; } if ( ! pInLeft
&& qInLeft
) { return root
; } if ( pInLeft
) { return lowestCommonAncestor ( root
. left
, p
, q
) ; } else { return lowestCommonAncestor ( root
. right
, p
, q
) ; } } private static boolean containsNode ( TreeNode root
, TreeNode p
) { if ( root
== null
) { return false ; } if ( root
== p
) { return true ; } if ( containsNode ( root
. left
, p
) ) { return true ; } return containsNode ( root
. right
, p
) ; }
}
二叉樹搜索樹轉換成排序雙向鏈表題目鏈接
import java
. util
. ArrayList
;
public class Solution { public TreeNode
Convert ( TreeNode pRootOfTree
) { if ( pRootOfTree
== null
) return null
; ArrayList
& lt
; TreeNode
& gt
; list
= new ArrayList & lt
; & gt
; ( ) ; Convert ( list
, pRootOfTree
) ; return Convert ( list
) ; } public void Convert ( ArrayList
& lt
; TreeNode
& gt
; list
, TreeNode root
) { if ( root
!= null
) { Convert ( list
, root
. left
) ; list
. add ( root
) ; Convert ( list
, root
. right
) ; } } public TreeNode
Convert ( ArrayList
& lt
; TreeNode
& gt
; list
) { TreeNode head
= list
. get ( 0 ) ; TreeNode cur
= head
; for ( int i
= 1 ; i
& lt
; list
. size ( ) ; ++ i
) { TreeNode node
= list
. get ( i
) ; node
. left
= cur
; cur
. right
= node
; cur
= node
; } return head
; }
}
根據一棵樹的前序遍歷與中序遍歷構造二叉樹題目鏈接
public TreeNode
buildTree ( int [ ] preorder
, int [ ] inorder
) { if ( preorder
. length
== 0 ) { return null
; } int rootValue
= preorder
[ 0 ] ; TreeNode root
= new TreeNode ( rootValue
) ; int leftSize
= 0 ; for ( int i
= 0 ; i
< inorder
. length
; i
++ ) { if ( inorder
[ i
] == rootValue
) { leftSize
= i
; } } int [ ] leftPreorder
= Arrays
. copyOfRange ( preorder
, 1 , 1 + leftSize
) ; int [ ] leftInorder
= Arrays
. copyOfRange ( inorder
, 0 , leftSize
) ; root
. left
= buildTree ( leftPreorder
, leftInorder
) ; int [ ] rightPreorder
= Arrays
. copyOfRange ( preorder
, 1 + leftSize
, preorder
. length
) ; int [ ] rightInorder
= Arrays
. copyOfRange ( inorder
, leftSize
+ 1 , inorder
. length
) ; root
. right
= buildTree ( rightPreorder
, rightInorder
) ; return root
; }
從中序和后序序列構建二叉樹題目鏈接
public TreeNode
buildTree ( int [ ] inorder
, int [ ] postorder
) { if ( inorder
. length
== 0 && postorder
. length
== 0 ) { return null
; } int rootValue
= postorder
[ postorder
. length
- 1 ] ; TreeNode root
= new TreeNode ( rootValue
) ; int leftSize
= 0 ; for ( int i
= 0 ; i
< inorder
. length
; i
++ ) { if ( inorder
[ i
] == rootValue
) { leftSize
= i
; } } int [ ] leftInorder
= Arrays
. copyOfRange ( inorder
, 0 , leftSize
) ; int [ ] leftPostOrder
= Arrays
. copyOfRange ( postorder
, 0 , leftSize
) ; root
. left
= buildTree1 ( leftInorder
, leftPostOrder
) ; int [ ] rightInorder
= Arrays
. copyOfRange ( inorder
, 1 + leftSize
, inorder
. length
) ; int [ ] rightPostOrder
= Arrays
. copyOfRange ( postorder
, leftSize
, postorder
. length
- 1 ) ; root
. right
= buildTree1 ( rightInorder
, rightPostOrder
) ; return root
; }
根據二叉樹創建字符串題目鏈接
class Solution { private StringBuilder sb
; private void preorder ( TreeNode root
) { if ( root
== null
) { sb
. append ( "()" ) ; return ; } sb
. append ( "(" ) ; sb
. append ( root
. val
) ; if ( root
. left
== null
&& root
. right
== null
) { } else if ( root
. right
== null
) { preorder ( root
. left
) ; } else { preorder ( root
. left
) ; preorder ( root
. right
) ; } sb
. append ( ")" ) ; } public String
tree2str ( TreeNode t
) { sb
= new StringBuilder ( ) ; preorder ( t
) ; sb
. delete ( 0 , 1 ) ; sb
. delete ( sb
. length ( ) - 1 , sb
. length ( ) ) ; return sb
. toString ( ) ; }
}
前中后序的非遞歸遍歷
由于遞歸遍歷會不斷調用棧,時間復雜度高 前序遍歷
public static void preorder ( TreeNode root
) { TreeNode cur
= root
; Stack
< TreeNode> stack
= new Stack < > ( ) ; while ( cur
!= null
|| ! stack
. isEmpty ( ) ) { while ( cur
!= null
) { System
. out
. println ( cur
. val
) ; stack
. push ( cur
) ; cur
= cur
. left
; } TreeNode pop
= stack
. pop ( ) ; cur
= pop
. right
; } }
中序遍歷
public static void inorder ( TreeNode root
) { TreeNode cur
= root
; Stack
< TreeNode> stack
= new Stack < > ( ) ; while ( cur
!= null
|| ! stack
. isEmpty ( ) ) { while ( cur
!= null
) { stack
. push ( cur
) ; cur
= cur
. left
; } TreeNode pop
= stack
. pop ( ) ; System
. out
. println ( pop
. val
) ; cur
= pop
. right
; } }
后序遍歷
public static void postorder ( TreeNode root
) { TreeNode cur
= root
; TreeNode last
= null
; Stack
< TreeNode> stack
= new Stack < > ( ) ; List
< TreeNode> pathOf8
= null
; List
< TreeNode> pathOf4
= null
; while ( cur
!= null
|| ! stack
. isEmpty ( ) ) { while ( cur
!= null
) { stack
. push ( cur
) ; cur
= cur
. left
; } TreeNode pop
= stack
. peek ( ) ; if ( pop
. right
== null
) { if ( pop
. val
== 4 ) { pathOf4
= new ArrayList < > ( stack
) ; } else if ( pop
. val
== 8 ) { pathOf8
= new ArrayList < > ( stack
) ; } stack
. pop ( ) ; last
= pop
; } else if ( pop
. right
== last
) { if ( pop
. val
== 4 ) { pathOf4
= new ArrayList < > ( stack
) ; } else if ( pop
. val
== 8 ) { pathOf8
= new ArrayList < > ( stack
) ; } stack
. pop ( ) ; last
= pop
; } else { cur
= pop
. right
; } } System
. out
. println ( pathOf4
) ; System
. out
. println ( pathOf8
) ; }
驗證demo:
import java
. util
. Arrays
; public class TestDemo { public static TreeNode
buildTree ( int [ ] preorder
, int [ ] inorder
) { if ( preorder
. length
== 0 ) { return null
; } int rootValue
= preorder
[ 0 ] ; TreeNode root
= new TreeNode ( rootValue
) ; int leftSize
= 0 ; for ( int i
= 0 ; i
< inorder
. length
; i
++ ) { if ( inorder
[ i
] == rootValue
) { leftSize
= i
; } } int [ ] leftPreorder
= Arrays
. copyOfRange ( preorder
, 1 , 1 + leftSize
) ; int [ ] leftInorder
= Arrays
. copyOfRange ( inorder
, 0 , leftSize
) ; root
. left
= buildTree ( leftPreorder
, leftInorder
) ; int [ ] rightPreorder
= Arrays
. copyOfRange ( preorder
, 1 + leftSize
, preorder
. length
) ; int [ ] rightInorder
= Arrays
. copyOfRange ( inorder
, leftSize
+ 1 , inorder
. length
) ; root
. right
= buildTree ( rightPreorder
, rightInorder
) ; return root
; } public static void main ( String
[ ] args
) { int [ ] preorder
= { 1 , 2 , 4 , 5 , 8 , 3 , 6 , 7 } ; int [ ] inorder
= { 4 , 2 , 5 , 8 , 1 , 6 , 3 , 7 } ; TreeNode root
= buildTree ( preorder
, inorder
) ; }
}
總結
以上是生活随笔 為你收集整理的数据结构树及相关算法题 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。