日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构树及相关算法题

發(fā)布時(shí)間:2023/12/19 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构树及相关算法题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

定義

樹是一種非線性的數(shù)據(jù)結(jié)構(gòu),它是由n(n>=0)個(gè)有限結(jié)點(diǎn)組成一個(gè)具有層次關(guān)系的集合。把它叫做樹是因?yàn)樗雌饋硐褚豢玫箳斓臉?#xff0c;也就是說它是根朝上,而葉朝下的。它具有以下的特點(diǎn):
有一個(gè)特殊的結(jié)點(diǎn)叫根節(jié)點(diǎn),根節(jié)點(diǎn)沒有 前驅(qū)節(jié)點(diǎn)。
除根節(jié)點(diǎn)外,其余節(jié)點(diǎn)被分為M(M>0)個(gè)互不相交的集合T1,T2…Tm,其中每一個(gè)集合Ti(1<=i<=m)有是一顆與樹類似的子樹,每顆子樹的根節(jié)點(diǎn)有且只有一個(gè)前驅(qū),可以有0個(gè)或者多個(gè)后繼。
樹是遞歸定義的。

重要概念

節(jié)點(diǎn)的度:一個(gè)節(jié)點(diǎn)含有的子樹的個(gè)數(shù)稱為該節(jié)點(diǎn)的度
樹的度:一棵樹中,最大的節(jié)點(diǎn)的度稱為樹的度
葉子節(jié)點(diǎn)或終端節(jié)點(diǎn):度為0的節(jié)點(diǎn)稱為葉節(jié)點(diǎn)
雙親節(jié)點(diǎn)或父節(jié)點(diǎn):若一個(gè)節(jié)點(diǎn)含有子節(jié)點(diǎn),則這個(gè)節(jié)點(diǎn)稱為其子節(jié)點(diǎn)的父節(jié)點(diǎn)
孩子節(jié)點(diǎn)或子節(jié)點(diǎn):一個(gè)節(jié)點(diǎn)含有的子樹的根節(jié)點(diǎn)稱為該節(jié)點(diǎn)的子節(jié)點(diǎn)
根結(jié)點(diǎn):一棵樹中,沒有雙親結(jié)點(diǎn)的結(jié)點(diǎn)
節(jié)點(diǎn)的層次:從根開始定義起,根為第1層,根的子節(jié)點(diǎn)為第2層,以此類推。
樹的高度或深度:樹中節(jié)點(diǎn)的最大層次
非終端節(jié)點(diǎn)或分支節(jié)點(diǎn):度不為0的節(jié)點(diǎn)
兄弟節(jié)點(diǎn):具有相同父節(jié)點(diǎn)的節(jié)點(diǎn)互稱為兄弟節(jié)點(diǎn)
堂兄弟節(jié)點(diǎn):雙親在同一層的節(jié)點(diǎn)互為堂兄弟
節(jié)點(diǎn)的祖先:從根到該節(jié)點(diǎn)所經(jīng)分支上的所有節(jié)點(diǎn)
子孫:以某節(jié)點(diǎn)為根的子樹中任一節(jié)點(diǎn)都稱為該節(jié)點(diǎn)的子孫
森林:由m(m>=0)棵互不相交的樹的集合稱為森林

樹的表示形式

樹有多種表示方式:雙親表示法、孩子表示法、孩子兄弟表示法等。
孩子兄弟表示法:

class Node{int value; //樹中存儲(chǔ)的數(shù)據(jù)Node firstChild;//第一個(gè)孩子引用Node nextBrother;//下一個(gè)兄弟引用 }

二叉樹

一棵二叉樹是結(jié)點(diǎn)的一個(gè)有限集合,該集合或者為空,或者是由一個(gè)根節(jié)點(diǎn)加上兩棵別稱為左子樹和右子樹的二叉樹組成。
二叉樹的特點(diǎn):
每個(gè)結(jié)點(diǎn)最多有兩棵子樹,即二叉樹不存在度大于 2 的結(jié)點(diǎn)
二叉樹的子樹有左右之分,其子樹的次序不能顛倒,因此二叉樹是有序樹

二叉樹的基本形態(tài)


從左往右依次是:空樹、只有根節(jié)點(diǎn)的二叉樹、節(jié)點(diǎn)只有左子樹、節(jié)點(diǎn)只有右子樹、節(jié)點(diǎn)的左右子樹均存在,一般二叉樹都是由上述基本形態(tài)結(jié)合而形成的。

滿二叉樹

滿二叉樹: 一個(gè)二叉樹,如果每一個(gè)層的結(jié)點(diǎn)數(shù)都達(dá)到最大值,則這個(gè)二叉樹就是滿二叉樹。也就是說,如果一個(gè)二叉樹的層數(shù)為K,且結(jié)點(diǎn)總數(shù)是2k?12^k-12k?1 ,則它就是滿二叉樹。

完全二叉樹

完全二叉樹: 完全二叉樹是效率很高的數(shù)據(jù)結(jié)構(gòu),完全二叉樹是由滿二叉樹而引出來的。對(duì)于深度為K的,有n個(gè)結(jié)點(diǎn)的二叉樹,當(dāng)且僅當(dāng)其每一個(gè)結(jié)點(diǎn)都與深度為K的滿二叉樹中編號(hào)從1至n的結(jié)點(diǎn)一一對(duì)應(yīng)時(shí)稱之為完全二叉樹。 要注意的是滿二叉樹是一種特殊的完全二叉樹。

二叉樹的性質(zhì)

若規(guī)定根節(jié)點(diǎn)的層數(shù)為1,則一棵非空二叉樹的第i層上最多有2i?12^{i-1}2i?1(i>0)個(gè)結(jié)點(diǎn)
若規(guī)定只有根節(jié)點(diǎn)的二叉樹的深度為1,則深度為K的二叉樹的最大結(jié)點(diǎn)數(shù)是2k?12^k-12k?1(k>=0)

二叉樹的基礎(chǔ)面試題

  • 二叉樹的前序遍歷題目鏈接
    前中后序的二叉樹遍歷采用遞歸的方式來寫有一個(gè)模板,只需要改變幾行代碼的順序就好。
  • /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/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;} }

    方法二:

    /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/ 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;} }
  • 對(duì)稱二叉樹 題目鏈接
  • 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);} }

    二叉樹的進(jìn)階面試題

  • 二叉樹的構(gòu)建及遍歷題目鏈接
  • 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;}@Overridepublic 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;}// 1. 獲取根的值char rootValue = preorder.get(0);if (rootValue == '#') {ReturnType rt = new ReturnType();rt.builtRoot = null;rt.used = 1;return rt;}TreeNode root = new TreeNode(rootValue);// 2. 構(gòu)建左子樹List<Character> leftSubTreePreorder = preorder.subList(1, preorder.size());ReturnType leftReturn = buildTree(leftSubTreePreorder);root.left = leftReturn.builtRoot;// 3. 構(gòu)建右子樹List<Character> rightSubTreePreorder = preorder.subList(1 + leftReturn.used, preorder.size());ReturnType rightReturn = buildTree(rightSubTreePreorder);root.right = rightReturn.builtRoot;// 4. 返回我們的兩個(gè)信息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;}
  • 給定一個(gè)二叉樹, 找到該樹中兩個(gè)指定節(jié)點(diǎn)的最近公共祖先題目鏈接
  • 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);} }
  • 二叉樹搜索樹轉(zhuǎn)換成排序雙向鏈表題目鏈接
  • 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;} }
  • 根據(jù)一棵樹的前序遍歷與中序遍歷構(gòu)造二叉樹題目鏈接
  • 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;}
  • 從中序和后序序列構(gòu)建二叉樹題目鏈接
  • 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;}
  • 根據(jù)二叉樹創(chuàng)建字符串題目鏈接
  • 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();} }

    前中后序的非遞歸遍歷

    由于遞歸遍歷會(huì)不斷調(diào)用棧,時(shí)間復(fù)雜度高
    前序遍歷

    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; // 記錄上次剛剛后序遍歷過的結(jié)點(diǎn)Stack<TreeNode> stack = new Stack<>();//int height = -1;List<TreeNode> pathOf8 = null;List<TreeNode> pathOf4 = null;while (cur != null || !stack.isEmpty()) {while (cur != null) {// 第一次經(jīng)過結(jié)點(diǎn)stack.push(cur);cur = cur.left;}TreeNode pop = stack.peek();//height = Integer.max(height, stack.size());if (pop.right == null) {if (pop.val == 4) {pathOf4 = new ArrayList<>(stack);} else if (pop.val == 8) {pathOf8 = new ArrayList<>(stack);}// 第二次經(jīng)過結(jié)點(diǎn),但同時(shí)看作第三次經(jīng)過結(jié)點(diǎn)stack.pop();//System.out.println(pop.val);last = pop;} else if (pop.right == last) {if (pop.val == 4) {pathOf4 = new ArrayList<>(stack);} else if (pop.val == 8) {pathOf8 = new ArrayList<>(stack);}// 第三次經(jīng)過結(jié)點(diǎn)stack.pop();//System.out.println(pop.val);last = pop;} else {// 第二次經(jīng)過結(jié)點(diǎn)cur = pop.right;}}//System.out.println(height);System.out.println(pathOf4);System.out.println(pathOf8);}

    驗(yàn)證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);//調(diào)用遍歷方法} }

    總結(jié)

    以上是生活随笔為你收集整理的数据结构树及相关算法题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。