栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

二叉搜索树BST在C++类中的实现(增删改查)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

二叉搜索树BST在C++类中的实现(增删改查)

网上能够查到的数据结构相关资料,多是用C语言代码实现。
C语言是面向过程的,C++是面向对象的,尽管它们有诸多的相同之处,尽管把C语言实现BST的代码拷贝在C++中差不多就能pass了。但既然学习了C++,就尽可能使用面向对象的思想,将函数封装在类中,而不是在main函数外面写了一个又一个的函数。那样的话,即使是用了一些C++的语法,整个程序也可以说是标准的C语言式。

BST,Binary Search Tree,是一种很典型并且广泛使用的数据结构。它的特点是左边节点的数据值比该节点小,右边节点的数据值比该节点大。利用这一点,在AVL Tree(这是BST的升级版,以后再写)中可以实现O(log n)的查找效率。

在这边,BSTree类提供了插入节点、删除节点、搜索节点、判断空树,以及四中遍历方式等功能(修改?搜索出来就可以改了)
其中建树、添加节点、遍历等,需要注意的点都不多,唯独删除节点。

  1. 因为删除的节点只能是目标节点一个,而对其下的子树(若有),所有的节点必须保留。
  2. 而且删除目标节点之后,还需要保证该二叉树还是BST。
    至于删除目标节点,以及其下所有子孙节点的函数,实现起来比较简单。有需要的慕友可自行增加这一函数。

代码设计:

  1. 节点类。一些函数在节点类中比较容易实现,把这个任务交给它。还有一些辅助函数,删除节点函数所需要的,也在节点类中设计。
  2. 树类。提供建一颗空树、判空、根据数据增加节点、查找、删除的功能,以及前序、中序、后序、层序,四种遍历。
  3. 测试

BSTree类的头文件BSTree.h以及实现文件BSTree.cpp如下:

#pragma once
#include "Node.h"

class BSTree {
public:
    BSTree();//建一颗空树。
    bool isEmpty(); //判断树是否为空。
    void insertNode(ElemType &elem);    //传入元素值,插入一个节点
    bool deleteNode(ElemType &elem);    //删除给定元素值的节点。
    Node* searchNode(ElemType &elem);   //查找给定元素值的节点,返回其地址。

    void preOrderTaversal(); //前序、中序、后序以及层序遍历。
    void inOrderTaversal();
    void postOrderTaversal();
    void levelOrderTaversal();
private:
    Node *rootPtr;
};
#include "BSTree.h"
#include 

BSTree::BSTree() {
    this->rootPtr = NULL;
}

bool BSTree::isEmpty() {
    return NULL == rootPtr;
}

void BSTree::insertNode(ElemType &elem) {
    if (isEmpty())
 rootPtr = new Node(elem);
    //若树非空,插入一个新节点的操作在Node类中更容易实现,所以把这个任务交给Node类。
    else
 rootPtr->addNode(elem);
}

bool BSTree::deleteNode(ElemType &elem) {
    Node *objNode = searchNode(elem);
    if (NULL == objNode) return false;
    //树根节点的情况比较特殊,单独考虑。
    if (objNode == rootPtr && !(rootPtr->leftChild != NULL && rootPtr->rightChild != NULL)) {
 if (rootPtr->leftChild == NULL && rootPtr->rightChild == NULL) 
     rootPtr = NULL;
 else if (rootPtr->leftChild == NULL) {      //rootPtr->rightChild != NULL
     rootPtr = rootPtr->rightChild;
     rootPtr->parent = NULL;
 }
 else if (rootPtr->rightChild == NULL) {
     rootPtr = rootPtr->leftChild;
     rootPtr->parent = NULL;
 }
 delete objNode;
 //树根有两个子节点的情况可做一般性处理。
    }
    else
 objNode->eraseNode();

    return true;
}

Node* BSTree::searchNode(ElemType &elem) {
    if (isEmpty()) return NULL;
    //若树非空,搜索指定元素值的节点在Node类中也更容易实现,同样将这个任务交给Node类。
    return rootPtr->findNode(elem);
}

void BSTree::preOrderTaversal() {
    if (!isEmpty()) rootPtr->traversalByPreOrder();
}

void BSTree::inOrderTaversal() {
    if (!isEmpty()) rootPtr->traversalByInOrder();
}

void BSTree::postOrderTaversal() {
    if (!isEmpty()) rootPtr->traversalByPostOrder();
}

void BSTree::levelOrderTaversal() {
    if (!isEmpty()) rootPtr->traversalByLevelOrder();
}

Node类的头文件和实现文件如下:

#pragma once

typedef int ElemType;
class Node {
public:
    Node(ElemType data = 0);
    void addNode(ElemType &elem);   
    Node* findNode(ElemType &elem); //返回给定元素值的节点的地址,若找不到,返回NULL。
    Node* findMin(); //返回以此节点为根节点的树的元素值最小的节点。
    Node* findMax();
    
    void eraseNode();   

    void traversalByPreOrder();     //前序、中序、后序以及层序遍历以此节点为根节点的树。
    void traversalByInOrder();
    void traversalByPostOrder();
    void traversalByLevelOrder();
public:
    ElemType data;
    Node *parent;
    Node *leftChild;
    Node *rightChild;
};
#include "Node.h"
#include 
#include 
using namespace std;

Node::Node(ElemType data ) {
    this->data = data;
    parent = leftChild = rightChild = NULL;
}

void Node::addNode(ElemType &elem) {
    if (elem < data) {
 if (leftChild == NULL) {
     leftChild = new Node(elem);
     leftChild->parent = this;
 }
 else
     leftChild->addNode(elem);
    }
    else if (elem > data) {
 if (rightChild == NULL) {
     rightChild = new Node(elem);
     rightChild->parent = this;
 }
 else
     rightChild->addNode(elem);
    }
    //do nothing when 'elem == data'.
}

Node* Node::findNode(ElemType &elem) {
    if (elem == data) return this;
    else if (elem < data && leftChild != NULL)
 return leftChild->findNode(elem);
    else if (elem > data && rightChild != NULL)
 return rightChild->findNode(elem);
    return NULL;
}

Node* Node::findMin() {
    Node *tmp = this;
    while (tmp->leftChild != NULL)
 tmp = tmp->leftChild;
    return tmp;
}

Node* Node::findMax() {
    Node *tmp = this;
    while (tmp->rightChild != NULL)
 tmp = tmp->rightChild;
    return tmp;
}


void Node::eraseNode() {
    if (leftChild != NULL && rightChild != NULL) {
 Node *tmp = leftChild->findMax();
 data = tmp->data;
 tmp->eraseNode();
    }
    else {
 if (leftChild == NULL) {    //左孩子节点是NULL,有右孩子节点,或者没有子节点。
     if (this == parent->leftChild) 
  parent->leftChild = rightChild;
     else 
  parent->rightChild = rightChild;
     if (rightChild != NULL) rightChild->parent = parent;
 }
 else {  //有左孩子,右孩子为NULL
     if (this == parent->leftChild)
  parent->leftChild = leftChild;
     else
  parent->rightChild = leftChild;
     leftChild->parent = parent;
 }
    }
}

void Node::traversalByPreOrder() {
    cout << data << " ";
    if (leftChild != NULL)
 leftChild->traversalByPreOrder();
    if (rightChild != NULL)
 rightChild->traversalByPreOrder();
}

void Node::traversalByInOrder() {
    if (leftChild != NULL)
 leftChild->traversalByInOrder();
    cout << data << " ";
    if (rightChild != NULL)
 rightChild->traversalByInOrder();
}

void Node::traversalByPostOrder() {
    if (leftChild != NULL)
 leftChild->traversalByPostOrder();
    if (rightChild != NULL)
 rightChild->traversalByPostOrder();
    cout << data << " ";
}

void Node::traversalByLevelOrder() {
    queue que;
    que.push(this);
    while (!que.empty()) {
 Node *tmp = que.front();
 que.pop();
 cout << tmp->data << " ";
 if (tmp->leftChild != NULL)
     que.push(tmp->leftChild);
 if (tmp->rightChild != NULL)
     que.push(tmp->rightChild);
    }
}

测试文件如下:

#include "BSTree.h"
#include 
using namespace std;

int main(void) {
    BSTree *bst = new BSTree;
    cout << boolalpha << "空树?" << bst->isEmpty() << endl;
    int intArr[] = { 6, 5, 8, 4, 7, 9, 2, 1, 3 };
    for (int i = 0; i < sizeof(intArr) / sizeof(int); i++) {
 bst->insertNode(intArr[i]);
    }
    
    cout << boolalpha << "空树?" << bst->isEmpty() << endl;

    //测试 deleteNode() 函数
    int elem = 10;
    bst->deleteNode(elem);
    elem = 3;
    bst->deleteNode(elem);
    elem = 4;
    bst->deleteNode(elem);
    elem = 8;
    bst->deleteNode(elem);
    elem = 6;
    bst->deleteNode(elem);

    bst->preOrderTaversal();
    cout << "先序遍历" << endl;
    bst->inOrderTaversal();
    cout << "中序遍历" << endl;
    bst->postOrderTaversal();
    cout << "后序遍历" << endl;
    bst->levelOrderTaversal();
    cout << "层序遍历" << endl;

    delete bst;
    system("pause");
    return 0;
}

慕友也可将之修改成一个类模板,但要切记,许多编译器不支持类模板的头文件和实现文件分离,要把它们都放在头文件中。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/233059.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号