zoukankan      html  css  js  c++  java
  • BinarySearchTree二叉搜索树的实现

    /*
    二叉搜索树(Binary Search Tree),(又:二叉查找树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
    */
    //
    BinarySearchTree.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> using std::cin; using std::cout; using std::endl; struct BinarySearchTreeNode{ int key; BinarySearchTreeNode *parent; BinarySearchTreeNode *left; BinarySearchTreeNode *right; }; struct BinarySearchTree{ BinarySearchTreeNode *root; int nodes; }; void initeTree(BinarySearchTree &T) { T.root = nullptr; T.nodes = 0; } void allocateNodeSpace(BinarySearchTreeNode **node) { *node = (BinarySearchTreeNode *)malloc(sizeof(BinarySearchTreeNode)); if (*node == NULL) cout << "allocte space error!"<<endl; else { (*node)->left = nullptr; (*node)->right = nullptr; (*node)->parent = nullptr; (*node)->key = 0; } }
    void inorderVisit(BinarySearchTreeNode *node) { if (node != nullptr) { inorderVisit(node->left); cout << node->key << ' '; inorderVisit(node->right); } } //递归实现 BinarySearchTreeNode &searchOneNode(BinarySearchTreeNode* node,int key) { if (node == nullptr || node->key == key) return *node; if (node->key < key) return searchOneNode(node->right, key); else return searchOneNode(node->left,key); } //迭代实现 BinarySearchTreeNode &searchOneNode1(BinarySearchTreeNode* node, int key) { while (node != nullptr && key != node->key) { if (node->key < key) node = node->right; else node = node->left; } return *node; } //查找某个结点子树中的最小元素 BinarySearchTreeNode &findMinmum(BinarySearchTreeNode *node) { while (node->left != nullptr) { node = node->left; } return *node; } //查找某个结点子树中的最大元素 BinarySearchTreeNode &findMaxmum(BinarySearchTreeNode *node) { while (node->right != nullptr) { node = node->right; } return *node; } //获取一个结点的后继 //两种情况: //1 结点x的右子树非空,那么x的后继结点恰是x的右子树中的最左结点。 //2 结点x的右子树为空,如果x有一个后继结点y,那么y就是x的有左孩子的最底层祖先,并且它也是x的一个祖先。 BinarySearchTreeNode &getNodeSuccessor(BinarySearchTreeNode *node) { BinarySearchTreeNode *ptr = nullptr; ptr = node->right; while (ptr != nullptr && ptr->left != nullptr) { ptr = ptr->left; } if (ptr == nullptr) ptr = node->parent; return *ptr; } //建立一棵二叉搜索树,即向二叉搜索树中增加结点 void inserTreeNode(BinarySearchTree &T,BinarySearchTreeNode *node) { BinarySearchTreeNode *parentPtr = nullptr; BinarySearchTreeNode *temPtr = T.root; while (temPtr != nullptr) { parentPtr = temPtr; if (node->key < temPtr->key) temPtr = temPtr->left; else temPtr = temPtr->right; } node->parent = parentPtr; if (parentPtr == nullptr) T.root = node; else if (node->key < parentPtr->key) parentPtr->left = node; else parentPtr->right = node; } //建立一棵二叉搜索树,即 void createTree(BinarySearchTree &T) { int key = -1; BinarySearchTreeNode *temNode = nullptr; while (cin>>key,key!=-1) { allocateNodeSpace(&temNode); temNode->key = key; inserTreeNode(T,temNode); } } //用一棵子树v替换另一棵子树u并成为其(u)双亲的孩子结点。 void transplantUV(BinarySearchTree &T,BinarySearchTreeNode *u, BinarySearchTreeNode *v) { if (u->parent == nullptr) T.root = v; else if (u == u->parent->left) u->parent->left = v; else u->parent->right = v; if (v != nullptr) v->parent = u->parent; }
    //从二叉搜索树中删除一个结点 /* 从一棵二叉搜索树中删除一个结点node,可以分为三种情况: 1)如果node没有孩子结点,那么可以直接删除该结点; 2)如果node只有一个孩子结点,那么就让该孩子结点取代node的位置; 3)如果node有两个孩子结点,那么找到node的后继结点afterNode(一定在node的右子树中),并让afterNode取代node的位置。 并让node原来的右子树成为afterNode新的右子树,node的左子树成为afterNode的左子树。 对于情况3)又可以分为两种情况: 3.1)afterNode是node的右孩子,那么直接让afterNode取代node的位置,不做其它变换。 3.2)afterNode是node的右子树中的左子树的一个结点,但不是node的右孩子,那么先让afterNode的右孩子取代afterNode的位置, 然后让afterNode取代node的位置,并让node的右子树成为afterNode新的右子树。 */ void deleteTreeNode(BinarySearchTree &T, int key) { BinarySearchTreeNode *node = &searchOneNode1(T.root,key); if (node->left == nullptr) transplantUV(T, node, node->right); else if (node->right == nullptr) transplantUV(T,node,node->left); else { BinarySearchTreeNode *temPtr = &findMinmum(node->right); if (temPtr->parent != node) { transplantUV(T,temPtr,temPtr->right); temPtr->right = node->right; temPtr->right->parent = temPtr; } transplantUV(T, node, temPtr); temPtr->left = node->left; node->left->parent = temPtr; } free(node); } void main(void) { cout << "1.首先构建一棵二叉搜索树:" << endl; BinarySearchTree T; initeTree(T); createTree(T); cout << "2.中序遍历二叉搜索树:" << endl; inorderVisit(T.root); //cout << endl; //cout << "3.输入出一个结点的后继结点:" << endl; //cout << "请输入要查找的结点的关键字Key:" << endl; //int keyValue; //cin >> keyValue; //BinarySearchTreeNode *temPtr = &searchOneNode1(T.root,keyValue); //BinarySearchTreeNode *successorPtr = &getNodeSuccessor(temPtr); //cout << successorPtr->key; //cout << "请输入要删除的结点的关键字:" << endl; //cin >> keyValue; int keyValue; cin >> keyValue; deleteTreeNode(T, keyValue); inorderVisit(T.root); }

    对于查找一个结点x的后继结点来说,其第二种情况即:如果结点x没有右子树,那么对于x的父结点来说又可以分为两种情况,1)x结点在其父结点的左子树上;2)x结点在其父结点的右子树上。当然我们不可能这样无休止的分析下去,因为相对于x结点的所有祖先来说,x结点所在的位置情况都有两种。若是x结点有n个祖先,那么就会出现2n中情况。所以可以另辟蹊径,那我们从遍历二叉搜索树着手。试想一下,我们可以通过中序遍历一棵二叉搜索树得到一串有序序列。那么对于中序遍历来说,其x结点的后继就是我们要找的点。如果结点x在中序遍历序列中不是最后一个结点的话,那么它必有一个后继结点(线性表的性质)。

    好,假如对于一个结点x,其后继结点y存在,那么y->key一定大于x->key。我们可以这样考虑:

    根据二叉搜索树的性质,我们知道x的左子树中的任一结点的key值都小于x,所以y必定不在其左子树中。那么结点y必定为x的最先结点或者其祖先结点的右子树。而且y的key值是其中大于x的key值且最小的一个,所以y结点不可能是其祖先的右子树上的 结点。接着我们就可以确定y必定是x的祖先结点,x结点必定在y的左子树中,也就是说y的左孩子也是x的祖先,那么对于所有满足条件的祖先结点有n个(pi-1<pi)其中i = 0,1,...,n-1.由此可以推知,x的后继结点必定为其中最小的一个即p0。得到一个结论结点x的右子树为空,如果x有一个后继结点y,那么y就是x的有左孩子的最底层祖先,并且它也是x的一个祖先。

  • 相关阅读:
    python自动发邮件库yagmail
    Vmware改成bridge方式联网
    centos7 更新Firefox版本
    无法应用转换程序,请检查指定的转换程序路径是否有效
    python中list/tuple/dict/set的区别
    Python中的*arg和**kwarg
    centos7.4下搭建JDK+Tomcat+Nginx+Mysql+redis+Mongodb+maven+Git+Jenkins
    用 Apache Derby 进行 ODBC 编程
    Derby 命令
    Python与数据库
  • 原文地址:https://www.cnblogs.com/tgycoder/p/4941883.html
Copyright © 2011-2022 走看看