jsoup查詢父元素 什麼是二叉查詢樹?

2021-10-13 16:22:54 字數 3317 閱讀 1898

對於樹的基本認識,我們很容易通過我們平常所見到的樹來理解:一棵樹,有乙個根,根往上又會分叉出大樹枝,大樹枝又會分叉出小樹枝,以此往復,直到最後是葉子。而作為資料結構的樹也是類似的,只不過我們通常將它倒著畫。樹的應用也相當廣泛,例如在檔案系統,資料庫索引中的應用等。本文會對樹的基本概念做介紹,但重點介紹二叉查詢樹。

樹是一種無向圖,其中任意兩個節點間存在唯一一條路徑。樹常常用一種遞迴的方式來定義,它是一種資料結構,要麼為空,要麼具有乙個值並且有零個或多個孩子,而每個孩子又是樹。

例如下圖一棵樹,任意兩個節點間只有一條路徑可到達:

圖一:樹

但下圖並非樹:

圖二:非樹

因為從節點root到節點b並非只有一條路徑。

我們可能已經聽過很多樹的名詞,例如,紅黑樹,霍夫曼樹,b樹,b+樹,平衡二叉樹等等,而本文將要介紹二叉查詢樹,很多其他樹都是它的變種,不像鍊錶的線性訪問,二叉查詢樹的大部分操作時間複雜度都為o(logn)。

在學習二叉查詢樹之前,必須要先了解一些名詞,我們借助下面的圖來了解,如果已經清楚了可以跳過此節。

介紹樹的基本名詞:

圖三:樹

圖四:二叉樹

二叉樹是一種樹的特殊形式,它的每個節點最多兩個孩子節點,分別為左孩子和右孩子。而二叉查詢樹在此基礎上,還有乙個特點,就是每個節點比它左子樹的節點值都要大,而比右子樹的節點值都要小

二叉查詢樹常見操作有插入,查詢,刪除以及遍歷。而實際上二叉查詢樹既可以使用陣列來實現,也可以使用鍊錶,本文採用鍊錶來實現。另外本文也排除了兩個節點存在相同值的情況。

節點定義

我們使用乙個結構體來定義它:

typedef struct tree_node

treenode;

二叉查詢樹的插入

我們以資料 10,5,19,4,8,13,24為例,來看看二叉查詢樹的插入流程是怎樣的。

最終完成了所有元素的插入。而觀察插入後的二叉樹可以發現,每個節點都要比左子樹的值大,而比右子樹的值小。另外,我們在插入的時候不斷地與節點值比較,比它大,則將插入右子樹,而比它小,則將插入左子樹,因此這個過程非常容易用遞迴來實現。

/*將value插入到樹中*/

treenode *inserttree(elementtype value,treenode *tree)

else

}/*比當前節點小,則插入到左子樹*/

else if(value value)

/*比當前節點大,則插入到右子樹*/

else if(value > tree->value)

return tree;

}

二叉查詢樹的查詢

實際上,我們在做插入操作的時候,已經在做查詢動作了,因為為了將乙個元素插入到正確的位置,我們需要從根節點開始,不斷比較其值和要插入(查詢)的值的大小,如果比該節點值小,則說明該值需要插入到左子樹,否則插入到右子樹,並且遞迴呼叫,最終找到插入的位置。

查詢的思路有點像二分查詢,我們知道根節點左子樹的值都比根節點值小,而右子樹的值都比根節點的值要大,以此遞迴呼叫,可以很容易找到:

/*查詢值為value的節點*/

treenode *findtree(elementtype value,treenode *tree)

/*從左子樹查詢*/

if(value value)

/*從右邊子樹查詢*/

else if(value > tree->value)

/*找到*/

else

return tree;

}

二叉查詢樹的刪除

相對來說,刪除要比插入和查詢複雜很多。因為它需要考慮很多情況:

第一種情況很容易理解,我們來看第二種和第三種情況。

先看第三種情況,假如我們要從前面的二叉樹中刪除節點值為10的節點。首先我們可以找到節點值為10的節點的右子樹的最小值,為13,因此,將13代替節點值為10的節點值,而幸運的是,節點值為13的節點沒有右子樹,因此釋放根節點的記憶體,完成刪除操作。刪除前後如圖所示:

圖八:二叉查詢樹刪除1

再看第二種情況,假如此時要刪除值為19的節點,從圖中可知,它有乙個右兒子,因此刪除該節點後,需要將其父節點指向它的右兒子,刪除後如下圖:

二叉查詢樹刪除2

圖九:二叉查詢樹刪除2

總體來說,刪除操作並不是一次簡單的查詢就可以完成,甚至刪除會使得整個二叉樹變得非常不平衡,所以如果刪除次數不多,完全可以採用懶惰刪除,即當節點被刪除時,僅做乙個標記,表明它被刪除了,而不是真的從樹中移除,這樣雖然表面上浪費了一點空間,但是如果後面又要插入該元素值,則為新元素分配記憶體的開銷就免了。

根據上面的分析,**如下:

treenode *deletetree(elementtype value,treenode *tree)

/*比當前節點值小,從左子樹查詢並刪除*/

else if(value value)

/*比當前節點值大,從右子樹查詢並刪除*/

else if(value > tree->value)

/*等於當前節點值,並且當前節點有左右子樹*/

else if(null != tree->left  && null != tree->right)

/*要刪除的節點只有乙個子節點或沒有子節點*/

else

return tree;

}

$ gcc -o binarysearchtree binarysearchtree.c

$ ./binarysearchtree

insert 10 to tree

insert 5 to tree

insert 19 to tree

insert 4 to tree

insert 8 to tree

insert 13 to tree

insert 24 to tree

find 13 

本文簡單介紹了二叉查詢樹的插入,查詢,刪除操作,其中刪除操作較為複雜,需要特別注意。

如果待插入資料是已經排好序的,會發生什麼情況?

什麼是二叉查詢樹,有什麼優勢?

對於順序儲存,不需要維護有序性,但查詢效率低 而有序儲存,查詢效率高,但由於插入刪除需要維護有序性,因此效率低。本文要介紹的二叉查詢樹 也叫二叉搜尋樹 二叉排序樹 adt樹 結合了二者的優勢,不僅查詢效率高,插入和刪除效率也高。二叉查詢樹 空樹也是二叉查詢樹 的定義 構建一顆二叉查詢樹的目的,不是為...

什麼是二叉樹

什麼是二叉樹 包含滿二叉樹和完全二叉樹 通過 樹的儲存結構 一節的學習,我們了解了一些樹儲存結構的基本知識。本節將給大家介紹一類具體的樹結構 二叉樹。簡單地理解,滿足以下兩個條件的樹就是二叉樹 本身是有序樹 樹中包含的各個節點的度不能超過 2,即只能是 0 1 或者 2 例如,圖 1a 就是一棵二叉...

動畫 什麼是二叉堆?

動態選擇優先順序最高的任務執行 堆,又稱為優先佇列。雖然名為優先佇列,但堆並不是佇列。堆和佇列是兩種不同的資料結構,堆是樹態的,佇列是線性的。在佇列中,我們可以向佇列新增元素,取出的時候是按照進入佇列的先後順序取出元素的,先進先出 而在堆中,卻不是按照元素新增的先後順序,而是按照元素的優先順序取出元...