🚩 二叉搜索树
定义
二叉查找树(Binary Search Tree),它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
节点构成
- 节点数据
- 节点指向左子树和右子树的指针
- 还有可能由指向父元素的指针
这里用的只有指向左子树和右子树的指针
typedef struct Node {
int key;
struct Node *left, *right;
} Node;
🚩 BST的基本操作
插入 insert
比较需插入的节点数据与当前节点大小,往左/右子树顺着往下找,直到找到树的最末尾然后插入
🕛 时间复杂度:O(树高)
function: inserts a new node to the tree
input: proot: pointer to the pointer to the tree root
x: the key of the new node
output: returns a pointer to the newly inserted node
returns NULL if insertion is not successful
递归
Node *insertNode(Node **proot, int x) {
if (*proot == NULL){ // if the tree is empty
return *proot = createNode(x);
}
if ((*proot)->key == x) { // we default the tree has different key
return NULL;
}
if ((*proot)->key > x) { // if x < (*proot)->key, find right position in left subtree
return insertNode(&(*proot)->left, x);
}
else { // if x > (*proot)->key, find right position in left subtree
return insertNode(&(*proot)->right, x);
}
}
非递归
Node *insertNode(Node **proot, int x) {
if (*proot == NULL){ //if root is NULL, create a new node in this position
*proot = createNode(x);
return *proot;
}
else {
Node *currenNode = *proot;
while(true){
if (currenNode->key == x){ // we defalt the tree has different key
return NULL;
}
if (currenNode->key > x){ // if x < currenNode->key, find right position in left subtree
if (currenNode->left){ // if currenNode->left != NULL, find next left subtree for position
currenNode = currenNode->left;
}
else { // currenNode->left == NULL, create a new node in this position
currenNode->left = createNode(x); // currenNode->left point to the new node
return *proot;
}
}
if (currenNode->key < x){ // if x > currenNode->key, find right position in right subtree
if (currenNode->right){ // if currenNode->right != NULL, find next right subtree for position
currenNode = currenNode->right;
}
else { // currenNode->right == NULL, create a new node in this position
currenNode->right = createNode(x); //currenNode->right point to the new node
return *proot;
}
}
}
}
}
寻找 find
比较需寻找的节点数据与当前节点大小,往左/右子树顺着往下找
🕛 时间复杂度:O(树高)
function: searches for a node in the tree
input: root: pointer to the tree root
x: the key of of the node to be searched
output: returns a pointer to the found node
returns NULL if no such node exists
递归
Node *findNode(Node *root, int x){
if (root == NULL){ // if the tree is empty
return NULL;
}
if (root->key == x){ // if root->key == x, it is the node we find
return root;
}
if (root->key > x){ // if currenNode->key > x, the node will in left subtree
return findNode(root->left, x);
}
else { // if currenNode->key < x, the node will in right subtree
return findNode(root->right, x);
}
}
非递归
Node *findNode(Node *root, int x){
Node *currenNode = root;
while (currenNode){
if (currenNode->key == x){ // if currenNode->key == x, it is the node we find
return currenNode;
}
else if (currenNode->key > x){ // if currenNode->key > x, the node will in left subtree
currenNode = currenNode->left;
}
else { // if currenNode->key < x, the node will in right subtree
currenNode = currenNode->right;
}
}
if (currenNode == NULL){ // we cannot find the node we want, return NULL
return NULL;
}
}
删除 delete
Case 1: the node does not have child
Case 2: the node have a child
Case 3: the node have two children
用 node 的左子树最大节点或右子树的最小节点替代 node 的位置
🕛 时间复杂度:O(树高)
function: removes a node from the tree without freeing it
input: proot: pointer to the pointer to the tree root
x: the key of of the node to be deleted
output: returns a pointer to the deleted node
returns NULL if no such node exists
💡 为了更清晰的显示思路,下面代码均把四种情况分别讨论,实际操作中部分情况可以合并讨论
递归
// Deletes and returns as result the minimum node in the non-empty tree.
Node *deleteMin(Node **proot) {
if((*proot)->left == NULL) {
// root is the minimum node, remove it from the tree and return it
Node *minNode = *proot;
*proot = (*proot)->right;
return minNode;
}
else {
// Keep moving down-left
return deleteMin(&(*proot)->left);
}
}
Node *deleteNode(Node **proot, int x){
if (*proot == NULL){ // cannot find key
return NULL;
}
if((*proot)->key == x) {
// Case 1: the node doesnot have child
if((*proot)->left == NULL && (*proot)->right == NULL) {
Node *deleteNode = *proot;
*proot = NULL;
return deleteNode;
}
// Case 2: the node has one left child
if((*proot)->left != NULL && (*proot)->right == NULL) {
Node *deleteNode = *proot;
*proot = (*proot)->left;
return deleteNode;
}
// Case 2: the node has one right child
if((*proot)->left == NULL && (*proot)->right != NULL) {
Node *deleted = *proot;
*proot = (*proot)->right;
return deleted;
}
// Case 3: the node has two children
if((*proot)->left != NULL && (*proot)->right != NULL) {
Node *deleteNode = *proot;
// Find the minimum node in the right subtree:
Node *minNode = deleteMin(&(*proot)->right);
// Replace the root with the minNode:
minNode->left = (*proot)->left;
minNode->right = (*proot)->right;
*proot = minNode;
return deleteNode;
}
}
if ((*proot)->key > x) { // keep moving down-left
return deleteNode(&(*proot)->left, x);
}
else { // keep moving down-right
return deleteNode(&(*proot)->right, x);
}
}
非递归
这里有两种方法,一种是改变被删节点的父节点的指针指向,另一种是改变被删节点的指针指向
- 第一种方法,如果起始节点构成有父节点则更方便,这里加多了个function得到节点的父节点
- 这里稍微复杂点,所以写多了点注释
// return the parent node of the number x
Node *Parent(Node *proot, int x){
Node* root = proot;
Node* parent = NULL; // initialize the parent node be NULL
while(root->key != x){
if(root->key > x){ // if x is in the left subtree
parent = root; // move parent to root
root = root->left; // move root to its left node
}
else{ // if x is in the right subtree
parent = root; // move parent to root
root = root->right; // move root to its right node
}
}
return parent;
}
Node *deleteNode(Node **proot, int x){
Node *root = *proot;
Node *deletedNode = findNode(root, x); // find the node which will be deleted
Node *parent = NULL; // initialize the parent node be NULL
if (*proot == NULL){ // if no such node exists, return NULL
return NULL;
}
root = findNode(*proot, x); // move root to the node which will be deleted
parent = Parent(*proot, x); // find the parent of the node which will be deleted
if (root->left == NULL && root->right == NULL){ // case 1 the node have no children
if (parent){ // if the node have parent
if (parent->key > x){ // if node is the left child of parent
parent->left = NULL;
}
else { // if node is the right child of parent
parent->right = NULL;
}
}
else { //if node is root
*proot = NULL;
}
}
else if (root->left == NULL && root->right != NULL){ // case 2 the node have one right child
if (parent){ // if node have parent
if (parent->key > x){ // if the node is the left child of parent
parent->left = root->right; // parent->left point to root->right
}
else { // parent->key < x, the node is the right child of parent
parent->right = root->right; // parent->right point to root->right
}
}
else { // if the node have no parent
*proot = root->right;
}
}
else if (root->left != NULL && root->right == NULL){ // case 2 the node have one left
if(parent){ // if node have parent
if (parent->key > x){ // if the node is the left child of parent
parent->left = root->left; // parent->left point to root->left
}
else { // parent->key < x, the node is the right child of parent
parent->right = root->left; // parent->right point to root->left
}
}
else { //if the node have no parent
*proot = root->left;
}
}
else { //case 3 the node have two children
Node *minParentNode = root->right; // assign minParentNode to root->right to find the root's right subtree's minNode's parent
Node *minNode = minParentNode->left; // assign minNode to minParentNode->left to find the root's right subtree's minNode
// find the min node, search for the last left node of the root's right
if (minNode){ //if the minNode is not the min node of the root's right tree
while (minNode->left){ // if there exist another left node of minNode
minParentNode = minNode; // move minParentNode to minNode
minNode = minNode->left; // move minNode to its left node
}
}
else { // if there is no other left node of minNode, now the minNode is the min node of the root's right subtree
minNode = minParentNode; // move minNode to minParentNode
minParentNode = Parent(*proot, minNode->key); // find the minNode's parent
}
root->key = minNode->key; // assign the minNode's value to the root's value
if (minNode == root->right){ // if minNode is the root's right node, that means minNode->right->key(if exist) is larger than minParentNode->key, minNode->right is in the right subtree of minParentNode
minParentNode->right = minNode->right; // minParentNode->right point to minNode->right
}
else { // if minNode is not the root's right node, that means minNode->right->key (if exist) is smaller than minParentNode->key, minNode->right is in the left subtree of minParentNode
minParentNode->left = minNode->right; // minParentNode->left point to minNode->right
}
deletedNode = minNode; // minNode is the node we need to delete, assign it to deletedNode
}
return deletedNode; // return the node which will be deleted
}
- 第二种方法,学校老师的答案
Node *deleteMin(Node **proot) {
while(true) {
if((*proot)->left == NULL) {
// root is the minimum node, remove it from the tree and return it
Node *minNode = *proot;
*proot = (*proot)->right;
return minNode;
} else {
// Keep moving down-left
proot = &(*proot)->left;
}
}
}
Node *deleteNode(Node **proot, int x){
while(true) {
if(*proot == NULL) {
// Cannot find key, deletion fails
return NULL;
}
if((*proot)->key == x) {
// Case 1: the node is a leaf
if((*proot)->left == NULL && (*proot)->right == NULL) {
Node *deleted = *proot;
*proot = NULL;
return deleted;
}
// Case 2-a: the node has one left child
if((*proot)->left != NULL && (*proot)->right == NULL) {
Node *deleted = *proot;
*proot = (*proot)->left;
return deleted;
}
// Case 2-b: the node has one right child
if((*proot)->left == NULL && (*proot)->right != NULL) {
Node *deleted = *proot;
*proot = (*proot)->right;
return deleted;
}
// Case 3: the node has two children
// We replace the root with the minimum node in the right subtree
// (The maximum node in the left subtree would work too.)
if((*proot)->left != NULL && (*proot)->right != NULL) {
Node *deleted = *proot;
// Find the minimum node in the right subtree:
Node *minNode = deleteMin(&(*proot)->right);
// Replace the root with the minNode:
minNode->left = (*proot)->left;
minNode->right = (*proot)->right;
*proot = minNode;
// Return the deleted node (the old root):
return deleted;
}
}
if((*proot)->key > x) {
proot = &(*proot)->left;
} else {
proot = &(*proot)->right;
}
}
}
其他基本操作
先序历遍
void preOrder(Node *root){
if (root == NULL){
return;
}
printf("%d ", root->key);
preOrder(root->left);
preOrder(root->right);
}
中序历遍
void preOrder(Node *root){
if (root == NULL){
return;
}
preOrder(root->left);
printf("%d ", root->key);
preOrder(root->right);
}
后序历遍
void preOrder(Node *root){
if (root == NULL){
return;
}
preOrder(root->left);
preOrder(root->right);
printf("%d ", root->key);
}
寻找最小值
Node findMin(Node *root){
if (root == NULL){
return NULL;
}
if (root->left == NULL){
return root;
}
return findMin(root->left);
}
寻找最大值
Node findMax(Node *root){
if (root == NULL){
return NULL;
}
if (root->right== NULL){
return root;
}
return findMax(root->right);
}
树的销毁
void destroyTree(Node *root){
if (root == NULL){
return;
}
destroyTree(root->left);
destroyTree(root->right);
free(root);
}
📖 以上均为个人学习数据结构算法时的小笔记,如有错误请多多指正