手把手教你写二叉查找树Binary Search Tree(1)

来源:互联网 发布:人工智能教学百度云 编辑:程序博客网 时间:2024/05/21 07:12

参考资料:《数据结构与算法分析》(第三版英文版)

书本题目:5.15

其实是做作业的时候顺便复习一下二叉查找树,顺便把自己写代码时的过程记录下来。虽然代码可能比较丑,但应该对于新手而言是比较友好的,可以了解如何一步一步实现BST的函数的。同时更深入理解一下返回值为Node*类型的Help函数。

说明:BST为Binary Search Tree,二叉查找树.Node为节点,即二叉查找树的节点。代码加粗部分为每次新增的代码

首先建立Node节点,每个节点只有1个整数类型的public数据成员

#pragma once#include <iostream>using namespace std;class Node {public:int x;Node* left;Node* right;Node(int val, Node* l = NULL, Node* r = NULL) {x = val;left = l;right = r;}~Node() {};};


随后建立BST类,里面只有一个数据成员根节点root,为Node*类型。

1。初始化

我们首先要实现构造函数和析构函数。

构造函数其实就是将root指向新new出来的Node对象。

析构函数中借用了一个clearHelp()函数,其参数为任意BST)的将被删除一个根节点rt(因为这样才能实现递归)。使用递归从左子树遍历到右子树,当发现某一节点的左右子树均为空的时候,删除该节点。随后逆流而上,向上删除。

#pragma once#include "Node.h"class BST{public:Node* root;BST(int val) {root = new Node(val, NULL, NULL);}~BST() {clearHelp(root);}void clearHelp(Node* rt) {if (rt == NULL) return;clearHelp(rt->left);clearHelp(rt->right);delete rt;}};


2.。增

实现插入函数insert();

首先,在Node类里面分别实现设置左节点和右节点的setleft()和setRight()函数

///Node 类
#pragma once#include <iostream>using namespace std;class Node {public:int x;Node* left;Node* right;Node(int val, Node* l = NULL, Node* r = NULL) {x = val;left = l;right = r;}~Node() {};void setLeft(Node* l) {left = l;}void setRight(Node* r) {right = r;}};
随后在BST类里面在InsertHelp(Node* ,int)函数的帮助下完成insert(int)函数.。原理(递归):从根节点出发,首先检测该节点是否为空,为空则返回一个新创建的节点。若不为空,则将要被插入的值val与当前按节点的值x比较,当val小于x时,向左继续往下走,否则向右继续往下走,进行新一轮检测。在新一轮检测中,把当前根节点的rt的左孩子rt->left作为新的根节点再次调用

insertHelp里面有3个重要的地方值得关注。

第一个是nsertHelp的返回类型是Node*  类型。

第二个是当前根节点不为空的setLeft()。这个是为了保证插入val之后维护好BST的用的。这要自己慢慢体会。

第三个是节点为空NULL时的返回

#pragma once#include "Node.h"class BST{public:Node* root;BST(int val) {root = new Node(val, NULL, NULL);}~BST() {clearHelp(root);}void clearHelp(Node* rt) {if (rt == NULL) return;clearHelp(rt->left);clearHelp(rt->right);delete rt;}void insert(int val){insertHelp(root, val);}Node* insertHelp(Node* rt, int val) {if (root == NULL)return new Node(val, NULL, NULL);if (val < rt->x){rt->setLeft(insertHelp(rt->left, val));}else{rt->setRight(insertHelp(rt->right, val));}}};

3。删

删除整个树的最小值,先用一根指针指向含有最小值的节点,再将这个节点的父节点的左指针指向这个节点的右孩子,而不在意这个节点的右孩子是否为空。

同样注意递归,setLeft(),以及Help返回类型为Node*这三个要点。

#pragma once#include "Node.h"class BST{public:Node* root;BST(int val) {root = new Node(val, NULL, NULL);}~BST() {clearHelp(root);}void clearHelp(Node* rt) {if (rt == NULL) return;clearHelp(rt->left);clearHelp(rt->right);delete rt;}void insert(int val){insertHelp(root, val);}Node* insertHelp(Node* rt, int val) {if (root == NULL)return new Node(val, NULL, NULL);if (val < rt->x){rt->setLeft(insertHelp(rt->left, val));}else{rt->setRight(insertHelp(rt->right, val));}}Node* findMin(Node* rt) {if (rt->left==NULL) return rt;elsereturn findMin(rt->left);}Node* deleteMin(Node* rt) {if (rt->left == NULL)return rt->right;else {rt->setLeft(deleteMin(rt->left));return rt;}}void deleteMin(){Node *temp = findMin(root);root = deleteMin(root);delete temp;}};

删除带有特定值val的节点

同样注意递归,setLeft(),以及返回类型为Node*这三个要点。

#pragma once#include "Node.h"class BST{public:Node* root;BST(int val) {root = new Node(val, NULL, NULL);}~BST() {clearHelp(root);}void clearHelp(Node* rt) {if (rt == NULL) return;clearHelp(rt->left);clearHelp(rt->right);delete rt;}void insert(int val){insertHelp(root, val);}Node* insertHelp(Node* rt, int val) {if (root == NULL)return new Node(val, NULL, NULL);if (val < rt->x){rt->setLeft(insertHelp(rt->left, val));}else{rt->setRight(insertHelp(rt->right, val));}}Node* findMin(Node* rt) {if (rt->left==NULL) return rt;elsereturn findMin(rt->left);}Node* deleteMin(Node* rt) {if (rt->left == NULL)return rt->right;else {rt->setLeft(deleteMin(rt->left));return rt;}}void deleteMin(){Node *temp = findMin(root);root = deleteMin(root);delete temp;}Node* removeHelp(Node* rt, int val){if (rt == NULL) return NULL; if (val < rt->x) rt->setLeft(removeHelp(rt->left, val)); if (val > rt->x) rt->setRight(removeHelp(rt->right, val));else {Node* temp = rt;if (rt->left == NULL) {rt = rt->right;delete temp;}else if (rt->right == NULL) {rt = rt->left;delete temp;}else  //左右节点均为空或者左右节点均不为空{Node* temp = findMin(rt->right);  //找到右子树最小值rt->x = temp->x;            //将右子树的最小值赋给rt值rt->setRight(deleteMin(rt->right));  // 将rt的右子树设为删除最小值后的新右子数delete temp;}}return rt;}void remove(int val){root = removeHelp(root, val);}};

4。查

查找是否含有特定值val的节点,有则返回true,否则返回false.

#pragma once#include "Node.h"class BST{public:Node* root;BST(int val) {root = new Node(val, NULL, NULL);}~BST() {clearHelp(root);}void clearHelp(Node* rt) {if (rt == NULL) return;clearHelp(rt->left);clearHelp(rt->right);delete rt;}void insert(int val){insertHelp(root, val);}Node* insertHelp(Node* rt, int val) {if (root == NULL)return new Node(val, NULL, NULL);if (val < rt->x){rt->setLeft(insertHelp(rt->left, val));}else{rt->setRight(insertHelp(rt->right, val));}}Node* findMin(Node* rt) {if (rt->left==NULL) return rt;elsereturn findMin(rt->left);}Node* deleteMin(Node* rt) {if (rt->left == NULL)return rt->right;else {rt->setLeft(deleteMin(rt->left));return rt;}}void deleteMin(){Node *temp = findMin(root);root = deleteMin(root);delete temp;}Node* removeHelp(Node* rt, int val){if (rt == NULL) return NULL;if (val < rt->x)   rt->setLeft(removeHelp(rt->left, val));if (val > rt->x) rt->setRight(removeHelp(rt->right, val));else {Node* temp = rt;if (rt->left == NULL) {rt = rt->right;delete temp;}else if (rt->right == NULL) {rt = rt->left;delete temp;}else{Node* temp = findMin(rt->right);rt->x = temp->x;rt->setRight(deleteMin(rt->right));delete temp;}}return rt;}void remove(int val){root = removeHelp(root, val);}Node* findHelp(Node* rt, int val){if (rt == NULL) return NULL;else if (val < rt->x) return findHelp(rt->left, val);else if (val > rt->x) return findHelp(rt->right, val);else return rt;}bool is_Exist(int val) {if (findHelp(root, val) == NULL) return false;else return true;}};

5。改,其实到这里大家应该都知道怎么写了,在findHelp函数的帮助下找到要被替换的值,对其进行修改。若找不到,则插入新值。

6。前序遍历,中序遍历,后序遍历  (其实是以 根节点的位置来命名这三种遍历的),下面看代码

//前序遍历 根->左->右void preorderTraverseHelp(Node* rt) {if (rt == NULL) return ;//else activity(rt);  当前节点不为空的话,对当前节点进行操作,这个操作是任意的, cout << rt->x<<endl; // 如对当前节点的值进行输出。preorderTraverseHelp(rt->left);preorderTraverseHelp(rt->right);}//实现函数封装void preorderTraverse() { preorderTraverseHelp(root);}//中序遍历  左->根->右void inorderTraverseHelp(Node* rt) {if (rt == NULL) return; inorderTraverseHelp(rt->left); cout << rt->x << endl; inorderTraverseHelp(rt->right);}void inorderTraver() {inorderTraverseHelp(root);}//后序遍历  左->右->根void postorderTraverseHelp(Node* rt){if (rt == NULL) return;postorderTraverseHelp(rt->left);postorderTraverseHelp(rt->right);cout << rt->x << endl;}void postorderTraverse(){postorderTraverseHelp(root);}
7。做题。在main.cpp里面

#include "BST.h"int main() {BST* tree = new BST(15);tree->insert(20);tree->insert(25);tree->insert(18);tree->insert(16);tree->insert(5);tree->insert(7);cout << endl << "preorder:" <<endl;tree->preorderTraverse();cout << endl << endl << "inorder;"<<endl ;tree->inorderTraver();cout << endl << endl << "postorder:"<<endl ;tree->postorderTraverse();system("pause");}
运行结果



阅读全文
0 0
原创粉丝点击