二叉查找树:在二叉树的基础上,若左子树不空,则左子树上所有结点的值均小于根结点的值; 若右子树不空,则右子树上所有结点的值均大于根结点的值; 且左、右子树也同时也是 二叉查找树。 亦称二叉排序树、二叉搜索树。
// Binary Search Tree
typedef int keyType;
struct BSNode {
BSNode(int k) :Key(k), Left(NULL), Right(NULL) {}
keyType Key; // 节点值
BSNode* Left; // 左子树
BSNode* Right; // 右子树
};
class BSTree {
public:
bool insert(keyType key); // 插入
bool deleted(keyType key); // 删除
void PreOrder(BSNode *node); // 先序遍历
void InOrder(BSNode* node); // 中序遍历
void PosOrder(BSNode* node); // 后序遍历
void LevelOrder(); // 层次遍历
BSTree() :Root(NULL) {}
public:
BSNode* Root; // 树根节点
};
插入:
// 插入
bool BSTree::insert(keyType key) {
if (NULL == Root) {
Root = new BSNode(key);
return true;
}
// 找到待插入节点位置
BSNode* T = Root;
Statu flat = UNKNOW;
while (1) {
if (key == T->Key) {
return false;
}
else if (key < T->Key) {
if (NULL == T->Left) {
flat = LEFT;
break;
}
T = T->Left;
}
else {
if (NULL == T->Right) {
flat = RIGHT;
break;
}
T = T->Right;
}
}
if (LEFT == flat) {
T->Left = new BSNode(key);
}
else if (RIGHT == flat) {
T->Right = new BSNode(key);
}
return true;
}
删除:
// 前驱、后继:中序遍历下节点的前一个和后一个
// 找某一节点的前驱
keyType FindPre(BSNode* node) {
BSNode* T = node->Left;
while (T->Right) {
T = T->Right;
}
return T->Key;
}
// 找某一节点的后继
keyType FindPos(BSNode* node) {
BSNode* T = node->Right;
while (T->Left) {
T = T->Left;
}
return T->Key;
}
// 删除
bool BSTree::deleted(keyType key) {
BSNode* T = Root;
BSNode* P = T; // T 的父节点
// 找到 key 所在节点
while (T) {
if (key < T->Key) {
P = T;
T = T->Left;
}
else if (key > T->Key) {
P = T;
T = T->Right;
}
else {
// 叶子节点
if (NULL == T->Left&&NULL == T->Right) {
if (P->Left == T) P->Left = NULL;
else P->Right = NULL;
return true;
}
// 非叶子节点 找到该节点的 前驱 或 后继
else if (NULL != T->Right) { // 有后继
key = FindPos(T);
T->Key = key; // 将 T的后继节点值赋值给 T ,到时候再删后继节点即可
P = T;
T = T->Right;
}
else if (NULL != T->Left) { // 无后继再找前驱
key = FindPre(T);
T->Key = key; // 将 T的后继节点值赋值给 T ,到时候再删后继节点即可
P = T;
T = T->Left;
}
}
}
return false;
}
递归遍历:
// 前序遍历
void BSTree::PreOrder(BSNode *node) {
if (NULL == node) {
return;
}
cout << node->Key << " ";
PreOrder(node->Left);
PreOrder(node->Right);
}
// 中序
void BSTree::InOrder(BSNode* node) {
if (NULL == node) {
return;
}
InOrder(node->Left);
cout << node->Key << " ";
InOrder(node->Right);
}
// 后序
void BSTree::PosOrder(BSNode* node) {
if (NULL == node) {
return;
}
PosOrder(node->Left);
PosOrder(node->Right);
cout << node->Key << " ";
}
// 层次遍历
void BSTree::LevelOrder() {
if (NULL == Root) {
return;
}
queue<BSNode*> NODE;
NODE.push(Root);
BSNode* T = Root;
while (!NODE.empty()) {
T = NODE.front();
NODE.pop();
cout << T->Key << " ";
if (T->Left) NODE.push(T->Left);
if (T->Right) NODE.push(T->Right);
}
cout << endl;
}
非递归遍历:
前序:先根 后左 再右
// 前序 (非递归)
void PreOrder(BSTree &Tree) {
if (NULL == Tree.Root) {
return;
}
stack<BSNode*> NODE;
NODE.push(Tree.Root);
BSNode* T = Tree.Root;
while (!NODE.empty()) {
T = NODE.top();
NODE.pop(); // 会先把左节点的全部出栈
cout << T->Key << " ";
// 先入右节点 再入左节点
if (T->Right) NODE.push(T->Right);
if (T->Left) NODE.push(T->Left);
}
}
中序:先左 后根 再右
需要先访问最左边的节点(左子树节点持续入栈),再出栈判断是否有右子树,若有右子树,将右子树看成一个小的二叉查找树,同样方法入栈出栈。
// 中序 (非递归)
void InOrder(BSTree &Tree) {
if (NULL == Tree.Root) {
return;
}
stack<BSNode*> NODE;
NODE.push(Tree.Root);
BSNode* T = Tree.Root;
while (!NODE.empty()) {
while (T&&T->Left) {
if (T->Left) NODE.push(T->Left);
T = T->Left;
}
T = NODE.top();
NODE.pop();
cout << T->Key << " ";
if (T->Right) { // 该节点有右子树
NODE.push(T->Right);
T = T->Right; // 做根入栈
}
else {
T = NULL; // 防止重复将左孩子入栈
}
}
}
后序:先左 后右 再根
// 后序 (非递归)
void PosOrder(BSTree &Tree) {
if (NULL == Tree.Root) {
return;
}
stack<BSNode*> NODE;
NODE.push(Tree.Root);
BSNode* T = Tree.Root;
BSNode* pT = NULL; // 记录上一个输出的节点
while (!NODE.empty()) {
T = NODE.top();
if (T->Left == NULL && T->Right == NULL || // 叶子处
(pT != NULL && (pT == T->Left || pT == T->Right))) {
// 先遍历左子树 当 pT == T->Right为真时 默认左子树不存在或已遍历
cout << T->Key << " ";
NODE.pop();
pT = T;
}
else {
// 先右后左
if (T->Right) NODE.push(T->Right);
if (T->Left) NODE.push(T->Left);
}
}
}
小结:非递归遍历需要多熟悉。