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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构与算法--求1~n能组成的所有二叉搜索树的排列

發布時間:2023/12/4 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构与算法--求1~n能组成的所有二叉搜索树的排列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

給定一個整數n,生成并返回所有N個節點組成并且節點值從1到n互不相同的不同二叉樹,可以按照任意順序

  • 二叉樹文章列表:

數據結構與算法–面試必問AVL樹原理及實現

數據結構與算法–二叉樹的深度問題

數據結構與算法–二叉堆(最大堆,最小堆)實現及原理

數據結構與算法–二叉查找樹轉順序排列雙向鏈表

數據結構與算法-- 二叉樹中和為某一值的路徑

數據結構與算法-- 二叉樹后續遍歷序列校驗

數據結構與算法-- 廣度優先打印二叉樹

數據結構與算法–解決問題的方法- 二叉樹的的鏡像

數據結構與算法–重建二叉樹

數據結構與算法–二叉查找樹實現原理

數據結構與算法–二叉樹實現原理

數據結構與算法–B樹原理及實現

數據結構與算法–數字在排序數組中出現次數

數據結構與算法–死磕二叉樹

數據結構與算法–二叉樹第k個大的節點

數據結構與算法–求1~n能組成的所有二叉搜索樹的排列

全排列問題

  • 排列組合的問題在之前的文中我們已經求解過:
    數據結構與算法–字符串的排列組合問題
    數據結構與算法–代碼完整性案例分析

  • 在求數組全排列的過程中,我們將數組的每一位看成是獨立的,接著每一位上分別排列1~9 的每一位樹,一次對數組的n為進行遞歸,得到我們的全排列。

  • 現題中需要讓1~n 組成n 個階段的不同二叉樹,也就是我們需要求解二叉樹的全排列

方法一:轉為數組全排列實現

  • 在構造二叉樹時候,我們將比root 節點小的放左邊,大的放右邊,那么如果有 從1~n的數組依次對每一個節點構造二叉樹的方式進行insert。那么我們能夠得到一顆二叉樹 T1

  • 如果我們修改數組的順序,修改成 k…k-1, 1, k+1,…n-1, n,接著生成二叉樹T2

  • 那么T1和 T2 大概率是不同的,特殊情況如下:

  • 情況一:3,1,2,4,5

  • 情況二:3,4,5,1,2

  • 如上兩種情況,在中間節點是root節點時,大節點列表4,5 與小節點列表 1,2 分別在兩側,不管數組如何排列,生成的二叉樹是相同的。

  • 經過如上分析,那么我們有如下的實現方案:

    • 生成一個1~n的數組,并且求數組的全排列
    • 每生成一個不同的數組排列,將該數組構建成一個二叉排序樹,并且記錄改二叉排序樹的前序遍歷生成的字符。并存儲在數組 StrLIst中
    • 如果 StrList中存在 元素 k 與當前生成的二叉樹的前序遍歷字符一致,那么說明這種情況以及生成過
    • 如果StrList中不存在,那么我們將新構建的NewBinary添加到我們的二叉排序樹數組 BinaryList中。
  • 如上分析有如下代碼:

/*** 給定一個整數n,生成并返回所有N個節點組成并且節點值從1到n互不相同的不同二叉樹,可以按照任意順序* 解析:求解1~n能組成多少個不同的二叉搜索樹* @author liaojiamin* @Date:Created in 10:15 2021/7/22*/ public class BuildGenerateTrees {public static void main(String[] args) {List<BinaryNode> binaryNodes = new ArrayList<>();List<String> middleSearch = new ArrayList<>();binaryNodes = generateTrees(4);for (int i = 0; i < binaryNodes.size(); i++) {StringBuilder strBu = new StringBuilder();middleSearch.add(printTree(binaryNodes.get(i),strBu));}middleSearch.forEach(System.out::println);}/*** 方法一* 構造二叉樹全排列:構造數組全排列,數組構造成二叉樹,通過前序遍歷值篩選二叉樹* */public static List<BinaryNode> generateTrees(int n){List<BinaryNode> binaryNodes = new ArrayList<>();List<String> middleSearchStr = new ArrayList<>();int[] array = new int[n];for (int i = 1; i <= n; i++) {array[i-1] = i;}return buildGenerateTree(array, binaryNodes, 0, middleSearchStr);}/*** 生成數組的全排列,每種排列按順序生成二叉樹* */public static List<BinaryNode> buildGenerateTree(int[] array, List<BinaryNode> binaryNodes, int start, List<String> middleSearchStr){if(array == null || array.length <=1 || start == (array.length -1)){BinaryNode newNode = buildBinarySearchTree(array);StringBuilder str = new StringBuilder();String middleStr = printTree(newNode, str );if(!middleSearchStr.contains(middleStr)){middleSearchStr.add(middleStr);binaryNodes.add(newNode);}}for (int i = start; i < array.length; i++) {int temp = array[i];array[i] = array[start];array[start] = temp;buildGenerateTree(array, binaryNodes, start+1, middleSearchStr);temp = array[i];array[i] = array[start];array[start] = temp;}return binaryNodes;}/*** 前序遍歷字符集合* */public static String printTree(BinaryNode t, StringBuilder strbu) {if (t == null || t.getElement() == null) {return strbu.toString();}for (int i = 0; i < t.getCount(); i++) {strbu.append(t.getElement() + ":" + t.getHeight()+" ");}printTree(t.getLeft(), strbu);printTree(t.getRight(), strbu);return strbu.toString();}/*** 根據數組構造二叉樹* */public static BinaryNode buildBinarySearchTree(int[] array){if(array == null || array.length <= 0){return null;}BinaryNode node = new BinaryNode(null, null, null);for (int i = 0; i < array.length; i++) {node = insertNode(node, array[i]);}return node;}/*** 插入節點構造二叉搜索樹* */public static BinaryNode insertNode(BinaryNode node, Integer k){if(k == null){return node;}if(node == null || node.getElement() == null){node = new BinaryNode(k, null, null);}int validateK = node.compareTo(k);if(validateK > 0){node.setLeft(insertNode(node.getLeft(), k));}else if (validateK < 0){node.setRight(insertNode(node.getRight(), k));}return node;} }
  • 如上實現方案時間復雜度在O(n2), 空間復雜度存在兩部分,一部分二叉搜索樹數組,這部分取決于節點數量,數量不同排列的個數不同,另一部分在于存儲二叉排序樹的前序遍歷字符串,因此空間復雜度也不會小。

方法二:分治法

  • 方案一的時間復雜度,空間復雜度都不是太理想,第一想法實現方案往往題目沒有這么簡單,在方法一中我們實現我們是受到之前文章中思路的影響,將之前的排列組合的思路套用在 二叉搜索樹的排列上,但是因為兩種數據結構本身復雜度就相差很大,導致二叉搜索樹的排列問題異常復雜。
  • 我們換一種思路,這個也是看到別的思路,看到后就茅塞頓開,因為一旦思路被固定住,要想跳出來還是比較困難的,就和寫小說的作者肯定不會去看別人寫的小說是一個道理。
  • 我們直接將數組全排列思想用到二叉樹搜索樹中:
    • 在1~n中每個數字都有可能是根節點,確定根節點后 k,k 之前的數據 1 ~ k就是左子樹,在k ~ n中每一個就是右子樹
    • 那么我們遍歷1 ~ n中每一位,讓每個數都構造成不同根的 一棵二叉搜索樹
    • 接著處理左子樹 1 ~ k,同樣,1~k中的左子樹也是一棵二叉搜索樹,依然套用以上邏輯,右子樹同理。分別記錄為leftList, rightLIst
    • 那么構造完左右子樹后,我們只需要在左子樹 leftList,rightList進行組合(雙循環構造每種排列方式),就得到了整個二叉樹的排列
      -如下圖,列舉其中一種情況:



  • 經如上分析有如下代碼:
/*** 給定一個整數n,生成并返回所有N個節點組成并且節點值從1到n互不相同的不同二叉樹,可以按照任意順序* 解析:求解1~n能組成多少個不同的二叉搜索樹* @author liaojiamin* @Date:Created in 10:15 2021/7/22*/ public class BuildGenerateTrees {public static void main(String[] args) {List<BinaryNode> binaryNodes = generateTreesBinary(1, 4);BinarySearchTree binarySearchTree = new BinarySearchTree();for (BinaryNode binaryNode : binaryNodes) {binarySearchTree.printTree(binaryNode);}}/*** 方法二* 分治法* */public static List<BinaryNode>generateTreesBinary(int start, int end){List<BinaryNode> binaryNodes = new LinkedList<>();if(start > end){binaryNodes.add(null);return binaryNodes;}for (int i=start;i<=end;i++){List<BinaryNode> leftNode = generateTreesBinary(start, i-1);List<BinaryNode> rightNode = generateTreesBinary(i+1, end);for (BinaryNode left : leftNode) {for (BinaryNode right : rightNode) {binaryNodes.add(new BinaryNode(i, left, right));}}}return binaryNodes;} }
  • 以上思路理解起來更清晰,代碼實現方式也更簡單,時間復雜度還是取決于n的大小,假設n個階段能構建Cn棵二叉搜索樹,那么時間復雜度一棵樹生成需要O(n),Cn棵樹O(n*Cn)
  • 空間復雜度,每一棵樹都有n個階段,有Cn棵樹,總空間復雜度O(n*Cn)

上一篇:數據結構與算法–二叉樹第k個大的節點
下一篇:數據結構與算法一篇幫助你吃下KMP算法

總結

以上是生活随笔為你收集整理的数据结构与算法--求1~n能组成的所有二叉搜索树的排列的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。