樹
樹是一種數據結構,它是由n個有限節點組成一個具有層次關系的集合
-
樹的特點:
每個節點有零個或多個子節點
沒有父節點的節點稱為根節點
每一個非根節點有且只有一個父節點
除了根節點外,每個子節點可以分為多個不相交的子樹
二叉樹
概念
-
二叉樹是樹的特殊一種,具有如下特點:
每個結點最多有兩顆子樹,結點的度最大為2
左子樹和右子樹是有順序的,次序不能顛倒
即使某結點只有一個子樹,也要區分左右子樹
二叉樹是一種有用的折中方案,既有鏈表的好處,也有數組的好處
添加,刪除元素都很快,并且在查找方面也有很多的算法優化
代碼示例:
class TreeNode{
public $value = null;
public $right = null;
public $left = null;
function __construct($value) {
$this->value = $value;
}
}
二叉樹遍歷算法:
前置遍歷(根——>左——>右)
function preTraverse(TreeNode $node) {
if(!$node) {
return;
}
$this->visit($node->value);
$this->preTraverse($node->left);
$this->preTraverse($node->right);
}
中區遍歷(左——>根——>右)
function midTraverse(TreeNode $node) {
if(!$node) {
return;
}
$this->midTraverse($node->left);
$this->visit($node->value);
$this->midTraverse($node->right);
}
后置遍歷(左——>右——>根)
function sufTraverse(TreeNode $node) {
if(!$node) {
return;
}
$this->sufTraverse($node->left);
$this->sufTraverse($node->right);
$this->visit($node->value);
}
層次遍歷
function levelTraverse(TreeNode $node) {
$queue = [$node];
while (!empty($queue)) {
$temp = array_pop($queue);
$this->visit($temp);
if($temp->left) {
array_push($queue, $temp->left);
}
if($temp->right) {
array_push($queue, $temp->right);
}
}
}
滿二叉樹
高度為h,由2^h-1個節點構成的二叉樹稱為滿二叉樹
完全二叉樹
完全二叉樹是由滿二叉樹而引出來的,若設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數(即1~h-1層為一個滿二叉樹),第 h 層所有的結點都連續集中在最左邊,這就是完全二叉樹。注:左右兩邊沒有大小關系。
堆一般都是用完全二叉樹來實現的
二叉查找樹
沒有鍵值相等的節點
若左子樹不為空,左子樹上節點值均小于根節點的值
若右子樹不為空,右子樹上節點值均大于根節點的值
二叉查找樹查找算法
-
步驟:
1、若根結點的關鍵字值等于查找的關鍵字,成功。
2、否則,若小于根結點的關鍵字值,遞歸查左子樹。
3、若大于根結點的關鍵字值,遞歸查右子樹。
4、若子樹為空,查找不成功。
public function find(int $data) {
$p = $this->tree;
while ($p) {
if ($data < $p->data) {
$p = $p->left;
} elseif ($data > $p->data) {
$p = $p->right;
} else {
return $p;
}
}
return null;
}
二叉查找樹插入算法
-
步驟:
1、首先執行查找算法,找出被插結點的父親結點。
2、判斷被插結點是其父親結點的左、右兒子。將被插結點作為葉子結點插入。
3、若二叉樹為空。則首先單獨生成根結點。
public function insert(int $data) {
if (!$this->tree) {
$this->tree = new TreeNode($data);
return true;
}
$p = $this->tree;
while ($p) {
if ($data < $p->data) {
if(!$p->left){
$p->left = new TreeNode($data);
return true;
}
$p = $p->left;
} elseif ($data > $p->data) {
if(!$p->right){
$p->right = new TreeNode($data);
return true;
}
$p = $p->right;
} else {
return false;
}
}
}
平衡二叉樹
它的左右兩個子樹的高度差的絕對值不超過1
并且左右兩個子樹都是一棵平衡二叉樹
平衡二叉查找樹
- 既是一顆二叉查找樹又是一顆平衡二叉樹
B樹
平衡的多叉樹
根節點至少有兩個子節點(可以多個)
每個節點有M-1個key,并且以升序排列
位于M-1和M key的子節點的值位于M-1 和M key對應的Value之間
其它節點至少有M/2個子節點
所有的葉子結點都位于同一層
B+樹
與B樹的區別:
-
B樹每個節點都存儲key和data,所有節點組成這棵樹,并且葉子節點指針為null。
B Tree
-
B+樹只有葉子節點存儲data,非葉子節點存儲指針,葉子節點包含了這棵樹的所有鍵值,葉子節點不存儲指針。
B+Tree
-
應用場景:mysql索引
為什么mysql用B+樹:B+樹的非葉子節點存儲的是指針,相對與B樹更小,如果把所有同一內部節點的關鍵字存放在同一盤塊中(分頁存儲),那么盤塊所能容納的關鍵字數量也越多,一次性讀入內存的需要查找的關鍵字也就越多,查詢效率更高;
紅黑樹
-
圖示:
紅黑樹
- 一種自平衡二叉查找樹
- 節點是紅色或黑色
- 根節點是黑色
- 每個紅色節點的兩個子節點都是黑色
- 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點
- 三種操作:左旋、右旋和變色
- 使用場景:java中的TreeSet,TreeMap,廣泛用在C++的STL中。如map和set都是用紅黑樹實現的
字典樹
-
圖示
字典樹
- 用于統計,排序和保存大量的字符串,經常被搜索引擎系統用于文本詞頻統計
- 利用字符串的公共前綴來減少查詢時間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高
- 應用場景:搜索引擎,用在統計和排序大量字符串,如自動機