【数据结构】搜索树

二叉搜索树

Binary Search Tree

静态查找, 动态查找

无序链表:灵活性好

有序数组:效率高

直接把元素放在树上,树的动态性强。

这种方式查找,即灵活又效率高。

二叉搜索树,又称有序二叉树,排序二叉树

顾名思义用来排序,何以排序,键值比大小

键 : key  排序用的是key,权值

值  :value  有意义的数据

性质:

1.非空左子树的键值均小于根结点;

2.非空右子树的键值小均于根结点;

3.左,右子树都是二叉树。

构造结点

    老规矩,树形数据结构先来构造结点-》 注意多出了key 与 value

template <class K>

struct BinarySearchTreeNode

{

        K _k;

         V _v;

        BinarySearchTreeNode<K>* _left;

        BinarySearchTreeNode<K>* _right;

        BinarySearchTreeNode(const K& k, const V& v)

               : _k(k)

                 : _v(v)

               , _left(NULL)

               , _right(NULL)

        {}

};

基本操作:

查找操作:key的作用是来排序,所以用它来查找,循环比较结点的key,小进入左子树,大进入右子树

相等时返回key 或 value

Node* Find(const T& x, Node* root)

{

    if (root == NULL)

        return NULL;

    if ( x == root->_t)

        return root;

    if ( x < root->_t)

        return Find(root->_left);  //尾递归 可以用循环来实现

    else ( x > root->_t)

        return Find(root->_right);

    else 

        error(flase);

}

找最值元素 : 根据他的概念不难知道

最大元素一定在最右边

最小元素一定在最左边

Node* FindMin(Node* root)

{

    while(root)

    {

        if (root->left)

            root = root->left;

    }

    return NULL;

}

结点的插入: 1.首先找到他所在的位置,类似查找函数

                     2判断有没有相同的key值,如果有更新

                     3.没有,就直接插入

bool Insert(const K& k)

        {

               Node* root = _root;

               Node* par = root;

               if (_root == NULL)

               {

                       _root = new Node(k);

                       //_root = root;

                       return true;

               }

               while (root)

               {

                       if (k < root->_k)

                       {

                              par = root;

                              root = root->_left;

                       }

                       else if (k > root->_k)

                       {

                              par = root;

                              root = root->_right;

                       }

                       else

                              return false;

               }

               if (k < par->_k)

                       par->_left = new Node(k);

               else

                       par->_right = new Node(k);

               return true;

        }

结点的删除 -》删除操作是很重要的操作,要不能影响其他的节点,具体为三种情况。

1.叶子结点,直接删除,置空

2.只有一个孩子结点,删除自己,父亲指向自己孩子

3.有俩个孩子结点,在左子树里找一个最大的数 或在右子树里找一个最小的树替换 转换为1 2种情况。

why: 因为右子树的最小值一定不会有俩个儿子,这样交换之后可以删除。

           何为右子树的最小值,上面有讲最值问题,最左边的节点一定最小。交换之后,因为他是从右子树交换上来所以一定比左树的值都大,又是比右树都小的,所以不影响。

bool Removed(const K& k)

        {

               Node* root = _root;

               Node* par = _root;

               if (!root)

                       return false;

               while (root)

               {

                       if (k < root->_k)

                       {

                              par = root;

                              root = root->_left;

                       }

                       else if (k > root->_k)

                       {

                              par = root;

                              root = root->_right;

                       }

                       else if (k == root->_k)

                              break;

               }

               if (!root)

                       return false;

               //1,当他为叶子结点时,直接删

               if (root->_left == NULL && root->_right == NULL)

               {

                       if (par->_left == root)

                              par->_left = NULL;

                       else if (par->_right == root)

                              par->_right = NULL;

                       /*else

                              error(false);*/

                       delete root;

                       return true;

               }

               //2.当他左树不为空时,找出左树中最大节点为交换值,删除

               if (root->_left != NULL)

               {

                       par = root;

                       Node* cur = root->_left;

                       while (cur->_right)

                       {

                              par = cur;

                              cur = cur->_right;

                       }

                       _Swap(root, cur);

                       if (par->_left == cur)

                              par->_left = cur->_left;

                       else if (par->_right == cur)

                              par->_right = cur->_left;

                       delete cur;

               }

               //3,只有右子树

               else if (root->_right != NULL)

               {

                       if (root == par->_left)

                              par->_left = root->_right;

                       else if (par->_right == root)

                              par->_right = root->_right;

                       delete root;

               }

        }

效率分析

    我们不难看出当某一端高度过高时,运行时间会变慢,为了让高度相近,就为平衡树。

    当插入顺序最好时,为平衡树,此时效率最高为lgn;

    所以 如何BST树构造为平衡数才是重点。

猜你喜欢

转载自blog.csdn.net/qq_32672481/article/details/79827264