算法导论(5) 二叉搜索树

来源:互联网 发布:我是一名淘宝差评师 编辑:程序博客网 时间:2024/06/05 07:02

二叉搜索树

设x是二叉搜索树的一个结点,如果y是x左子树的一个结点,那么y.key≤x.key,如果y是x有字数的一个结点,那么y.key≥x.key。

二叉树有三种遍历的方法:
先序遍历:输出根的关键字在其左右子树的关键字之前。
中序遍历:输出根的关键字在其左右子树的关键字之间。
后序遍历:输出根的关键字在其左右子树的关键字之后。

主要的操作包括查找,遍历,最大最小关键字寻找,前驱后继结点查找,插入和删除。代码如下:

class Node{private:    int key;//值public:    Node *left;//左子树    Node *right;//右子树    Node *parent;//父结点    int getkey();    void setkey(int k);    Node(int k = 0);    bool operator == (Node &z);    Node& operator = (Node &z);};//二叉搜索树class BSTree{public:    Node *root;    BSTree(){        root = NULL;    }    void treeinsert(Node &root, Node &z);//插入结点    Node treesearch(Node *root, int k);//查询结点    void treewalk(Node *root);//遍历    Node treemin(Node *root);//寻找结点root下最小值结点    Node treemax(Node *root);//寻找结点root下最大值结点    Node treesuccessor(Node *x);//寻找结点x的后继结点    Node treeprodecessor(Node *x);//寻找结点x的前驱结点    void treetransplant(Node &root, Node *u, Node *v);//在根结点root下移动子树v到u    void treedelete(Node &root, Node *z);//删除结点};#include<iostream>#include"BinarySearchTree.h"using namespace std;Node::Node(int k):key(k){    left = NULL;    right = NULL;    parent = NULL;}bool Node::operator == (Node &z){    if ((key == z.key)&&(left == z.left)&&(right == z.right)&&(parent == z.parent))    {        return true;    }    else{        return false;    }}Node& Node::operator = (Node &z){    delete left;    delete right;    delete parent;    left = z.left;    right = z.right;    parent = z.parent;    key = z.key;    z.left = NULL;    z.right = NULL;    z.parent = NULL;    return *this;}int Node::getkey(){    return key;}void Node::setkey(int k){    key = k;}//查询、最大值、最小值、前驱、后继函数均可以在O(h)时间内完成,h为树的高度Node BSTree::treesearch(Node *root, int k)//查询结点{    //递归版本    if (k == root->getkey())    {        return *root;    }    if (k < root->getkey())    {        return treesearch(root->left, k);    }    else    {        return treesearch(root->right, k);    }    return 0;}void BSTree::treewalk(Node *root)//中序遍历{    if (root != NULL)    {        treewalk(root->left);        cout << root->getkey() << " ";        treewalk(root->right);    }}Node BSTree::treemin(Node *root)//寻找结点root下最小值结点{    //最左边最小    Node *x;    x = root;    while (x->left != NULL)    {        x = x->left;    }    return *x;}Node BSTree::treemax(Node *root)//寻找结点root下最大值结点{    //最右边最大    Node *x;    x = root;    if (x->right != NULL)    {    return treemax(x->right);    }    return *x;}Node BSTree::treesuccessor(Node *x)//寻找结点x的后继结点{    Node *y;    //如果右孩子不空,则右子树中的最小值即为后继    if (x->right != NULL){        return treemin(x->right);    }    y = x->parent;    //如果父结点也为空,无后继结点    //父结点存在时,后继结点为它的最底层祖先,并且后继结点的左结点也是它的祖先    //因此循环的终止条件为x == y->right,当x是一个左孩子时终止,x的父结点为后继结点    while (y != NULL && x == y->right)    {        x = y;        y = y->parent;    }    //y=NULL时,返回y会出错    if (y != NULL)    {        return *y;    }    return 0;}Node BSTree::treeprodecessor(Node *x)//寻找结点x的前驱结点{    Node *y;    //如果左孩子存在,前驱结点为左子树中最大值    if (x->left != NULL){        return treemax(x->left);    }    y = x->parent;    //与后继结点类似,当x为右孩子时终止,x父结点为前驱结点    while (y != NULL && x == y->left)    {        x = y;        y = y->parent;    }    if (y != NULL)    {        return *y;    }    return 0;}void BSTree::treeinsert(Node &root, Node &z)//插入结点{    Node *x, *y = NULL;    x = &root;    //向下寻找位置    while (x != NULL)    {        y = x;        if (z.getkey() < x->getkey())        {            x = x->left;        }        else{            x = x->right;        }    }    z.parent = y;    //判断树是否为空    if (y == NULL)    {        root = z;    }    else if (z.getkey() < y->getkey())    {        y->left = &z;    }    else{        y->right = &z;    }}void BSTree::treetransplant(Node &root, Node *u, Node *v)//在根结点root下移动子树v到u{    //u为根结点    if (u->parent == NULL)    {        root = *v;    }    else if (u == u->parent->left)    {        u->parent->left = v;    }    else{        u->parent->right = v;    }    if (v != NULL)    {        v->parent = u->parent;    }}void BSTree::treedelete(Node &root, Node *z)//删除结点{    Node *y=new Node;    if (z->left == NULL){        //如果左孩子为空,利用右孩子替换,右孩子为空时,相当于直接删除        treetransplant(root, z, z->right);    }    else if (z->right == NULL){        //执行此步时,一定只有左孩子,拿左孩子替换即可        treetransplant(root, z, z->left);    }    else{        //左右孩子都存在,首先需要寻找它的后继结点         y= &treemin(z->right);        if (!(*y == *z->right)){            //如果后继结点不是它的右孩子,后继结点没有左孩子,否则不是后继结点            //先拿后继结点右孩子替换后继结点,再拿后继结点替换要删除的结点            treetransplant(root, y, y->right);            //将z的右孩子换到y上,if外的语句把z的左孩子换到y上            y->right = z->right;            y->right->parent = y;        }        //如果后继结点就是它的右孩子,并且这个右孩子没有左孩子,否则不可能是后继结点,因此直接拿后继结点替换        treetransplant(root, z, y);        y->left = z->left;        y->left->parent = y;    }   }

结构上,指针、引用的应用都比较乱,只做参考。

0 0