1. 程式人生 > >資料結構基礎溫故-6.查詢(上):基本查詢與樹表查詢

資料結構基礎溫故-6.查詢(上):基本查詢與樹表查詢

只要你開啟電腦,就會涉及到查詢技術。如炒股軟體中查股票資訊、硬碟檔案中找照片、在光碟中搜DVD,甚至玩遊戲時在記憶體中查詢攻擊力、魅力值等資料修改用來作弊等,都要涉及到查詢。當然,在網際網路上查詢資訊就更加是家常便飯。查詢是計算機應用中最常用的操作之一,也是許多程式中最耗時的一部分,查詢方法的優劣對於系統的執行效率影響極大。因此,本篇討論一些查詢方法。

一、順序查詢

1.1 基本思想

  順序查詢(Sequential Search)又叫線性查詢,是最基本的查詢技術,它的查詢過程是:從表中第一個(或最後一個)記錄開始,逐個進行記錄的關鍵字和給定值比較,若某個記錄的關鍵字和給定值相等,則查詢成功,找到所查的記錄;如果直到最後一個(或第一個)記錄,其關鍵字和給定值比較都不等時,則表中沒有所查的記錄,查詢不成功。

順序查詢所用時間與查詢關鍵字Key線上性表中的位置有關,其時間複雜度為O(n)。順序查詢的優點在於:演算法簡單易行,且對錶的結構無任何要求(無論是順序表還是連結串列,也無論是按關鍵字有序還是無序存放)。當然,其缺點也比較明顯:演算法效率較低,在較大規模的資料集合中進行查詢時,不宜採用順序查詢

1.2 程式碼實現

        static void SequenceSearchDemo()
        {
            int[] seqList = { 2, 8, 10, 13, 21, 36, 51, 57, 62, 69 };

            Console.WriteLine(
"-------------基本順序查詢-------------"); Console.WriteLine("查詢51:{0}", SequenceSearch(seqList, 51)); Console.WriteLine("查詢8:{0}", SequenceSearch(seqList, 8)); Console.WriteLine("查詢15:{0}", SequenceSearch(seqList, 15)); } static int SequenceSearch(int
[] seqList, int key) { int index = -1; for (int i = 0; i < seqList.Length; i++) { if (seqList[i] == key) { index = i; break; } } return index; }

  執行結果為:

二、二分查詢

2.1 基本思想

  折半查詢(Binary Search)技術,又稱為二分查詢。它的前提是線性表中的記錄必須是關鍵碼有序(通常從小到大有序),線性表必須採用順序儲存,其時間複雜度為O(logn)。

折半查詢的基本思想是:在有序表中,取中間記錄作為比較物件,若給定值與中間記錄的關鍵字相等,則查詢成功;若給定值小於中間記錄的關鍵字,則在中間記錄的左半區繼續查詢;若給定值大於中間記錄的關鍵字,則在中間記錄的右半區繼續查詢。不斷重複上述過程,直到查詢成功,或所有查詢區域無記錄,查詢失敗為止。

2.2 程式碼實現

        static void SeqSearchDemo()
        {
            int[] seqList = { 2, 8, 10, 13, 21, 36, 51, 57, 62, 69 };

            Console.WriteLine("-------------基本二分查詢-------------");
            Console.WriteLine("查詢51:{0}", SeqSearch(seqList, 51));
            Console.WriteLine("查詢8:{0}", SeqSearch(seqList, 8));
            Console.WriteLine("查詢15:{0}", SeqSearch(seqList, 15));
        }

        static int SeqSearch(int[] seqList, int key)
        {
            int low = 0;
            int high = seqList.Length - 1;
            int mid;

            while (low <= high)
            {
                mid = (low + high) / 2;
                if (seqList[mid] == key)
                {
                    return mid;
                }
                else if (seqList[mid] < key)
                {
                    low = mid + 1;
                }
                else
                {
                    high = mid - 1;
                }
            }

            return -1;
        }

  執行結果為:

2.3 Array.BinarySearch方法

  在.NET中的陣列類Array中,內建了一個二分查詢的方法—Array.BinarySearch,它是一個靜態方法。需要注意的是:在呼叫這個方法前,需要確保作為引數的查詢表內的關鍵字已經有序,否則就需要手動呼叫Array.Sort()方法進行排序。

    int[] seqList = { 32, 25, 8, 10, 13, 21, 36, 51, 57, 62, 69 };
    Console.WriteLine("-------------Array.BinarySearch-------------");
    Array.Sort(seqList);
    Console.WriteLine("查詢51:{0}", Array.BinarySearch(seqList, 51));
    Console.WriteLine("查詢69:{0}", Array.BinarySearch(seqList, 69));
    Console.WriteLine("查詢15:{0}", Array.BinarySearch(seqList, 15));

  在Array.BinarySearch()方法內部的求mid值的公式為:mid=low+((high-low)>>1),這是因為整數右移一位相當於整數除2操作,但位移運算的速度快於除法運算

2.4 System.Collections.SortedList類

  在.NET中的System.Collections名稱空間下,SortedListSortedList<TKey,TValue>兩個類是用於存放鍵值對的集合類,它們的元素儲存於線性表中,並按鍵值進行排序。其中SortedList使用了兩個陣列來分別存放key和value,並巧妙地運用了二分查詢使得它的各項效能與ArrayList十分近似。

    SortedList<string, string> studentList = new SortedList<string, string>();
    studentList.Add("005", "張三");
    studentList.Add("004", "李四");
    studentList.Add("006", "王五");
    studentList.Add("012", "馬六");
    studentList.Add("002", "錢七");
    studentList.Add("009", "劉八");

    foreach (var item in studentList)
    {
       Console.WriteLine("{0}:{1}", item.Key, item.Value);
    }

  執行結果為:

  回過頭來,我們看看SortedList類的Add方法,從中可以發現,它藉助了Array.BinarySearch方法獲取儲存位置,也就是說它也使用了二分查詢方法。

三、查詢樹方法

  前面討論的幾種查詢方法中,二分查詢效率最高,但其要求表中記錄按照關鍵字有序,且只能在順序表上實現,從而需要在插入和刪除操作時移動很多的元素。如果不希望表中記錄按關鍵字有序,而又希望得到較高的插入和刪除效率,可以考慮使用幾種特殊的二叉樹或樹作為表的組織形式。

3.1 二叉查詢樹

(1)基本概念

  二叉查詢樹(Binary Search Tree,BST)又稱二叉排序樹,它是滿足如下性質的二叉樹:

  •  若它的左子樹非空,則左子樹上所有記錄的值均小於根記錄的值;
  •  若它的右子樹非空,則右子樹上所有記錄的值均大於根記錄的值;
  •  左、右子樹又各是一棵二叉查詢樹。

  假如有一個序列{62,88,58,47,35,73,51,99,37,93},那麼構造出來的二叉查詢樹如下圖所示:

  二叉查詢樹是遞迴定義的,其一般理解是:二叉查詢樹中任一節點,其值為k,只要該節點有左孩子,則左孩子的值必小於k,只要有右孩子,則右孩子的值必大於k。二叉查詢樹的一個重要的性質是:中序遍歷該樹得到的序列是一個遞增有序的序列

(2)二叉查詢樹的新增操作

(3)二叉查詢樹的刪除操作

(4)二叉查詢樹的程式碼實現

  有關二叉查詢樹的新增和刪除節點如何實現,可以閱讀《資料結構基礎溫故—4.樹(中)》一文,該文使用C#實現了二叉查詢樹。

注意:對於二叉查詢樹最糟糕的情況是插入一個有序序列,使得具有N個元素的集合生成了高度為N的單枝二叉樹,從而使其退化了一個單鏈表,其查詢效率也會會由O(logn)變為O(n)。

3.2 平衡二叉樹

  剛剛提到在二叉查詢樹中,如果插入元素的順序接近有序,那麼二叉查詢樹將退化為連結串列,從而導致二叉查詢樹的查詢效率大大降低。前蘇聯兩位科學家G.M. Adelson-Velskii和E.M. Landis在1962年的一篇論文中提出了一種自平衡二叉查詢樹。這種二叉查詢樹在插入和刪除操作中,可以通過一系列的旋轉操作來保持平衡,從而保證了二叉查詢樹的查詢效率。最終這種二叉查詢樹被命名為AVL-Tree,也被稱為平衡二叉樹。

(1)基本概念

  平衡二叉樹定義(AVL):它或者是一顆空樹,或者具有以下性質的二叉樹:它的左子樹和右子樹的深度之差的絕對值不超過1,且它的左子樹和右子樹都是一顆平衡二叉樹。

  平衡因子(BF):結點的左子樹的深度減去右子樹的深度,那麼顯然-1<=bf<=1;

PS:平衡二叉樹上所有結點的平衡因子只可能是-1、0和1。只要二叉樹上有一個結點的平衡因子的絕對值大於1,則該二叉樹就是不平衡的

(2)平衡二叉樹的操作

假設我們已經有棵平衡二叉樹,現在讓我們來看看插入節點後,原來節點失去平衡後,平衡二叉樹會進行不同型別(RR、LL、LR以及RL)的旋轉來保持平衡。

3.3 System.Collections.Generic.SortedDictionary類

  另一種與平衡二叉樹類似的是紅黑樹,紅黑樹和AVL樹的區別在於它使用顏色來標識節點的高度,它所追求的是區域性平衡而不是AVL樹中的非常嚴格的平衡。在.NET中的System.Collections.Generic名稱空間下,SortedDictionary類就是使用紅黑樹實現的。紅黑樹和AVL樹的原理非常接近,但是複雜度卻遠勝於AVL樹,這裡也就不做討論。園子裡也已經有了不少關於紅黑樹的比較好的介紹的文章,有興趣的可以去閱讀閱讀。

  在程式碼中,我們可以模擬100000個數字進行新增:

            Random random = new Random();
            int array_count = 100000;
            List<int> intList = new List<int>();
            for (int i = 0; i <= array_count; i++)
            {
                int ran = random.Next();
                intList.Add(ran);
            }

            SortedDictionary<int, int> dic_int = new SortedDictionary<int, int>();
            foreach (var item in intList)
            {
                if (dic_int.ContainsKey(item) == false)
                {
                    dic_int.Add(item, item);
                }
            }

  當然,還可以與SortedList(SortedList內部是Array,而SortedDictionary內部是紅黑樹)進行一下對比,這裡使用了老趙的CodeTimer類

  (1)新增操作對比

  由於SortedList用Array陣列儲存,每次進行插入操作時,首先用二分查詢法找到相應的位置,得到位置以後,SortedList會把該位置以後的值依次往後移一個位置,空出當前位,再把值插入,這個過程中用到了Array.Copy方法,而呼叫該方法是比較損耗效能的,該程式碼如下:

private void  Insert(int  index, TKey key, TValue value)
{
    ......

    if  (index < this._size)
    {
        Array.Copy(this.keys, index, this.keys, index + 1, this._size - index);
        Array.Copy(this.values, index, this.values, index + 1, this._size - index);
    }
    
    ......
}

  SortedDictionary在新增操作時,只會根據紅黑樹的特性,旋轉節點,保持平衡,並沒有對Array.Copy的呼叫。下面我們就用資料測試一下:迴圈一個int型、容量為10w的隨機陣列,分別用SortedList和SortedDictionary新增,看看效率如何:

        static void SortedAddInTest()
        {
            Random random = new Random();
            int array_count = 100000;
            List<int> intList = new List<int>();
            for (int i = 0; i <= array_count; i++)
            {
                int ran = random.Next();
                intList.Add(ran);
            }

            SortedList<int, string> sortedlist_int = new SortedList<int, string>();
            SortedDictionary<int, string> dic_int = new SortedDictionary<int, string>();
            CodeTimer.Time("sortedList_Add_int", 1, () =>
            {
                foreach (var item in intList)
                {
                    if (sortedlist_int.ContainsKey(item) == false)
                        sortedlist_int.Add(item, "test" + item.ToString());
                }
            });
            CodeTimer.Time("sortedDictionary_Add_int", 1, () =>
            {
                foreach (var item in intList)
                {
                    if (dic_int.ContainsKey(item) == false)
                        dic_int.Add(item, "test" + item.ToString());
                }
            });
        }

  執行結果如下圖所示:

  從上圖可以看出:在大量新增操作的情況下,SortedDictionary效能(無論是從時間消耗、CPU計算、還是GC垃圾回收次數)優於SortedList。

  (2)查詢操作對比

  兩者的查詢操作中,時間複雜度都為O(logn),且原始碼中也沒有額外的操作造成效能損失,那麼他們在查詢操作中效能如何?繼續上面一個例子進行測試。

        static void SortedQueryInTest()
        {
            Random random = new Random();
            int array_count = 100000;
            List<int> intList = new List<int>();
            for (int i = 0; i <= array_count; i++)
            {
                int ran = random.Next();
                intList.Add(ran);
            }

            SortedList<int, string> sortedlist_int = new SortedList<int, string>();
            SortedDictionary<int, string> dic_int = new SortedDictionary<int, string>();

            foreach (var item in intList)
            {
                if (sortedlist_int.ContainsKey(item) == false)
                    sortedlist_int.Add(item, "test" + item.ToString());
            }

            foreach (var item in intList)
            {
                if (dic_int.ContainsKey(item) == false)
                    dic_int.Add(item, "test" + item.ToString());
            }

            CodeTimer.Time("sortedList_Search_int", 1, () =>
            {
                foreach (var item in intList)
                {
                    sortedlist_int.ContainsKey(item);
                }
            });

            CodeTimer.Time("sortedDictionary_Search_int", 1, () =>
            {
                foreach (var item in intList)
                {
                    dic_int.ContainsKey(item);
                }
            });
        }

  執行結果如下圖所示:

  從上圖可以看出:兩者在迴圈10w次的情況下,查詢操作SortedList大概為SortedDictionary的一半,這是由於SortedList已經在插入操作時已經將其轉化為了一個有序的陣列,從而在查詢時可以直接使用二分查詢提高效率。SortedDictionary則是一個二叉排序樹,查詢效率理論上也是O(logn),但其較有序陣列的二分查詢效率還是差了一點點。

  (3)刪除操作對比

  從新增操作例子可以看出,由於SortedList內部使用Array陣列進行儲存資料,而陣列本身的侷限性使得SortedList大部分的新增操作都要呼叫Array.Copy方法,從而導致了效能的損失,這種情況同樣存在於刪除操作中。

  SortedList每次刪除操作都會將刪除位置後的值往前挪動一位,以填補刪除位置的空白,這個過程剛好跟新增操作反過來,同樣也需要呼叫Array.Copy方法,相關程式碼如下:

public void RemoveAt(int index)
{
    ......

    if (index < this._size)
    {
        Array.Copy(this.keys, index + 1, this.keys, index, this._size - index);
        Array.Copy(this.values, index + 1, this.values, index, this._size - index);
    }
    
    ......
}

  而SortedDictionary使用紅黑樹結構儲存元素,紅黑樹本身是一棵二叉查詢樹,它的刪除和二叉查詢樹的刪除類似。首先要找到真正的刪除點,當被刪除結點n存在左右孩子時,真正的刪除點應該是n的中序遍歷的前驅,關於這一點請參考二叉查詢樹的刪除。如下圖所示,當刪除結點20時,實際被刪除的結點應該為18,結點20的資料變為18。

  這裡,我們仍然選擇上面的例子來進行一個簡單的對比測試,仍然是10w個元素的資料量:

        static void SortedDeleteInTest()
        {
            Random random = new Random();
            int array_count = 100000;
            List<int> intList = new List<int>();
            for (int i = 0; i <= array_count; i++)
            {
                int ran = random.Next();
                intList.Add(ran);
            }

            SortedList<int, string> sortedlist_int = new SortedList<int, string>();
            SortedDictionary<int, string> dic_int = new SortedDictionary<int, string>();

            foreach (var item in intList)
            {
                if (sortedlist_int.ContainsKey(item) == false)
                    sortedlist_int.Add(item, "test" + item.ToString());
            }

            foreach (var item in intList)
            {
                if (dic_int.ContainsKey(item) == false)
                    dic_int.Add(item, "test" + item.ToString());
            }

            CodeTimer.Time("sortedList_Delete_String", 1, () =>
            {
                foreach (var item in intList)
                {
                    sortedlist_int.Remove(item);
                }
            });

            CodeTimer.Time("sortedDictionary_Delete_String", 1, () =>
            {
                foreach (var item in intList)
                {
                    dic_int.Remove(item);
                }
            });
        }

  執行結果如下圖所示:

  從上圖也可以看出:在10w次的刪除操作中,SortedDictionary的處理速度和效能消耗較SortedList好的不是一丁半點

總結:

①SortedList用陣列儲存資料,所以對GC比較友好一點,而且對於相對比較有序的輸入源而言,操作較少(eg:List<int> intList = Enumerable.Range(0, array_count).ToList())。
②SortedDictionary用節點鏈儲存資料,所以對GC而言,相對比較複雜。所以當可以預見到集合中的元素比較少的時候或者資料本身相對比較有序時,應該傾向於使用SortedList。

參考資料

(1)程傑,《大話資料結構》

(2)陳廣,《資料結構(C#語言描述)》

(3)段恩澤,《資料結構(C#語言版)》

特別感謝

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。

相關推薦

資料結構基礎-5.圖圖的基本概念

前面幾篇已經介紹了線性表和樹兩類資料結構,線性表中的元素是“一對一”的關係,樹中的元素是“一對多”的關係,本章所述的圖結構中的元素則是“多對多”的關係。圖(Graph)是一種複雜的非線性結構,在圖結構中,每個元素都可以有零個或多個前驅,也可以有零個或多個後繼,也就是說,元素之間的關係是任意的。現實生活中的很多

資料結構基礎-5.圖圖的遍歷演算法

上一篇我們瞭解了圖的基本概念、術語以及儲存結構,還對鄰接表結構進行了模擬實現。本篇我們來了解一下圖的遍歷,和樹的遍歷類似,從圖的某一頂點出發訪問圖中其餘頂點,並且使每一個頂點僅被訪問一次,這一過程就叫做圖的遍歷(Traversing Graph)。如果只訪問圖的頂點而不關注邊的資訊,那麼圖的遍歷十分簡單,使用

資料結構基礎-5.圖最小生成樹演算法

圖的“多對多”特性使得圖在結構設計和演算法實現上較為困難,這時就需要根據具體應用將圖轉換為不同的樹來簡化問題的求解。 一、生成樹與最小生成樹 1.1 生成樹   對於一個無向圖,含有連通圖全部頂點的一個極小連通子圖成為生成樹(Spanning Tree)。其本質就是從連通圖任一頂點出發進行遍歷操作所經過

資料結構基礎-5.圖最短路徑

圖的最重要的應用之一就是在交通運輸和通訊網路中尋找最短路徑。例如在交通網路中經常會遇到這樣的問題:兩地之間是否有公路可通;在有多條公路可通的情況下,哪一條路徑是最短的等等。這就是帶權圖中求最短路徑的問題,此時路徑的長度不再是路徑上邊的數目總和,而是路徑上的邊所帶權值的和。帶權圖分為無向帶權圖和有向帶權圖,但如

資料結構基礎-6.查詢基本查詢查詢

只要你開啟電腦,就會涉及到查詢技術。如炒股軟體中查股票資訊、硬碟檔案中找照片、在光碟中搜DVD,甚至玩遊戲時在記憶體中查詢攻擊力、魅力值等資料修改用來作弊等,都要涉及到查詢。當然,在網際網路上查詢資訊就更加是家常便飯。查詢是計算機應用中最常用的操作之一,也是許多程式中最耗時的一部分,查詢方法的優劣對於系統的執

資料結構基礎-6.查詢雜湊

雜湊(雜湊)技術既是一種儲存方法,也是一種查詢方法。然而它與線性表、樹、圖等結構不同的是,前面幾種結構,資料元素之間都存在某種邏輯關係,可以用連線圖示表示出來,而雜湊技術的記錄之間不存在什麼邏輯關係,它只與關鍵字有關聯。因此,雜湊主要是面向查詢的儲存結構。雜湊技術最適合的求解問題是查詢與給定值相等的記錄。

資料結構基礎-1.線性

在上一篇中,我們學習了線性表最基礎的表現形式-順序表,但是其存在一定缺點:必須佔用一整塊事先分配好的儲存空間,在插入和刪除操作上需要移動大量元素(即操作不方便),於是不受固定儲存空間限制並且可以進行比較快捷地插入和刪除操作的連結串列橫空出世,所以我們就來複習一下連結串列。 一、單鏈表基礎 1.1 單鏈表的

資料結構基礎-4.二叉

上面兩篇我們瞭解了樹的基本概念以及二叉樹的遍歷演算法,還對二叉查詢樹進行了模擬實現。數學表示式求值是程式設計語言編譯中的一個基本問題,表示式求值是棧應用的一個典型案例,表示式分為字首、中綴和字尾三種形式。這裡,我們通過一個四則運算的應用場景,藉助二叉樹來幫助求解表示式的值。首先,將表示式轉換為二叉樹,然後通過

資料結構基礎-4.二叉

在上一篇中,我們瞭解了樹的基本概念以及二叉樹的基本特點和程式碼實現,還用遞迴的方式對二叉樹的三種遍歷演算法進行了程式碼實現。但是,由於遞迴需要系統堆疊,所以空間消耗要比非遞迴程式碼要大很多。而且,如果遞迴深度太大,可能系統撐不住。因此,我們使用非遞迴(這裡主要是迴圈,迴圈方法比遞迴方法快, 因為迴圈避免了一系

資料結構基礎-4.二叉

前面所討論的線性表元素之間都是一對一的關係,今天我們所看到的結構各元素之間卻是一對多的關係。樹在計算機中有著廣泛的應用,甚至在計算機的日常使用中,也可以看到樹形結構的身影,如下圖所示的Windows資源管理器和應用程式的選單都屬於樹形結構。樹形結構是一種典型的非線性結構,除了用於表示相鄰關係外,還可以表示層次

資料結構基礎-1.線性

在上一篇中,我們瞭解了單鏈表與雙鏈表,本次將單鏈表中終端結點的指標端由空指標改為指向頭結點,就使整個單鏈表形成一個環,這種頭尾相接的單鏈表稱為單迴圈連結串列,簡稱迴圈連結串列(circular linked list)。 一、迴圈連結串列基礎 1.1 迴圈連結串列節點結構   迴圈連結串列和單鏈表的

資料結構基礎查詢查詢

轉自:http://www.cnblogs.com/edisonchou/p/4700850.html   查詢(上):基本查詢與樹表查詢 只要你開啟電腦,就會涉及到查詢技術。如炒股軟體中查股票資訊、硬碟檔案中找照片、在光碟中搜DVD,甚至玩遊戲時在記憶體中查詢攻擊力、魅力值等

資料結構基礎-2.棧

現實生活中的事情往往都能總結歸納成一定的資料結構,例如餐館中餐盤的堆疊和使用,羽毛球筒裡裝的羽毛球等都是典型的棧結構。而在.NET中,值型別線上程棧上進行分配,引用型別在託管堆上進行分配,本文所說的“棧”正是這種資料結構。棧和佇列都是常用的資料結構,它們的邏輯結構與線性表相通,不同之處則在於操作受某種特殊限制

資料結構基礎-3.佇列

在日常生活中,佇列的例子比比皆是,例如在車展排隊買票,排在隊頭的處理完離開,後來的必須在隊尾排隊等候。在程式設計中,佇列也有著廣泛的應用,例如計算機的任務排程系統、為了削減高峰時期訂單請求的訊息佇列等等。與棧類似,佇列也是屬於操作受限的線性表,不過佇列是隻允許在一端進行插入,在另一端進行刪除。在其他資料結構如

資料結構基礎-7.排序

排序(Sorting)是計算機內經常進行的一種操作,其目的是將一組“無序”的記錄序列調整為按關鍵字“有序”的記錄序列。如何進行排序,特別是高效率地進行排序時計算機工作者學習和研究的重要課題之一。排序有內部排序和外部排序之分,若整個排序過程不需要訪問外存便能完成,則稱此類排序為內部排序,反之則為外部排序。本篇主

15-二分查詢圖和用最省記憶體的方式實現快速查詢功能?

今天我們講一種針對有序資料集合的查詢演算法:二分查詢(Binary Search)演算法,也叫折半查詢演算法。二分查詢的思想非常簡單,很多非計算機專業的同學很容易就能理解,但是看似越簡單的東西往往越難掌握好,想要靈活應用就更加困難。 老規矩,我們還是來看一道思考

提高篇1RMQ問題ST

style 總結 線段 區間 選擇 線段樹 支持 ins 例題 RMQ是英文Range Minimum/Maximum Query的縮寫,是詢問某個區間內的最值,這裏講一種解法:ST算法 ST算法通常用在要多次(10^6級別)詢問區間最值的問題中,相比於線段樹,它實現更簡

Druid.io系列基本概念架構

在介紹Druid架構之前,我們先結合有關OLAP的基本原理來理解Druid中的一些基本概念。 1 資料 以圖3.1為例,結合我們在第一章中介紹的OLAP基本概念,按列的型別上述資料可以分成以下三類: 時間序列(Timestamp),Druid既是記憶

Netty 入門基本元件執行緒模型

  Netty 的學習內容主要是圍繞 TCP 和 Java NIO 這兩個點展開的,後文中所有的內容如果沒有特殊說明,那麼所指的內容都是與這兩點相關的。由於 Netty 是基於 Java NIO 的 API 之上構建的網路通訊框架,Java NIO 中的幾個元件,都能在 Netty 中找到對應的封裝。下面我們

iOS/OS X記憶體管理基本概念原理

CSDN移動將持續為您優選移動開發的精華內容,共同探討移動開發的技術熱點話題,涵蓋移動應用、開發工具、移動遊戲及引擎、智慧硬體、物聯網等方方面面。如果您想投稿、尋求《近匠》報道,或給文章挑錯,歡迎傳送郵件至tangxy#csdn.net(請把#改成@)。  在Objective-C的記憶體管理中,其實就