資料結構和演算法面試題系列 二叉樹基礎

2021-09-12 09:47:31 字數 3704 閱讀 3393

這個系列是我多年前找工作時對資料結構和演算法總結,其中有基礎部分,也有各大公司的經典的面試題,最早發布在csdn。現整理為乙個系列給需要的朋友參考,如有錯誤,歡迎指正。

0 概述

在說二叉樹前,先來看看什麼是樹。樹中基本單位是結點,結點之間的鏈結,稱為分支。一棵樹最上面的結點稱之為根節點,而下面的結點為子結點。乙個結點可以有0個或多個子結點,沒有子結點的結點我們稱之為葉結點。

二叉樹是指子結點數目不超過2個的樹,它是一種很經典的資料結構。而二叉搜尋樹(bst)是有序的二叉樹,bst需要滿足如下條件:

若任意結點的左子樹不空,則左子樹上所有節點的值均小於它的根節點的值;

若任意結點的右子樹不空,則右子樹上所有節點的值均大於或等於它的根節點的值;(有些書裡面定義為bst不能有相同值結點,本文將相同值結點插入到右子樹)

任意結點的左、右子樹也分別為二叉查詢樹;

1 定義

我們先定義乙個二叉樹的結點,如下:

typedefstructbtnode btnode;複製**

其中 value 儲存值,left 和 right 指標分別指向左右子結點。二叉搜尋樹跟二叉樹可以使用同乙個結構,只是在插入或者查詢時會有不同。

2 基本操作

接下來看看二叉樹和二叉查詢樹的一些基本操作,包括bst插入結點,bst查詢結點,bst最大值和最小值,二叉樹結點數目和高度等。二叉查詢樹(bst)特有的操作都在函式前加了 bst 字首區分,其他函式則是二叉樹通用的。

1) 建立結點

分配記憶體,初始化值即可。

/** * 建立btnode */btnode *newnode(int value)elsereturnroot;}/**

* bst中插入結點,非遞迴方法

*/btnode *bstinsertiter(btnode *root,intvalue)if(parent->value >= value)parent->left = node;elseparent->right = node;returnroot;}複製**

3) bst 刪除結點

刪除結點稍微複雜一點,要考慮3種情況:

刪除的是葉子結點,好辦,移除該結點並將該葉子結點的父結點的 left 或者 right 指標置空即可。

刪除的結點有兩個子結點,則需要找到該結點左子樹的最大結點(使用後面的bstsearchiter 函式),並將其值替換到待刪除結點中,然後遞迴呼叫刪除函式刪除該結點左子樹最大結點即可。

刪除的結點只有乙個子結點,則移除該結點並將其子結點的值填充到該刪除結點即可(需要判斷是左孩子還是右孩子結點)。

/** * bst中刪除結點 */btnode *bstdelete(btnode *root, int value) if (!node->left&& !node->right) else } else free(node);

} elseif (node->left&&node->right) else else free(node);

returnroot;}複製**

4) bst 查詢結點

注意在非遞迴查詢中會將父結點也記錄下來。

* bst查詢結點-遞迴

*/btnode *bstsearch(btnode *root,intvalue)elseif(root->value>value) else}/**

* bst查詢結點-非遞迴

*/btnode *bstsearchiter(btnode *root, btnode **parent,intvalue)returncurrent;}複製**

5)bst 最小值結點和最大值結點

最小值結點從左子樹遞迴查詢,最大值結點從右子樹遞迴找。

/** * bst最小值結點 */btnode *bstmin(btnode *root)/** * bst最大值結點 */btnode *bstmax(btnode *root)複製**

6)二叉樹結點數目和高度

* 二叉樹結點數目

*/intsize(btnode *root)/**

* 二叉樹高度

*/intheight(btnode *root)複製**

3 二叉樹遍歷

遞迴遍歷-先序、中序、後序、層序

二叉樹遍歷的遞迴實現比較簡單,直接給出**。這裡值得一提的是層序遍歷,先是計算了二叉樹的高度,然後呼叫的輔助函式依次遍歷每一層的結點,這種方式比較容易理解,雖然在時間複雜度上會高一些。

* 二叉樹先序遍歷

*/void preorder(btnode *root)/**

* 二叉樹中序遍歷

*/void inorder(btnode *root)/**

* 二叉樹後序遍歷

*/void postorder(btnode *root)/**

* 二叉樹層序遍歷

*/void levelorder(btnode *root)}/**

* 二叉樹層序遍歷輔助函式-列印第level層的結點

*/void levelorderinlevel(btnode *root, int level) levelorderinlevel(root->left, level-1);levelorderinlevel(root->right, level-1);}複製**

非遞迴遍歷-先序、中序、後序、層序

非遞迴遍歷裡面先序遍歷最簡單,使用乙個棧來儲存結點,先訪問根結點,然後將右孩子和左孩子依次壓棧,然後迴圈這個過程。中序遍歷稍微複雜一點,需要先遍歷完左子樹,然後才是根結點,最後才是右子樹。

後序遍歷使用乙個棧的方法postorderiter()會有點繞,也易錯。所以在面試時推薦用兩個棧的版本postorderiterwith2stack(),容易理解,也比較好寫。

層序遍歷用了佇列來輔助儲存結點,還算簡單。

這裡我另外實現了乙個佇列 btnodequeue 和棧 btnodestack,用於二叉樹非遞迴遍歷。

/*********************//** 二叉樹遍歷-非遞迴 **//*********************//** * 先序遍歷-非遞迴 */void preorderiter(btnode *root) free(stack);}/** * 中序遍歷-非遞迴 */void inorderiter(btnode *root) else } free(stack);}/** * 後續遍歷-使用乙個棧非遞迴 */void postorderiter(btnode *root)  current = pop(stack);  if (current->right && peek(stack) == current->right) else   } while (!is_empty(stack)); }/** * 後續遍歷-使用兩個棧,更好理解一點。 */void postorderiterwith2stack(btnode *root) while (!is_empty(output)) }/** * 層序遍歷-非遞迴 */void levelorderiter(btnode *root) printf("\n"); }}

資料結構 二叉樹面試題(1)

pragma once include include include typedef char datatype typedef struct btreenode btreenode btreenode createnode datatype data btreenode createtree d...

資料結構 二叉樹面試題(2)

pragma once include include include typedef struct bstreenode bstreenode bstreenode createnode int data 如果存在,插入失敗返回 1,否則插入成功,返回 0 int insert bstreenod...

資料結構 二叉樹基本操作 二叉樹面試題

二叉樹的基本概念就不多說了 如下 binarytree.c pragma once include include include include typedef char btdatatype typedef struct binarytreenode btnode a是乙個前序遍歷的陣列 二叉樹...