創建於:2019.5.23 - 5.25
個人思考過程,不是普遍運用的簡便方法。
判斷二叉樹(不限於完全二叉樹)一個結點的層數:
BinaryNode<T> p;
完全二叉樹可以根據公式算出結點p的層數
假如結點p是第i個結點(i>=0),根據完全二叉樹的性質h=(log2 i)+1可算出層數
假如要計算普通二叉樹一個結點的層數,則沒有公式,想算法:
- 思考:
- 利用層數遍歷的得到的list
結果:只能得出每個結點的序號,無法判斷其層數
- (行不通)方一:利用標明空子樹的前序序列preList
定義一個int型 層數數組
逐個元素(包括空標識)往后遍歷,每遍歷一個層次+1,當上一個是空標識時,該元素層值,上兩個是空標識時,層值 -1,上三個是空標識時,層值 -3
(可行)例一:
prelist= (A B D ^ G ^ ^ ^ C E ^ ^ F ^ ^)
level[]= 1 2 3 4 4 5 5 5 2 3 4 4 3 4 4
(不可行)例二:
Prelist= ( A B E ^ F ^ ^ C ^ D G ^ ^ ^ ^ )
Level[]= (1, 2 , 3, 4, 4 , 5, 5, 4, 5, 5, 6, 7 , 7, 7 ,4 )
3
- (已改進)方法二:利用 標明空子樹標識的前序序列preList和層次遍歷得到的levelList
*泛型用ArrayList代替數組
定義一個數組存放層次序號,長度為二叉樹結點個數
主要遍歷leveList,過程見例一
(可行)例一:
prelist= ( A B D ^ G ^^^C E ^^ F ^^)
levelList= (A B C D E F G )
level[]= 1 2 2 3 3 3 4
過程:
根結點只有一個,所以第一個A的層數肯定是1
第二個B的層數肯定是2;
LevelList下標指向C,preList下標指向D,若不相等,層數不變,且preList下標不變;
*為什么:
levelist中B的下一個是C,要么C是B的孩子,要么C是B的兄弟。在preList中,B的下一個元素不是C(C不是B的孩子),所以C肯定是B的兄弟
LevelList下標指向D,preList的下標仍是D,相等,層數+1(D的層數為3),preList下標+1(指向G)
*為什么:D在C的后面,D可能是B的孩子也可能是C的孩子,但是誰的孩子不重要,肯定不是兄弟(因為是二叉樹),層數+1
(可行)例二:
Prelist= ( A B E ^ F ^^ C ^ D G ^ ^^ ^)
levelList= (A B E C F D G )
level[]= ( 1, 2, 3, 3, 4, 4, 4 )
(改進后可行)例三:
Prelist= ( 100 , 40 , 19, ^^, 21,^^, 60, 28, 11, 5 , 2 ,^^, 3,^^,6, ^^,17, 7,^^,10,^^,32,^^)
levelList= (100, 40, 60, 19, 21, 28, 32, 11, 17 , 5, 6, 7, 10, 2, 3 )
level[]= ( 1, 2, 2, 3, 4, 4, 4, 4 , 4, 4, 4, 4, 4, 4, 4 )
3 3 3 4 4 5 5 5 5 6 6
改進1:(加條件)若prelist中遍歷到的元素前有連續兩個空標識,層數也不變(不論元素是否相等),preList下標+1
改進2:若在preList中遍歷到levelList指向元素之前遍歷過的元素,直接刪除該元素
(不可以只是跳過,因為還要判斷preFlag指向前兩個元素是否為空標識^)
過程:
(部分)
LevelList中指標指向21,Prelist指向21,相等,但因為prelist的21前有兩個連續空標識,所以層數不變;
*為什么:
LevelList中21在19的后面,21可能是19的孩子,21也可能是19的兄弟,看preList,雖然指向21,但前有兩個空標識,說明21肯定不是19的孩子(兩個孩子位被空標識占去),21只可能是19的兄弟,所以層數不變。
LevelList中指標指向28,Prelist指向60,因為levelList中60在28之前已經出現過,所以跳過這個元素,preflag++
*為什么:
判斷一個元素的層數只需要知道,它與前面一個結點的關系(孩子還是兄弟),無需知道更前面哪些元素的信息。由於這個前面出現過的元素的層數已經計算得出,可以直接刪去該元素。
例四:
preList= (18,7, ^^ , 11, 5, ^^, 6, 2,^^, 4,^^)
levelList= (18, 7, 11, 5, 6, 2, 4 )
Level[]= ( 1, 2, 2, 3, 3, 4, 4 )
算法實現代碼:(已測試)
/** * @title: nodelevel * @description: get a given node's level * @author: Navis * @date: May 25, 2019 6:04:49 PM * @param p as root node * @return int :level * @throws:IllegalArgumentException:p==null */ public int nodelevel(BinaryNode<T> p) { if (this.root == null) return -1; if (p == null) throw new IllegalArgumentException("p==null"); int nodeCount = this.getNodeConut(); int[] lev = new int[nodeCount]; ArrayList preList = this.getPrelist(this.root); ArrayList levelList = this.levelList(); int nodeNum = levelList.indexOf(p.data); // p在levelList中的元素位置 lev[0] = 1;// 根結點只有一個,所以第一個元素層數是1 lev[1] = 2;// 第二個元素的層數是2; int preFlag = 2; Object firstBefore = preList.get(0); Object secondBefore = preList.get(1); // 計算層數數組lev[] for (int i = 2; i < levelList.size(); i++) {// 從第3個元素開始 for (int k = 0; k < i; k++) {// 若preFlag指向元素,在levelList的第i個元素前已經出現過,則刪除該元素 if (preList.get(preFlag).equals(levelList.get(k))) { preList.remove(preFlag); k = 0;// k重新開始循環,判斷更新后的preFlag位置元素是否之前出現過 } } if (firstBefore.equals("^") && secondBefore.equals("^")) { lev[i] = lev[i - 1]; preFlag++; while (preList.get(preFlag).equals("^")) { preFlag++; } firstBefore = preList.get(preFlag - 1);// preFlag指向元素的前面第一個元素 secondBefore = preList.get(preFlag - 2);// preFlag指向元素的前面第二個元素 } else { if (preList.get(preFlag).equals(levelList.get(i))) {// 相等 lev[i] = lev[i - 1] + 1; preFlag++; while (preList.get(preFlag).equals("^")) {// 跳過^空標識,指向有值元素 preFlag++; if (preFlag >= preList.size()) {// 防止preList后面全是^空標識,導致一直循環下去 break; } } firstBefore = preList.get(preFlag - 1); secondBefore = preList.get(preFlag - 2); } else {// 不相等 lev[i] = lev[i - 1]; } } // System.out.println(levelList.get(i) + ":" + lev[i]); } return lev[nodeNum]; } /** * @title: getNodeConut * @description: getNodeCount * @author: Navis * @date: May 24, 2019 10:55:13 AM * @return int nodeCount */ public int getNodeConut() { int nodeCount = 0; ArrayList prelist = this.getPrelist(this.root);// 得到帶有空子樹標識的prelist for (int i = 0; i < prelist.size(); i++) { if (prelist.get(i) != "^") nodeCount++; } return nodeCount; } /** * @title: getPrelist * @description: getPrelist; with emptySubTree sign * @author: Navis * @date: May 24, 2019 10:30:34 AM * @param BinaryNode<T> p * @return ArrayList prelist */ public ArrayList getPrelist(BinaryNode<T> p) { ArrayList prelist = new ArrayList(); preorder(prelist, p); return prelist; } /** * @title: preorder * @description: transverse a tree; preorder;get prelist with emptySubTree sign * @author: Navis * @date: May 23, 2019 8:55:17 AM * @param ArrayList prelist * @param BinaryNode<T> p */ public void preorder(ArrayList prelist, BinaryNode<T> p) { if (p != null) { prelist.add(p.data); preorder(prelist, p.left); preorder(prelist, p.right); } else prelist.add("^"); // 空子樹標識 } /** * @title: levelList * @description: get levelList;levelOrder * @author: Navis * @date: May 24, 2019 11:54:07 AM * @return ArrayList levelList */ public ArrayList levelList() { LinkedQueue<BinaryNode<T>> queue = new LinkedQueue<>();// 空隊列 BinaryNode<T> p = this.root;// 根結點不入隊 ArrayList levelList = new ArrayList(); while (p != null) { levelList.add(p.data); // 將已出隊結點p的元素值加入levelList if (p.left != null) queue.add(p.left);// p的左孩子入隊 if (p.right != null) queue.add(p.right);// p的右孩子入隊 p = queue.poll();// p指向出隊結點,若隊列為空返回null } return levelList; }