参考算法导论第12章
//头文件bintree.h
//定义了binnode,bintree类
#pragma once #define NUM_NODE 7 #include<iostream> #include<stack> #include<ctime> #include<assert.h> class binnode { public: int key; char value; binnode *left, *right,*parent; bool beVisited; //用于中序遍历的指针回溯版本 bool bePushed; //用于中序遍历的 binnode(){} binnode(int k, char v) :key(k), value(v) { left = right = parent = nullptr; beVisited = false; bePushed = false; } binnode(const binnode& bn) { key = bn.key; value = bn.value; left = right = parent = nullptr; beVisited = false; bePushed = false; } }; class bintree { public: bintree(); ~bintree() { remove(root); } bool insert(const binnode& bn); void menu(); //主菜单 binnode * search(int k); //查询关键值为k的节点,若存在返回指向节点的指针,不存在返回nullptr binnode * min(binnode * p); //返回指向一指针p指向的节点为根节点的二叉树的关键值最小的节点的指针,不存在返回nullptr binnode * max(binnode * p); binnode * successor(binnode * bn); //返回bn指向的节点的在中序后继,不存在返回nullptr binnode * presuccessor(binnode *bn); //返回bn指向的节点的中序前驱,不存在返回nullptr binnode * getroot() { return root; } void inorder(); void postorder(); void preorder(); binnode * del(int k); //在二叉树中删除关键值为k的节点,并返回指向该节点的指针,若删除失败返回nullptr); protected: void remove(binnode * bn); void inorder(binnode * bn); //递归前序遍历 void _inorder(); //非递归前序遍历 void __inorder(binnode * bn); void postorder(binnode * bn); void _postorder(); void preorder(binnode * bn); void _preorder(); void __preorder(binnode * bn); void visit(binnode *bn); private: binnode *root; binnode *NIL; };
//inorder.cpp
//中序遍历的递归和非递归实现
#include"bintree.h" void bintree::inorder() { int select; std::cout << "1.递归中序遍历. \t2.非递归中序遍历.\t 3.非递归中序遍历2 \t 4.返回主菜单\n"; std::cin >> select; while (select != 1 && select != 2 && select != 3 && select != 4) { std::cout << "输入错误,请重新输入!" << std::endl; std::cin >> select; } switch (select) { case 1:inorder(root); std::cout << std::endl; inorder(); break; case 2:_inorder(); std::cout << std::endl; inorder(); break; case 3:__inorder(root); std::cout << std::endl; inorder(); break; case 4:menu(); break; } } void bintree::inorder(binnode * bn) { //递归中序遍历 if (bn != nullptr) { inorder(bn->left); visit(bn); inorder(bn->right); } } /* // 中序遍历伪代码:非递归版本,用栈实现,版本1 void InOrder1(TNode* root) { Stack S; while ( root != NULL || !S.empty() ) { while( root != NULL ) // 左子树入栈 { S.push(root); root = root->left; } if ( !S.empty() ) { root = S.pop(); Visit(root->data); // 访问根结点 root = root->right; // 通过下一次循环实现右子树遍历 } } } */ void bintree::_inorder() { //非递归中序遍历 std::stack<binnode*> s; binnode *p = root; while (p != NULL || !s.empty()) //循环结束条件:当节点为空且栈为空结束循环 { while (p != NULL) //遍历左子树并进栈,直到左子树为空 { s.push(p); p = p->left; } if (!s.empty()) //若栈不为空则出栈,打印并进入节点的右子树 { p = s.top(); visit(p); s.pop(); p = p->right; } } } /* // 中序遍历伪代码:非递归版本,不用栈,增加指向父节点的指针 void InOrder3(TNode* root) { while ( root != NULL ) // 回溯到根节点时为NULL,退出 { while ( root->left != NULL && !root->left->bVisited ) { // 沿左子树向下搜索当前子树尚未访问的最左节点 root = root->left; } if ( !root->bVisited ) { // 访问尚未访问的最左节点 Visit(root); root->bVisited=true; } if ( root->right != NULL && !root->right->bVisited ) { // 遍历当前节点的右子树 root = root->right; } else { // 回溯至父节点 root = root->parent; } } } */ void bintree::__inorder(binnode * bn) { binnode * p = bn; while (p != nullptr) { while (p->left != nullptr && !p->left->beVisited) { p = p->left; } if (!p->beVisited) { visit(p); p->beVisited = true; } if (p->right != nullptr && !p->right->beVisited) { p = p->right; } else { p = p->parent; } } } /* // 中序遍历伪代码:非递归版本,用栈实现,版本2 void InOrder2(TNode* root) { Stack S; if( root != NULL ) { S.push(root); } while ( !S.empty() ) { TNode* node = S.pop(); if ( node->bPushed ) { // 如果标识位为true,则表示其左右子树都已经入栈,那么现在就需要访问该节点了 Visit(node); } else { // 左右子树尚未入栈,则依次将 右节点,根节点,左节点 入栈 if ( node->right != NULL ) { node->right->bPushed = false; // 左右子树均设置为false S.push(node->right); } node->bPushed = true; // 根节点标志位为true S.push(node); if ( node->left != NULL ) { node->left->bPushed = false; S.push(node->left); } } } } */
//preorder.cpp
//前序遍历的递归和非递归实现
#include"bintree.h" void bintree::preorder() { int select; binnode * p = root; std::cout << "1.递归前序遍历. \t2.非递归前序遍历.\t 3.非递归遍历2. \t 4.返回主菜单\n"; std::cin >> select; while (select != 1 && select != 2 && select != 3 && select != 4) { std::cout << "输入错误,请重新输入!" << std::endl; std::cin >> select; } switch (select) { case 1:preorder(p); std::cout << std::endl; preorder(); break; case 2:_preorder(); std::cout << std::endl; preorder(); break; case 3:__preorder(root); break; case 4:menu(); break; } } void bintree::preorder(binnode * bn) { if (bn == nullptr)return; std::cout << bn->value << " "; preorder(bn->left); preorder(bn->right); } void bintree::_preorder() { binnode * p = root; std::stack<binnode*> s; p = root; assert(s.empty()); while (p != nullptr || !s.empty()) { if (p != nullptr) { visit(p); s.push(p); p = p->left; } else { p = s.top(); s.pop(); p = p->right; } } } void bintree::__preorder(binnode * bn) { binnode * p = bn; std::stack<binnode*> s; s.push(p); while (!s.empty()) { p = s.top(); s.pop(); if (p != nullptr) { //入栈的时候可能有空指针,只有非空指针才能进行操作 visit(p); s.push(p->right); s.push(p->left); } } } /* // 先序遍历伪代码:非递归版本,用栈实现,版本1 void preOrder1(TNode* root) { Stack S; while ((root != NULL) || !S.empty()) { if (root != NULL) { Visit(root); S.push(root); // 先序就体现在这里了,先访问,再入栈 root = root->left; // 依次访问左子树 } else { root = S.pop(); // 回溯至父亲节点 root = root->right; } } } */ /* // 先序遍历伪代码:非递归版本,用栈实现,版本2 void preOrder2(TNode* root) { if ( root != NULL) { Stack S; S.push(root); while (!S.empty()) { TNode* node = S.pop(); Visit(node); // 先访问根节点,然后根节点就无需入栈了 S.push(node->right); // 先push的是右节点,再是左节点 S.push(node->left); } } } */
//postorder.cpp
//后序遍历的递归和非递归实现
#include"bintree.h" void bintree::postorder() { int select; std::cout << "1.递归后序遍历. \t2.非递归后序遍历.\t 3.返回主菜单\n"; std::cin >> select; while (select != 1 && select != 2 && select != 3) { std::cout << "输入错误,请重新输入!" << std::endl; std::cin >> select; } switch (select) { case 1:postorder(root); postorder(); break; case 2:_postorder(); postorder(); break; case 3:menu(); break; } } void bintree::postorder(binnode * bn) { //递归后序遍历 if (bn != nullptr) { postorder(bn->left); postorder(bn->right); std::cout << bn->value << " "; } } /* // 后序遍历伪代码:非递归版本,用栈实现 void PostOrder(TNode* root) { Stack S; if( root != NULL ) { S.push(root); } while ( !S.empty() ) { TNode* node = S.pop(); if ( node->bPushed ) { // 如果标识位为true,则表示其左右子树都已经入栈,那么现在就需要访问该节点了 Visit(node); } else { node->bPushed = true; // 根节点标志位为true S.push(node); // 左右子树尚未入栈,则依次将 右节点,左节点,根节点 入栈 if ( node->right != NULL ) { node->right->bPushed = false; // 左右子树均设置为false S.push(node->right); } if ( node->left != NULL ) { node->left->bPushed = false; S.push(node->left); } } } } */ void bintree::_postorder() { std::stack<binnode*> s; binnode *p = root; if (p != nullptr) { s.push(p); } while (!s.empty()) { p = s.top(); s.pop(); if (p->bePushed) { visit(p); } else { p->bePushed = true; s.push(p); if (p->right != nullptr) { s.push(p->right); p->right->bePushed = false; } if (p->left != nullptr) { s.push(p->left); p->left->bePushed = false; } } } }
//search.cpp
//搜索函数的实现
#include"bintree.h" binnode * bintree::search(int k) { binnode * p = root; while (p != nullptr && p->key != k) { if (k <= p->key) p = p->left; else p = p->right; } return p; }
//successor.cpp
//寻找当前节点的中序前驱和中序后继的实现
#include"bintree.h" binnode * bintree::successor(binnode * bn) { if (bn->right != nullptr) { //若右子女不为空,则右子树的最左子树就是当前节点的后继 return min(bn->right); } binnode * p = bn->parent; while (p != nullptr && bn == p->right) { //若右子女为空,则向上查找,直到遇到第一个父节点是左子女的节点 bn = p; p = p->parent; } return p; } binnode * bintree::presuccessor(binnode * bn) { if (bn->left != nullptr) { return max(bn->left); } binnode * p = bn->parent; while (p != nullptr && bn == p->left) { bn = p; p = p->parent; } }
//delete.cpp
//删除关键值为k的节点的实现
#include"bintree.h" binnode * bintree::del(int k) { binnode * p = search(k); binnode * del = nullptr, *del_child = nullptr; if (p == nullptr) return nullptr; /* 删除节点的节点可能有无子女,只有一个子女,有两个子女三种情况 */ if (p->left == nullptr || p->right == nullptr) { //无子女或者只有一个子女,直接删除 del = p; } else { //有一对子女,先删除要删除的节点的中序后继, del = successor(p); //再将中序后继的内容复制到当前节点 } if (del->left != nullptr) { //del_child指向要删除的节点的子女,若有非空子女则指向非空子女,否则指向空 del_child = del->left; } else { del_child = del->right; } if (del_child != nullptr) { //若子女非空,就给子女的值域赋值,因为若子女为空就没必要了 del_child->parent = del->parent; } if (del->parent == nullptr) { //若要删除的节点的父节点为空,就没必要设置父节点的左右子女了 root = del_child; //此时要删除的节点是根节点,删除之后del_child变为新的根节点 } else { //若要删除的节点的父节点不为空,设置父节点的值域 if (del->parent->left == del) { //判断要删除的节点是其父节点的左子女还是右子女,类似于链表删除 del->parent->left = del_child; } else { del->parent->right = del_child; } } //删除操作完成,接下来判断是删除的哪一种情况 //若是有一个子女或没有子女的情况,删除就已经结束了 //若是有两个子女的情况,删除的是要删除节点的中序后继 //删除完成之后还要复制节点的内容到要删除的节点 if (del != p) { p->key = del->key; //只修改非指针域的内容,因为指针域的删除操作已经完成 p->value = del->value; } return del; }
//min_max.cpp
//寻找当前节点为根节点的树中的最大最小值的实现
#include"bintree.h" binnode * bintree::min(binnode * p) { while (p != nullptr && p->left != nullptr) { p = p->left; } return p; } binnode * bintree::max(binnode * p) { while (p != nullptr && p->right != nullptr) { p = p->right; } return p; }
//bintree.cpp
//测试文件
#include"bintree.h" bintree::bintree() { root = nullptr; NIL = nullptr; } bool bintree::insert(const binnode& bn) { binnode *tmp = root; //指向插入位置的指针 binnode *parent_tmp = nullptr; //插入位置的父节点 while (tmp != NIL) { parent_tmp = tmp; //先赋值父节点 if (bn.key <= tmp->key) { tmp = tmp->left; //指针指向子节点 } else tmp = tmp->right; } tmp = new binnode(bn); //产生插入的节点 if (tmp == nullptr) { std::cout << "allocated error!.\n"; return false; } tmp->parent = parent_tmp; //赋值子节点的父指针 if (tmp->parent == NIL) { //若父节点为空,则当前插入的节点是根节点 root = tmp; //赋值根节点 return true; } if (tmp->key <= tmp->parent->key) { //判断插入的位置是父节点的左子女还是右子女 tmp->parent->left = tmp; } else tmp->parent->right = tmp; return true; } void bintree::visit(binnode *bn) { std::cout << bn->value << " "; /* if (bn->parent != nullptr) { std::cout << bn->value << "'s parent is " << bn->parent->value << " "; }*/ } void bintree::menu() { int select; std::cout << "1.前序遍历. \t 2.中序遍历. \t 3.后序遍历. \t 4.结束遍历\n"; std::cin >> select; while (select != 1 && select != 2 && select != 3 && select != 4) { std::cout << "输入错误,请重新输入!"; std::cin >> select; } switch (select) { case 1:preorder(); break; case 2:inorder(); break; case 3:postorder(); break; case 4:return; break; default: break; } } void bintree :: remove(binnode * bn) { if (bn != nullptr) { remove(bn->left); remove(bn->right); std::cout << "删除了节点" << bn->value << " " << std::endl; delete bn; } } int main() { bintree bt; int key[NUM_NODE] = {4,2,3,1,5,6,7}; char value[NUM_NODE] = {'A','B','C','D','E','F','G'}; binnode bn[NUM_NODE]; /*创建二叉查找树*/ for (int i = 0; i < NUM_NODE; ++i) { bn[i].key = key[i]; bn[i].value = value[i]; bn[i].left = bn[i].right = bn[i].parent = nullptr; bn[i].beVisited = false; bn[i].bePushed = false; } for (int i = 0; i < NUM_NODE; ++i) { std::cout << bn[i].value << " "; } std::cout << std::endl; for (int i = 0; i < NUM_NODE; ++i) { bt.insert(bn[i]); } /*测试遍历*/ //bt.menu(); if (bt.search(key[3])) { std::cout << "查找成功:" << bt.search(key[3])->value << " "; } std::cout << "min:" << bt.min(bt.getroot())->value << std::endl; std::cout << "max:" << bt.max(bt.getroot())->value << std::endl; std::cout << "中序序列:" << std::endl; bt.inorder(); std::cout << bt.search(key[3])->value << "的中序后继是" << bt.successor(bt.search(key[3]))->value << std::endl; std::cout << bt.search(key[4])->value << "的中序前驱是" << bt.presuccessor(bt.search(key[4]))->value << std::endl; binnode * del_flag = bt.del(key[0]); if (del_flag != nullptr) bt.inorder(); return 0; }