樹的寬度(廣度)優先遍歷:先訪問樹的第一層節點,再訪問第二層節點,直到最後一層。同一層節點中,從左到右依次訪問。
二叉搜尋樹中,左子節點總是小於等於根節點,右子節點總是大於等於根節點。我們可以平均在o(logn)的時間內根據節點值在二叉搜尋樹中找到乙個節點。
二叉樹的特例有堆和紅黑樹。堆分最大堆和最小堆,最大(小)堆中根節點的值最大(小),很多需要快速找到最值的問題可以用堆來解決。紅黑樹是把樹中的節點定義為紅、黑兩種顏色,並通過規則確保從根節點到葉節點的最長路徑的長度不超過最短路徑長度的兩倍。stl中,set、multiset、map、multimap等資料結構都是基於紅黑樹實現的。
面試題7:重建二叉樹。輸入某二叉樹的前序遍歷和中序遍歷的結果,該二叉樹沒有重複的節點值,請重建該二叉樹,輸出頭結點。二叉樹的節點定義如下:
struct binarytreenode
;
在二叉樹的前序遍歷中,第乙個數字總是樹的根節點的值。但在中序遍歷序列中,根節點的值在序列中間,左子樹的節點的值位於根節點的值的左邊,而右子樹的節點的值位於根節點的值的右邊。這樣我們就可以找到左右子樹的前序遍歷序列和中序遍歷序列,我們可以用遞迴完成剩下的部分:
#include
using
namespace std;
struct binarytreenode
;binarytreenode*
constructcore
(int
* startpreorder,
int* endpreorder,
int* startinorder,
int* endinorder)
else
}int
* rootinorder = startinorder;
while
(rootinorder < endinorder &&
*rootinorder !=
*startpreorder)
if(rootinorder == endinorder &&
*rootinorder !=
*startpreorder)
int leftlength = rootinorder - startinorder;
// 左子樹長度
int* leftpreorderend = startpreorder + leftlength;
// 左子樹先序遍歷尾邊界
if(leftlength >0)
if(leftlength < endpreorder - startpreorder)
return root;
}binarytreenode*
construct
(int
* preorder,
int* inorder,
int length)
return
constructcore
(preorder, preorder + length -
1, inorder, inorder + length -1)
;}void
preorderprint
(binarytreenode* root)
cout << root-
>m_nvalue << endl;
preorderprint
(root-
>m_pleft)
;preorderprint
(root-
>m_pright)
;return;}
intmain()
;int inorder=
; binarytreenode* root =
construct
(preorder, inorder,8)
;preorderprint
(root)
;return0;
}
在劍指offer原書中,這句**有誤:
while
(rootinorder <= endinorder && rootinorder != startpreorder)
if(rootinorder == endinorder &&
*rootinorder !=
*startpreorder)
錯誤在於,當while迴圈條件部分符號為小於等於時,若中序遍歷中未找到根節點,rootinorder會指向endinorder之後,造成下一句中的if條件部分永遠為false。
struct binarytreenode
;
如果乙個節點有右子樹,那麼它中序遍歷的下乙個節點就是它右子樹中的最左子節點,即,從右子樹出發一直沿著指向左子節點的指標,就能找到它中序遍歷的下乙個節點。
如果乙個節點沒有右子樹,並且這個節點是左節點,那麼它的中序遍歷的下乙個節點是它的父節點。
如果乙個節點沒有右子樹,並且這個節點是右節點,我們可以沿著指向父節點的指標向上遍歷,直到找到乙個左節點,這個左節點的父節點就是它中序遍歷的下乙個節點。
假如二叉樹如下圖所示(將a換為1,b換為2,以此類推):
完整**如下:
#include
using
namespace std;
struct binarytreenode
;binarytreenode*
constructcore
(int
* startpreorder,
int* endpreorder,
int* startinorder,
int* endinorder)
else
}int
* rootinorder = startinorder;
while
(rootinorder < endinorder &&
*rootinorder !=
*startpreorder)
if(rootinorder == endinorder &&
*rootinorder !=
*startpreorder)
int leftlength = rootinorder - startinorder;
// 左子樹長度
int* leftpreorderend = startpreorder + leftlength;
// 左子樹先序遍歷尾邊界
if(leftlength >0)
if(leftlength < endpreorder - startpreorder)
return root;
}binarytreenode*
construct
(int
* preorder,
int* inorder,
int length)
return
constructcore
(preorder, preorder + length -
1, inorder, inorder + length -1)
;}binarytreenode*
getnextinorder
(binarytreenode* pnode)
binarytreenode* pnext =
nullptr
;// 用來指向輸入節點中序遍歷的下乙個節點
if(pnode-
>m_pright !=
nullptr
) pnext = prnode;
}else
if(pnode-
>m_pparent !=
nullptr
) pnext = pcurrentparent;
// 當迴圈結束時,要麼找到了乙個是左節點的父節點(此處包含了當輸入節點沒有右
// 子樹時,輸入節點是左節點和輸入節點是右節點兩種情況),要麼父節點為空,意味著輸入節點沿著父節點向上的所有節點都是右節點,
// 而右節點是中序遍歷的最後乙個節點,即輸入節點是整棵樹中序遍歷的最後乙個節點
}return pnext;
// 輸入節點既沒有右節點,其父節點也不存在時,即輸入節點是根節點,並且這棵樹只含左子樹。那麼它就是中序遍歷的最後乙個節點
}void
connectparent
(binarytreenode* root)
if(root-
>m_pleft !=
nullptr)if
(root-
>m_pright !=
nullptr)}
intmain()
;// 上圖二叉樹的中序遍歷
int preorder=
;// 上圖二叉樹的前序遍歷
binarytreenode* root =
construct
(preorder, inorder,9)
;// 構建二叉樹,但不帶父指標
connectparent
(root)
;// 新增二叉樹的父指標
if(binarytreenode* pnode =
getnextinorder
(root-
>m_pright-
>m_pright)
)else
return0;
}
劍指offer學習筆記
筆記主要記錄方法和知識點 知識點1 負數與補碼 乙個參考 知識點2 移位操作 右移 變小 按位 操作 知識點3 0xffffffff表示32位 1 o logn 的方法 非遞迴的快速冪,用到二進位制表示。在迴圈內注意base base。兩個指標等間距一起走。想明白斷開鍊錶這個事情,相當於操作是在原有...
劍指offer學習筆記2
void matrix vector num,int x1,int y1,int x2,int y2 if x1 x2 if x1 x2 y1 y2 if x2 x1 1 y1 y2 x1 y1 x2 y2 template class stackwithmin else void pop t to...
劍指offer筆記
對於這道題來說,書上的和leetcode上的是不一樣的。在leetcode上,是一位陣列中判斷是否有重複數字,有的話任意返回乙個就行。這個思路也有兩個 1.先用乙個排序如快排o nlogn 然後就判斷相鄰元素是否相等,若相等直接返回即可。2.用乙個集合set,遍歷陣列放進去,因為集合有唯一性,若哪個...