二叉查找树

来源:互联网 发布:php开源项目 编辑:程序博客网 时间:2024/06/06 07:30

最近在看数据结构和算法(c语言描述),想着用c++自己实现一遍


节点类:

#ifndef __NODE_H__#define __NODE_H__#include <iostream>template<typename T> struct Node{T m_val;Node<T>* m_pl;Node<T>* m_pr;Node() : m_pl(nullptr), m_pr(nullptr){}Node(T value, Node<T>* __pl = nullptr, Node<T>* __pr = nullptr) : m_val(value), m_pl(__pl), m_pr(__pr){}void printType(){std::cout << typeid(T).name() << std::endl;}};#endif



查找树:

#ifndef __SEARCHTREE_H__#define __SEARCHTREE_H__#include "node.h"template<typename T> class SearchTree{public:SearchTree() : root(nullptr){}~SearchTree() {}//生成一棵空树,好像啥都没做void MakeEmpty();//查找树中元素Node<T>* Find(T value);//查找最小元素Node<T>* FindMin();//查找最大元素Node<T>* FindMax();Node<T>* Insert(T value);void PreTraversal();void MidTraversal();void BackTraversal();void Destroy();void Delete(T value);private:Node<T>* root;Node<T>* MakeEmpty(Node<T>* pnd);Node<T>* Find(Node<T>* pnd, T value);Node<T>* FindMin(Node<T>* pnd);Node<T>* Insert(Node<T>*& pnd, T value);void PreTraversal(Node<T>* pnd);void MidTraversal(Node<T>* pnd);void BackTraversal(Node<T>* pnd);void Destroy(Node<T>* pnd);void Delete(Node<T>*& pnd, T value);T DeleteMin(Node<T>*& pnd);};template<typename T> Node<T>* SearchTree<T>::MakeEmpty(Node<T>* pnd){if (pnd != nullptr){MakeEmpty(pnd->m_pl);MakeEmpty(pnd->m_pr);delete pnd;}return nullptr;}template<typename T> void SearchTree<T>::MakeEmpty(){if (root != nullptr){MakeEmpty(root);}root = nullptr;}template<typename T> Node<T>* SearchTree<T>::Find(Node<T>* pnd, T value){if (pnd == nullptr)return nullptr;if (value < pnd->m_val){return Find(pnd->m_pl, value);}else if (value > pnd->m_val){return Find(pnd->m_pr, value);}elsereturn pnd;}template<typename T> Node<T>* SearchTree<T>::Find(T value){return Find(root, value);}template<typename T> Node<T>* SearchTree<T>::FindMin(Node<T>* pnd){if (pnd == nullptr)return nullptr;else if (pnd->m_pl == nullptr)return pnd;elsereturn FindMin(pnd->m_pl);}template<typename T> Node<T>* SearchTree<T>::FindMin(){if (root == nullptr)return nullptr;return FindMin(root);}template<typename T> Node<T>* SearchTree<T>::FindMax(){if (root == nullptr)return nullptr;Node<T>* tmp = root;while (tmp->m_pr != nullptr){tmp = tmp->m_pr;}return tmp;}//插入的递归写法(此版本不允许插入两个相同的值)//template<typename T> Node<T>* SearchTree<T>::Insert(Node<T>*& pnd, T value)//{//if (pnd == nullptr)//{//pnd = new Node<T>(value);//}//else if (value < pnd->m_val)//{//return Insert(pnd->m_pl, value);//}//else if (value > pnd->m_val)//{//return Insert(pnd->m_pr, value);//}///*这样插入是不支持插入两个相同的值的*///return pnd;//}////template<typename T> Node<T>* SearchTree<T>::Insert(T value)//{//return Insert(root, value);//}//插入的非递归写法(此版本不允许插入两个相同的值)template<typename T> Node<T>* SearchTree<T>::Insert(T value){if (root == nullptr){root = new Node<T>(value);return root;}Node<T>* pre = nullptr;Node<T>* tmp = root;while (tmp != nullptr){pre = tmp;if (value < tmp->m_val){tmp = tmp->m_pl;}else if (value > tmp->m_val){tmp = tmp->m_pr;}}if (value < pre->m_val){pre->m_pl = new Node<T>(value);return pre->m_pl;}if (value > pre->m_val){pre->m_pr = new Node<T>(value);return pre->m_pr;}return nullptr;}template<typename T> void SearchTree<T>::PreTraversal(Node<T>* pnd){if (pnd == nullptr)return;std::cout << pnd->m_val << std::endl;PreTraversal(pnd->m_pl);PreTraversal(pnd->m_pr);}template<typename T> void SearchTree<T>::PreTraversal(){PreTraversal(root);}template<typename T> void SearchTree<T>::MidTraversal(Node<T>* pnd){if (pnd == nullptr)return;MidTraversal(pnd->m_pl);std::cout << pnd->m_val << std::endl;MidTraversal(pnd->m_pr);}template<typename T> void SearchTree<T>::MidTraversal(){MidTraversal(root);}template<typename T> void SearchTree<T>::BackTraversal(Node<T>* pnd){if (pnd == nullptr)return;BackTraversal(pnd->m_pl);BackTraversal(pnd->m_pr);std::cout << pnd->m_val << std::endl;}template<typename T> void SearchTree<T>::BackTraversal(){BackTraversal(root);}template<typename T> void SearchTree<T>::Destroy(Node<T>* pnd){if (pnd == nullptr)return;Destroy(pnd->m_pl);Destroy(pnd->m_pr);delete pnd;}template<typename T> void SearchTree<T>::Destroy(){Destroy(root);root = nullptr;}template<typename T> void SearchTree<T>::Delete(Node<T>*& pnd, T value)  //这里又犯了这个错误,因为下面要改变指向,所以肯定要传引用{if (pnd == nullptr)return;if (value < pnd->m_val){Delete(pnd->m_pl, value);}else if (value > pnd->m_val){Delete(pnd->m_pr, value);}else if (pnd->m_pl != nullptr && pnd->m_pr != nullptr) //如果有左子树和右子树,那么为了保持查找树特性,要找出右子树中的最小值{/*Node<T> *tmp = FindMin(pnd->m_pr); pnd->ch = tmp->ch;Delete(pnd->m_pr, tmp->ch);*/pnd->m_val = DeleteMin(pnd->m_pr);   //其实应该像书里所说的,实现一个DeleteMin,就可以不用像现在这样搜索两次,提高效率}else  //只有左子树或只有右子树{Node<T> *tmp = pnd;if (pnd->m_pl == nullptr){pnd = pnd->m_pr;}else if (pnd->m_pr == nullptr){pnd = pnd->m_pl;}delete tmp;}}template<typename T> void SearchTree<T>::Delete(T value){Delete(root, value);}//DeletMin专用于在删除节点时如果此节点有左右子节点的情况,为了保持二叉查找树的特性,要找出右子树中的最小节点替换当前节点,并将其删除//注意是引用,所以写法是对的,实际操作的是父节点的左指针或者右指针,上面好几个函数都是以指针引用的形式直接改变父节点左右指针的指向template<typename T> T SearchTree<T>::DeleteMin(Node<T>*& pnd) {//这里其实应该保证传入的pnd必须不为空,好在Delete函数中就保证了T value;memset(&value, 0, sizeof(value));if (pnd == nullptr)return value;//是最小的if (pnd->m_pl == nullptr){Node<T>* tmp = pnd;value = pnd->m_val;//if (pnd->m_pr != nullptr)pnd = pnd->m_pr; //不管怎么样,都等于右节点,m_pr是nullptr也是正确的delete tmp;tmp = nullptr;return value;}elsereturn DeleteMin(pnd->m_pl);}#endif




main函数:

int main(int argc, char* argv[]){//TestCreateTree();/*Node<int> no;no.printType();*/SearchTree<int> st;st.MakeEmpty();Node<int> *p = st.Insert(10);p = st.Insert(20);st.Insert(30);st.Insert(5);st.Insert(8);st.MidTraversal();st.Delete(30);cout << "******************************" << endl;st.MidTraversal();st.Destroy();system("pause");}