【數據結構 ——二叉樹】判斷二叉樹(不限於完全二叉樹)一個結點的層數


創建於:2019.5.23 - 5.25

 

個人思考過程,不是普遍運用的簡便方法。

 

判斷二叉樹(不限於完全二叉樹)一個結點的層數:

 

BinaryNode<T> p;

 

完全二叉樹可以根據公式算出結點p的層數

假如結點p是第i個結點(i>=0),根據完全二叉樹的性質h=(log2 i)+1可算出層數

 

假如要計算普通二叉樹一個結點的層數,則沒有公式,想算法:

 

  •   思考:
  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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM