从0创建一棵2-3树

实现了2-3树结点的插入操作、结点删除操作和前中后序遍历2-3树代码

从0创建一棵2-3树完整代码

两个头文件:NODE.h 和 TREE.h
以及三个源文件

#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED
#include <string>

using namespace std;

class Node {

	friend class Tree;

private:
	string small;
	string large;

	Node* left;
	Node* middle;
	Node* right;
	Node* parent;

	Node();
	Node(const string&);
	bool isLeaf();
	bool isFull();
	bool hasKey(const string&);
	void insertKey(const string&);
};



#endif // NODE_H_INCLUDED

#ifndef TREE_H_INCLUDED
#define TREE_H_INCLUDED

#include "Node.h"

class Tree {
private:
    Node* root;

public:
    Tree();
    ~Tree();
    //Inserts a value into tree while following 2-3 tree properties
    void insert(const string&);
    //Prints tree in pre order
    void preOrder() const;
    //Prints tree in order
    void inOrder() const;
    //Prints tree in post order
    void postOrder() const;
    //Removes node from tree while following 2-3 tree properties
    void remove(const string&);
    //Returns true if key exists in any node in tree
    bool search(const string&) const;

    Node* getRoot();
    void adjust(Node*) const;

private:
    void destroyTree(Node*);//destructor helper
    bool searchNode(Node*, const string&) const;//search helper
    Node* searchDeleteNode(Node*, const string&) const;
    Node* splitNode(Node*, Node*, const string&);//insert helper

    Node* splitNode(Node*, Node*, Node*);//insert helper
    Node* insert(Node*, const string& key);//insert helper
    void insertChildren(Node*, const string&, Node*, Node*);//insert helper
    void insertChildren(Node*, Node*, Node*, Node*);//insert helper
    void insertLeaf(Node*, const string&);//insert helper
    void preOrderTraversal(Node*) const;
    void inOrderTraversal(Node*) const;
    void postOrderTraversal(Node*) const;
    Tree* operator=(Tree* rhs);//Assignment operator
    Tree(const Tree& rhs); // Copy Constructor
    void remove(Node*, const string&); //remove helper
    void remove(Node*);

    Node* getPre(Node*,const string& key);
    void inOrderTraversal2(Node* node) const;

};

#endif // TREE_H_INCLUDED

#include "Tree.h"
#include <iostream>

using namespace std;

void printOrders(Tree* tree) {
    cout << "Preorder = ";
    tree->preOrder();
    cout << "Inorder= ";
    tree->inOrder();
    cout << "Postorder = ";
    tree->postOrder();
}

int menu() {
    int choice = 0;
    cout << endl << "Enter menu choice: ";
    cout << endl;
    cout
        << "1. Insert" << endl
        << "2. Remove" << endl
        << "3. Print" << endl
        << "4. Search" << endl
        << "5. Quit" << endl;
    cin >> choice;

    // fix buffer just in case non-numeric choice entered
    // also gets rid of newline character
    cin.clear();
    cin.ignore(256, '\n');
    return choice;
}

int main() {

    Tree tree;

    int choice = menu();

    string entry;
    while (choice != 5) {
        if (choice == 1) {
            cout << "Enter movie title to insert: ";
            getline(cin, entry);
            cout << endl;

            tree.insert(entry);
            tree.adjust(tree.getRoot());

        }
        else if (choice == 2) {
            cout << "Enter movie title to remove: ";
            getline(cin, entry);
            cout << endl;

            tree.remove(entry);

            tree.adjust(tree.getRoot());

        }
        else if (choice == 3) {
            printOrders(&tree);

        }
        else if (choice == 4) {
            cout << "Enter movie title to search for: ";
            getline(cin, entry);
            cout << endl;

            if (tree.search(entry)) {
                cout << "Found" << endl;
            }
            else {
                cout << "Not Found" << endl;
            }
        }
        //fix buffer just in case non-numeric choice entered
        choice = menu();
    }

    return 0;
}

#include <iostream>
#include <string>
using namespace std;

#include "Node.h"

Node::Node() : small(""), large(""), left(nullptr), middle(nullptr), right(nullptr), parent(nullptr) {}

Node::Node(const string& value) : small(value), large(""), left(nullptr), middle(nullptr), right(nullptr), parent(nullptr) {}

bool Node::isLeaf() {
    return (left == nullptr && middle == nullptr && right == nullptr);
}

bool Node::isFull() {
    return (!small.empty() && !large.empty());
}

bool Node::hasKey(const string& key) {
    return (small == key || large == key);
}

void Node::insertKey(const string& key) {
    if (!isFull()) {
        if (small.empty()) {
            small = key;
        }
        else if (large.empty()) {
            large = key;
        }
    }
    if (small > large) {
        swap(small, large);
    }
}


#include <iostream>
#include <string>
#include <stdexcept>
#include<vector>
using namespace std;

#include "Tree.h"

string inorder[1000];

int i=0;
// Default constructor
Tree::Tree() {
    root = nullptr;
}

Tree::~Tree() {
    // Call a private helper function to delete all nodes recursively
    destroyTree(root);
}

//Wrapper function for searchNode
bool Tree::search(const string& value) const {
    return searchNode(root, value);
}

//Recursively searches through the tree to find matching value
bool Tree::searchNode(Node* node, const string& key) const {
    if (node == nullptr) {
        return false; //Empty tree or reaches the end of tree
    }

    if (node->small == key || node->large == key) {
        return true;
    }

    if (node->small.empty()) {
        //Should never happen so returns false
        return false;
    }

    //Recursively searches through the tree
    if (key < node->small) {
        return searchNode(node->left, key);
    }
    else if(!node->large.empty() && key>node->large){
        return searchNode(node->right, key);
    }
    else {
        return searchNode(node->middle, key);
    }
}

//Recursively searches through the tree to find matching value
Node* Tree::searchDeleteNode(Node* node, const string& key) const {
    if (node == nullptr) {
        return nullptr; //Empty tree or reaches the end of tree
    }

    if (node->small == key || node->large == key) {
        return node;
    }

    if (node->small.empty()) {
        //Should never happen so returns false
        return nullptr;
    }

    //Recursively searches through the tree
    if (key < node->small) {
        return searchDeleteNode(node->left, key);
    }
    else if(!node->large.empty() && key>node->large){
        return searchDeleteNode(node->right, key);
    }
    else {
        return searchDeleteNode(node->middle, key);
    }
}

//Helper that recursively frees all node in tree
void Tree::destroyTree(Node* node) {
    if (node != nullptr) {
        destroyTree(node->left);
        destroyTree(node->middle);
        destroyTree(node->right);
        delete node;
    }
}

//Wrapper for insertion
void Tree::insert(const string& key) {
    if (search(key)) {

        cout<<"exist......"<<endl;
        return; //Does not insert anything if there already exists node with key data in the tree
    }
    //Case 1: Inserting into empty tree
    if (root == nullptr) {
        root = new Node(key); //Simply makes a new node and set root to point to it
    }
    else {
        insert(root, key);
    }
}

//Insertion

Node* Tree::insert(Node* curr, const string& key) {
    if (search(key)) {
        return nullptr; //Does not insert if duplicate value found
    }
    //Premptively splits nodes if encountered while inserting
    if (curr->isFull() && curr->isLeaf()) {
        curr = splitNode(curr, curr->parent, new Node(key));
    }
    //Locating sutable leaf node for the insertion
    else if (!curr->isLeaf()) {
        if (key < curr->small) {
            return insert(curr->left, key);
        }
        else if (curr->large == "" || key < curr->large) {
            return insert(curr->middle, key);
        }
        else {
            return insert(curr->right, key);
        }
    }
    else {
        insertLeaf(curr, key);
        return curr;
    }
}

void Tree::insertLeaf(Node* curr, const string& key) {
    if (search(key)) {
        return;
    }
    else if (key < curr->small) {
        curr->large = curr->small;
        curr->small = key;
    }
    else if (key > curr->small) {
        curr->large = key;
    }

}
//Helper for splitting up nodes
Node* Tree::splitNode(Node* curr, Node* parent, Node* key) {

    if (!curr->isFull()) {
        return nullptr; //Does nothing if curr is not full hence no need to split
    }
    Node* splitLeft = nullptr;
    Node* splitRight = nullptr;
    Node* mid = nullptr;
    //记录下左中右
    Node* tmpl = curr->left;
    Node* tmpm = curr->middle;
    Node* tmpr = curr->right;
    string midStr;

    //插入最左边 中间给右边
    if (key->small < curr->small) {
        midStr = curr->small;
        splitLeft = key;
        splitRight = new Node(curr->large);
        splitRight->left = tmpm;
        splitRight->middle = tmpr;
        splitLeft->parent = parent;
        splitRight->parent = parent;
        if(key->left)
            key->left->parent = key;
        if(key->middle)
            key->middle->parent = key;
    }
    //插入中间 都要给
    else if (key->small > curr->small && key->small < curr->large) {
        midStr = key->small;
        splitLeft = new Node(curr->small);
        splitLeft->left = tmpl;
        splitLeft->middle = key->left;
        if(key->left)
            key->left->parent = splitLeft;
        splitRight = new Node(curr->large);
        splitRight->left = key->middle;
        if(key->middle)
            key->middle->parent = splitRight;
        splitRight->middle = curr->right;
        splitLeft->parent = parent;
        splitRight->parent = parent;
    }
    //插入最右边 给左边
    else {
        midStr = curr->large;
        splitLeft = new Node(curr->small);
        splitRight = key;
        splitLeft->left = tmpl;
        splitLeft->middle = tmpm;
        splitLeft->parent = parent;
        splitRight->parent = parent;
        if(key->left)
            key->left->parent = key;
        if(key->middle)
            key->middle->parent = key;

    }
    mid = new Node(midStr);
    mid->left = splitLeft;
    mid->middle = splitRight;
    delete curr;
    if (parent != nullptr) {
        insertChildren(parent, mid, splitLeft, splitRight);
    }
    else {
        parent = mid;
        parent->left = splitLeft;
        parent->middle = splitRight;
        root = parent;
        splitLeft->parent = root;
        splitRight->parent = root;
    }
    return parent;
}
//Handles insertion to a node with children that was split as well
void Tree::insertChildren(Node* parent, Node* son, Node* splitLeft, Node* splitRight) {
    Node* t;
    if(!parent->isFull()){
        if (son->small < parent->small) {
        parent->large = parent->small;
        parent->small = son->small;
        parent->left = son->left;
        parent->right = parent->middle;
        parent->middle = son->middle;
        son->left->parent = parent;
        son->middle->parent = parent;
    }
    else {
        parent->large = son->small;
        parent->left = parent->left;
        parent->right = son->middle;
        parent->middle = son->left;
        son->left->parent = parent;
        son->middle->parent = parent;
    }
    }else{
        t = splitNode(parent, parent->parent, son);
    }
}

//Wrapper for preOrder
void Tree::preOrder() const {
    preOrderTraversal(root);
    cout << endl;
}
//Standard pre order traversal
void Tree::preOrderTraversal(Node* node) const {
    if (node != nullptr) {
        cout << node->small << ", ";

        preOrderTraversal(node->left);

        if (!node->large.empty()) {
            cout << node->large << ", ";
        }
        preOrderTraversal(node->middle);

        preOrderTraversal(node->right);
    }
}
//Wrapper for postOrder
void Tree::postOrder() const {
    postOrderTraversal(root);
    cout << endl;
}
//Standard post order traversal
void Tree::postOrderTraversal(Node* node) const {
    if (node != nullptr) {
        postOrderTraversal(node->left);
        postOrderTraversal(node->middle);

        cout << node->small << ", ";

        postOrderTraversal(node->right);

        if (!node->large.empty()) {
            cout << node->large << ", ";
        }
    }
}
//Wrapper for in order
void Tree::inOrder() const {
    inOrderTraversal(root);
    cout << endl;
}
//Standard in order travsersal
void Tree::inOrderTraversal(Node* node) const {
    if (node != nullptr) {
        inOrderTraversal(node->left);

        cout << node->small << ", ";

        inOrderTraversal(node->middle);
        if (!node->large.empty()) {
            cout << node->large << ", ";
        }

        inOrderTraversal(node->right);

    }
}

//Remove implementation
void Tree::remove(const string& key) {

    Node* delNode=nullptr;
    if (!search(key)) {
        cout<<"not found"<<endl;
        return;
    }
    else{
        delNode = searchDeleteNode(root,key);
        if(delNode){
            remove(delNode, key);
        }
    }
}

void Tree::remove(Node* curr, const string& key) {
    //删除非叶节点
    //前驱替代
    if(!curr->isLeaf()){
    Node* pre = getPre(root,key);
    string prev;

    if(pre->isFull()){
        prev = pre->large;
        pre->large = key;
    }else{
        prev = pre->small;
        pre->small = key;
    }
    if(curr->small == key){
        curr->small = prev;
    }else{
        curr->large = prev;
    }
    remove(pre, key);
    }
    //删除叶节点
    else{
        //3节点直接删除
        if(curr->isFull()){
            if(key == curr->small){
                curr->small = curr->large;
                curr->large="";
            }else{
                curr->large="";
            }
        return;
        }
        //删除2节点
        else{

            //找兄弟借
            if(curr->parent->left->hasKey(key)&&curr->parent->middle->isFull()){

                curr->small = curr->parent->small;
                curr->parent->small = curr->parent->middle->small;
                curr->parent->middle->small = curr->parent->middle->large;
                curr->parent->middle->large = "";
            }
            else if(curr->parent->middle->hasKey(key)&&curr->parent->left->isFull()){
                curr->small = curr->parent->small;
                curr->parent->small = curr->parent->left->large;
                curr->parent->left->large = "";
            }
            else if(curr->parent->middle->hasKey(key)&&curr->parent->right->isFull()){
                curr->small = curr->parent->large;
                curr->parent->large = curr->parent->right->small;
                curr->parent->right->small = curr->parent->right->large;
                curr->parent->right->large = "";
            }
            else if(curr->parent->right && curr->parent->right->hasKey(key)&&curr->parent->middle->isFull()){
                curr->small = curr->parent->large;
                curr->parent->large = curr->parent->middle->large;
                curr->parent->middle->large = "";
            }
            //兄弟都是2节点,找父亲借
            else if(curr->parent->isFull()){
                if(curr->parent->left->hasKey(key)){
                    curr->parent->middle->large = curr->parent->middle->small;
                    curr->parent->middle->small = curr->parent->small;
                    curr->parent->small = curr->parent->large;
                    curr->parent->large = "";
                    curr->parent->left = curr->parent->middle;
                    curr->parent->middle = curr->parent->right;
                    curr->parent->right = nullptr;
                    delete curr;
                }
                else if(curr->parent->middle->hasKey(key)){
                    curr->parent->left->large = curr->parent->small;
                    curr->parent->middle->small = curr->parent->small;
                     curr->parent->small = curr->parent->large;
                    curr->parent->large = "";
                    curr->parent->middle = curr->parent->right;
                    curr->parent->right = nullptr;
                    delete curr;
                }
                else if(curr->parent->right->hasKey(key)){
                    curr->parent->middle->large = curr->parent->large;
                    curr->parent->large = "";
                    curr->parent->right = nullptr;
                    delete curr;
                }
            }
            //父兄都是2节点
            else{
                //删左边
                if(curr->parent->left->hasKey(key)){
                    curr->small = curr->parent->small;
                    curr->large = curr->parent->middle->small;
                    delete curr->parent->middle;
                    curr->parent->middle = nullptr;
                    remove(curr->parent);
                }
                //删右边
                if(curr->parent->middle->hasKey(key)){
                    curr->small = curr->parent->left->small;
                    curr->large = curr->parent->small;

                    curr->parent->left = curr;
                    curr->parent->right = nullptr;
                    remove(curr->parent);
                }
            }

            }

    }
}


//父兄均不可借的情况
void Tree::remove(Node* curr){
    if(curr==nullptr)
        return;
    if(!curr->parent){
        root = curr->left;
        return;
    }
    //父不可借
    if(!curr->parent->isFull()){
        //兄弟可借
        if(curr->parent->left == curr && curr->parent->middle->isFull()){
        curr->small = curr->parent->small;
        curr->parent->small = curr->parent->middle->small;
        curr->parent->middle->small = curr->parent->middle->large;
        curr->parent->middle->large = "";
        curr->middle = curr->parent->middle->left;
        curr->parent->middle->left = curr->parent->middle->middle;
        curr->parent->middle->middle = curr->parent->middle->right;
        curr->parent->middle->right = nullptr;
        if(curr->middle)
            curr->middle->parent = curr;
        }
        else if(curr->parent->middle == curr && curr->parent->left->isFull()){
            curr->small = curr->parent->small;
            curr->parent->small = curr->parent->left->large;
            curr->parent->left->large = "";
            curr->middle = curr->left;
            curr->left = curr->parent->left->right;
            curr->parent->left->right = nullptr;
        }
        //兄弟不可借
        else{
            //合并父和兄
            //在左边
            if(curr->parent->left == curr){
                curr->small = curr->parent->small;
                curr->large = curr->parent->middle->small;
                curr->middle = curr->parent->middle->left;
                curr->right = curr->parent->middle->middle;
                curr->parent->left = curr;

                if(curr->left)
                curr->left->parent = curr;
                if(curr->middle)
                curr->middle->parent = curr;
                if(curr->right)
                curr->right->parent = curr;

                delete curr->parent->middle;
                curr->parent->middle = nullptr;
                remove(curr->parent);
            }
            //在右边
            else if(curr->parent->middle == curr){
                curr->small = curr->parent->left->small;
                curr->large = curr->parent->small;
                curr->right = curr->left;
                curr->left = curr->parent->left->left;
                curr->middle = curr->parent->left->middle;

                //更改父母
                curr->left->parent = curr;
                curr->middle->parent = curr;
                curr->right->parent = curr;


                delete curr->parent->left;
                curr->parent->left = curr;
                curr->parent->middle = nullptr;
                remove(curr->parent);
            }
        }
    }

     //父可借
    else{
        //如果兄弟可借
        if(curr->parent->left == curr && curr->parent->middle->isFull()){
            curr->small = curr->parent->small;
            curr->parent->small = curr->parent->middle->small;

            curr->middle = curr->parent->middle->left;
            //更改父母
            curr->middle->parent = curr;
            curr->parent->middle->small = curr->parent->middle->large;
            curr->parent->middle->large = "";
            curr->parent->middle->left = curr->parent->middle->middle;
            curr->parent->middle->middle = curr->parent->middle->right;
            curr->parent->middle->right = nullptr;
        }
        else if(curr->parent->middle == curr && curr->parent->left->isFull()){
            curr->small = curr->parent->small;
            curr->parent->small = curr->parent->left->large;

            curr->middle = curr->left;
            curr->left = curr->parent->left->right;
            //更改父母
            curr->left->parent = curr;

            curr->parent->left->large = "";
            curr->parent->left->right = nullptr;
        }
        else if(curr->parent->middle == curr && curr->parent->right->isFull()){
            curr->small = curr->parent->large;
            curr->parent->large = curr->parent->right->small;

            curr->middle = curr->parent->right->left;
            //更改父母
            curr->middle->parent = curr;

            curr->parent->right->left = curr->parent->right->middle;
            curr->parent->right->middle = curr->parent->right->right;

            curr->parent->right->small= curr->parent->right->large;
            curr->parent->right->large = "";
            curr->parent->right->right = nullptr;

        }
        else if(curr->parent->right == curr && curr->parent->middle->isFull()){
            curr->small = curr->parent->large;
            curr->parent->large = curr->parent->middle->large;

            curr->middle = curr->left;
            curr->left = curr->parent->middle->right;

            //更改父母
            curr->left->parent = curr;

            curr->parent->middle->large = "";
            curr->parent->middle->right = nullptr;


        }
        //兄弟不可借
        else{
            if(curr->parent->left == curr){
                curr->small = curr->parent->small;
                curr->large = curr->parent->middle->small;

                curr->middle = curr->parent->middle->left;
                curr->right = curr->parent->middle->middle;
                //更改父母
                curr->middle->parent = curr;
                curr->right->parent = curr;

                curr->parent->small = curr->parent->large;
                curr->parent->large = "";

                delete curr->parent->middle;
                curr->parent->middle = curr->parent->right;
                curr->parent->right = nullptr;
            }
            else if(curr->parent->middle == curr){
                curr->large = curr->parent->small;
                curr->small = curr->parent->left->small;

                curr->right = curr->left;
                curr->middle = curr->parent->left->middle;//
                curr->left = curr->parent->left->left;//

                //更改父母
                curr->middle->parent = curr;
                curr->left->parent = curr;

                curr->parent->small = curr->parent->large;
                curr->parent->large = "";

                curr->parent->middle = curr->parent->right;
                delete curr->parent->left;
                curr->parent->left = curr;
                curr->parent->right = nullptr;
            }
            else{
                curr->large = curr->parent->large;
                curr->small = curr->parent->middle->small;

                curr->right = curr->left;
                curr->middle = curr->parent->middle->middle;//
                curr->left = curr->parent->middle->left;//
                //更改父母
               curr->middle->parent = curr;
               curr->left->parent = curr;

                delete curr->parent->middle;
                curr->parent->middle = curr;
                curr->parent->right = nullptr;

                curr->parent->large = "";

            }
        }

    }
}

//记录中序遍历结果 用来找前驱
void Tree::inOrderTraversal2(Node* node) const {
    if (node != nullptr) {
        inOrderTraversal2(node->left);
        inorder[i++] = node->small;

        inOrderTraversal2(node->middle);
        if (!node->large.empty()) {
            inorder[i++] = node->large;
        }
        inOrderTraversal2(node->right);

    }
}

//通过中序遍历查找前驱节点
Node* Tree::getPre(Node* node,const string& key){
    inOrderTraversal2(node);
    int k = 0;
    while(inorder[k]!=key)
        k++;
    string prev = inorder[k-1];
    i=0;
    return searchDeleteNode(root, prev);
}

Node* Tree::getRoot(){

    return root;
}

//调整parent
void Tree::adjust(Node* node) const {
    if (node != nullptr) {
        if(node->left)
            node->left->parent = node;
        if(node->middle)
            node->middle->parent = node;
        if(node->right)
            node->right->parent = node;

        adjust(node->left);

        if (!node->large.empty()) {
            if(node->left)
            node->left->parent = node;
            if(node->middle)
            node->middle->parent = node;
            if(node->right)
            node->right->parent = node;
        }
        adjust(node->middle);

        adjust(node->right);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值