二叉搜索树(BST)递归和非递归的实现 - C语言

🚩 二叉搜索树

定义

二叉查找树(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);
}




📖 以上均为个人学习数据结构算法时的小笔记,如有错误请多多指正
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值