日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前言

之前很多小伙伴問我怎么看源代碼,還有就是越來越多的程序員都想要看源代碼,搞懂底層原理,但是感覺源代碼非常的晦澀難懂,不夠直接和清晰,所以我希望這篇文章能夠快速帶同學們看懂JAVA源碼,更加深入的學習java,幫助小伙伴們節約學習的時間成本.

1.樹的介紹

  • 什么是樹結構?其實就是一個節點下面有多個子節點,我們稱之為樹結構,如下圖:
  • 普通節點:擁有子節點的節點。
  • 葉子節點:沒有子節點的節點。
一起來看源代碼-01TreeMap添加操作

 

什么是二叉樹?

  • 二叉樹就是一個節點最多只能有2個子節點,分為左節點和右節點,如下圖:

什么是排序二叉樹?

  • 若左子樹不為空,則左子樹所有節點的值小于根節點的值。
  • 若右子樹不為空,則右子樹所有節點的值大于根節點的值。
    如圖:

什么是紅黑樹?紅黑樹其實是一個平衡排序二叉樹,屬于查詢高效的樹結構.請看下圖:

一起來看源代碼-01TreeMap添加操作

 

查詢元素6普通的二叉樹需要操作6次,紅黑樹只需要操作4次,所以紅黑樹查詢更加高效.

##1.TreeMap的結構介紹###1.1 結構關系

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable{

繼承關系:

  • 父類AbstractMap,讓子類擁有基本Map的方法,比如增(put)刪(remove)查(get)等方法.

實現關系:

  • NavigableMap:父接口為SortedMap,所以NavigableMap為可排序接口,表示TreeMap但是一個排序的Map:
  • Cloneable:標記型的接口,內部都沒有方法和屬性,實現 Cloneable來表示該對象能被克隆,能使用Object.clone()方法。如果沒有實現 Cloneable的類對象調用clone()就會拋出CloneNotSupportedException。
  • Serializable:標記型的接口,內部都沒有方法和屬性,實現Serializable表示可進行序列化和反序列化,表示能夠使用在ObjectOutputStream.writeObject())和ObjectInputStream.readObject()

###1.2 基本成員組成

   /**
     * 比較器:類似于一個"裁判",用于比較插入對象和樹節點的內容大小
     * 因為TreeMap是一個紅黑樹,紅黑樹是一個排序二叉樹,插入元素的時候需要進行排序,排序可以使用比較器中的方式排序
     */
    private final Comparator<? super K> comparator;
    /**
     *  根節點
     */
    private transient Entry<K,V> root;
    /**
     * 樹的元素個數
     */
    private transient int size = 0;
    /**
     * 操作次數:增加和刪除操作數都會加1,用于控制并發修改異常
     */
    private transient int modCount = 0;

通過root根節點可以看出一個節點(元素)就是一個Entry對象,所以一個節點(元素)中包含多個數據.結構如下:

    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;//鍵
        V value;//值
        Entry<K,V> left;//左節點
        Entry<K,V> right;//右節點
        Entry<K,V> parent;//父節點
        boolean color = BLACK;//顏色

節點表示如下:

一起來看源代碼-01TreeMap添加操作

 

###1.3添加操作:

public V put(K key, V value) {
        Entry<K, V> t = root;//和插入節點進行比較的樹節點
        //根節點為空
        if (t == null) {
            compare(key, key); //key比key,自己比較自己,目的是想要檢查類型,確保傳入了比較器或者是key實現了可比較接口
            //創建了一個沒有父節點的新的節點,作為根節點
            root = new Entry<>(key, value, null);
            size = 1;//元素個數為1
            modCount++;//操作數+1
            return null;//返回空,根節點添加結束
        }
        int cmp;//表示比較結果
        Entry<K, V> parent;
        // cpr臨時表示比較器
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {//比較器不為空,就使用比較器比較元素
            do {
                parent = t;//父節點為t
                cmp = cpr.compare(key, t.key);//通過比較器對key和樹節點比較得到比較結果
                if (cmp < 0)//比較結果小于0,表示插入的元素比樹節點小
                    t = t.left;//t往左走
                else if (cmp > 0)//比較結果大于0,表示插入的元素比樹節點大
                    t = t.right;//t往右走
                else//cmp比較結果為0,覆蓋節點中的value
                    return t.setValue(value);
            } while (t != null);//直到t為空停下來,保證插入的是節點
        } else {//比較器為空就使用元素中的比較方法
            if (key == null)//插入的元素key為空,沒辦法和樹結構中的元素比較,拋出空指針異常
                throw new NullPointerException();
            /*
             *  key進行強轉,看一下key是否實現了Comparable接口,是否存在compareTo方法,
             *  如果沒有實現接口,也就不確定有沒有compareTo方法了,沒辦法進行比較了
             */
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;//父節點為t
                cmp = k.compareTo(t.key);//通過節點中的比較方法比較插入節點和樹節點的大小
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);//直到沒有節點可以比較
        }
        Entry<K, V> e = new Entry<>(key, value, parent);
        if (cmp < 0)//如果比較結果小于0插入左邊
            parent.left = e;
        else
            parent.right = e;//否則插入右邊
        fixAfterInsertion(e);//對樹進行自平衡
        size++;
        modCount++;
        return null;
    }

###1.4 元素插入后對樹進行自平衡

紅黑樹的自平衡規則:(目標就是黑色節點平衡)

每個節點都只能是紅色或者黑色根節點是黑色每個葉節點(空節點)是黑色的。如果一個結點是紅的,則它兩個子節點都是黑的。也就是說在一條路徑上不能出現相鄰的兩個紅色結點。從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。

    private void fixAfterInsertion(Entry<K, V> x) {//x表示插入的節點,
        x.color = RED;//設置插入的節點為紅色
        //當x不為空,x不為根節點,x的父節點為紅色就需要進行平衡
        while (x != null && x != root && x.parent.color == RED) {
            //x的父節點等于x的爺爺節點的左邊,其實就是說x的父節點是否屬于左節點
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                //獲取x的爺爺節點的右節點
                Entry<K, V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {//爺爺節點的右節點為紅色
                    setColor(parentOf(x), BLACK);//將x的父節點設置為黑色
                    setColor(y, BLACK);//x父節點的兄弟節點設置為黑色
                    setColor(parentOf(parentOf(x)), RED);//爺爺節點設置為紅色
                    x = parentOf(parentOf(x));//x指向原來的爺爺節點,目的是為了繼續往上修改顏色
                } else {//不為紅色,也就是子節點和父節點的顏色出現沖突
                    //如果x等于父節點的右節點
                    if (x == rightOf(parentOf(x))) {
                        //操作的x為x的父節點
                        x = parentOf(x);
                        //左自旋,旋轉后x為原來x的子節點
                        rotateLeft(x);
                    }
                    //x的父節點設置為黑色
                    setColor(parentOf(x), BLACK);
                    //x的爺爺節點設置為紅色
                    setColor(parentOf(parentOf(x)), RED);
                    //右自旋
                    rotateRight(parentOf(parentOf(x)));
                }
            } else {
                //y為爺爺節點的左節點(父節點的兄弟節點)
                Entry<K, V> y = leftOf(parentOf(parentOf(x)));
                //如果y的顏色為紅色
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);//父節點設置為黑色
                    setColor(y, BLACK);//y設置為黑色
                    setColor(parentOf(parentOf(x)), RED);//爺爺節點設置為紅色
                    x = parentOf(parentOf(x));//x指向原來的爺爺節點,目的是為了繼續往上修改顏色
                } else {
                    //如果父節點的左節點為x
                    if (x == leftOf(parentOf(x))) {
                        //x為父節點
                        x = parentOf(x);
                        //右自旋,旋轉后x為原來x的子節點
                        rotateRight(x);
                    }
                    setColor(parentOf(x), BLACK);//父節點設置為黑色
                    setColor(parentOf(parentOf(x)), RED);//爺爺節點設置為紅色
                    rotateLeft(parentOf(parentOf(x)));//左自旋
                }
            }
        }
        root.color = BLACK;//保證根節點必須為黑色
    }

###1.5左自旋

    private void rotateLeft(Entry<K, V> p) {
        //p不為空
        if (p != null) {
            //r表示p的右節點
            Entry<K, V> r = p.right;
            //將r的左節點 賦值給 p的有右節點
            p.right = r.left;
            //如果r的左節點不為空
            if (r.left != null)
                //r的左節點的父節點為p
                r.left.parent = p;
            //r的父節點為p的父節點
            r.parent = p.parent;
            //如果p的父節點為空
            if (p.parent == null)
                //r作為根節點
                root = r;
            //如果p的父節點的左節點等于p,說明p為父節點的左節點
            else if (p.parent.left == p)
                //p的父節點的左節點為r
                p.parent.left = r;
            else
                //p的父節點的左節點為r
                p.parent.right = r;
            //r的左節點為p
            r.left = p;
            //p的父節點為r
            p.parent = r;
        }
    }

###1.6右自旋

 private void rotateRight(Entry<K, V> p) {
        //p不為空
        if (p != null) {
            //l表示p的左節點
            Entry<K, V> l = p.left;
            //p的左節點指向l的右節點
            p.left = l.right;
            //如果l的右節點不為空
            if (l.right != null)
                //l的右節點的父節點為p
                l.right.parent = p;
            //l的父節點指向p的父節點
            l.parent = p.parent;
            //如果p的父節點為空
            if (p.parent == null)
                //l為根節點
                root = l;
            //如果p的父節點的右節點為p
            else if (p.parent.right == p)
                //p的父節點的右節點為l
                p.parent.right = l;
            else
                //p的父節點的左節點為l
                p.parent.left = l;
            //l的右節點指向p
            l.right = p;
            //p的父節點指向l
            p.parent = l;
        }
    }

###1.7案例演示:演示代碼如下:

一起來看源代碼-01TreeMap添加操作

 

代碼執行步驟如下:

一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 


一起來看源代碼-01TreeMap添加操作

 

分享到:
標簽:源代碼 TreeMap
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定