mirror of
				https://github.com/krahets/hello-algo.git
				synced 2025-10-31 18:37:48 +08:00 
			
		
		
		
	 56b20eff36
			
		
	
	56b20eff36
	
	
	
		
			
			* .net 8.0 migration * update docs * revert change * revert change and update appendix docs * remove static * Update binary_search_insertion.cs * Update binary_search_insertion.cs * Update binary_search_edge.cs * Update binary_search_insertion.cs * Update binary_search_edge.cs --------- Co-authored-by: Yudong Jin <krahets@163.com>
		
			
				
	
	
		
			161 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| /**
 | |
|  * File: binary_search_tree.cs
 | |
|  * Created Time: 2022-12-23
 | |
|  * Author: haptear (haptear@hotmail.com)
 | |
|  */
 | |
| 
 | |
| namespace hello_algo.chapter_tree;
 | |
| 
 | |
| class BinarySearchTree {
 | |
|     TreeNode? root;
 | |
| 
 | |
|     public BinarySearchTree() {
 | |
|         // 初始化空树
 | |
|         root = null;
 | |
|     }
 | |
| 
 | |
|     /* 获取二叉树根节点 */
 | |
|     public TreeNode? GetRoot() {
 | |
|         return root;
 | |
|     }
 | |
| 
 | |
|     /* 查找节点 */
 | |
|     public TreeNode? Search(int num) {
 | |
|         TreeNode? cur = root;
 | |
|         // 循环查找,越过叶节点后跳出
 | |
|         while (cur != null) {
 | |
|             // 目标节点在 cur 的右子树中
 | |
|             if (cur.val < num) cur =
 | |
|                 cur.right;
 | |
|             // 目标节点在 cur 的左子树中
 | |
|             else if (cur.val > num)
 | |
|                 cur = cur.left;
 | |
|             // 找到目标节点,跳出循环
 | |
|             else
 | |
|                 break;
 | |
|         }
 | |
|         // 返回目标节点
 | |
|         return cur;
 | |
|     }
 | |
| 
 | |
|     /* 插入节点 */
 | |
|     public void Insert(int num) {
 | |
|         // 若树为空,则初始化根节点
 | |
|         if (root == null) {
 | |
|             root = new TreeNode(num);
 | |
|             return;
 | |
|         }
 | |
|         TreeNode? cur = root, pre = null;
 | |
|         // 循环查找,越过叶节点后跳出
 | |
|         while (cur != null) {
 | |
|             // 找到重复节点,直接返回
 | |
|             if (cur.val == num)
 | |
|                 return;
 | |
|             pre = cur;
 | |
|             // 插入位置在 cur 的右子树中
 | |
|             if (cur.val < num)
 | |
|                 cur = cur.right;
 | |
|             // 插入位置在 cur 的左子树中
 | |
|             else
 | |
|                 cur = cur.left;
 | |
|         }
 | |
| 
 | |
|         // 插入节点
 | |
|         TreeNode node = new(num);
 | |
|         if (pre != null) {
 | |
|             if (pre.val < num)
 | |
|                 pre.right = node;
 | |
|             else
 | |
|                 pre.left = node;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /* 删除节点 */
 | |
|     public void Remove(int num) {
 | |
|         // 若树为空,直接提前返回
 | |
|         if (root == null)
 | |
|             return;
 | |
|         TreeNode? cur = root, pre = null;
 | |
|         // 循环查找,越过叶节点后跳出
 | |
|         while (cur != null) {
 | |
|             // 找到待删除节点,跳出循环
 | |
|             if (cur.val == num)
 | |
|                 break;
 | |
|             pre = cur;
 | |
|             // 待删除节点在 cur 的右子树中
 | |
|             if (cur.val < num)
 | |
|                 cur = cur.right;
 | |
|             // 待删除节点在 cur 的左子树中
 | |
|             else
 | |
|                 cur = cur.left;
 | |
|         }
 | |
|         // 若无待删除节点,则直接返回
 | |
|         if (cur == null)
 | |
|             return;
 | |
|         // 子节点数量 = 0 or 1
 | |
|         if (cur.left == null || cur.right == null) {
 | |
|             // 当子节点数量 = 0 / 1 时, child = null / 该子节点
 | |
|             TreeNode? child = cur.left ?? cur.right;
 | |
|             // 删除节点 cur
 | |
|             if (cur != root) {
 | |
|                 if (pre!.left == cur)
 | |
|                     pre.left = child;
 | |
|                 else
 | |
|                     pre.right = child;
 | |
|             } else {
 | |
|                 // 若删除节点为根节点,则重新指定根节点
 | |
|                 root = child;
 | |
|             }
 | |
|         }
 | |
|         // 子节点数量 = 2
 | |
|         else {
 | |
|             // 获取中序遍历中 cur 的下一个节点
 | |
|             TreeNode? tmp = cur.right;
 | |
|             while (tmp.left != null) {
 | |
|                 tmp = tmp.left;
 | |
|             }
 | |
|             // 递归删除节点 tmp
 | |
|             Remove(tmp.val!.Value);
 | |
|             // 用 tmp 覆盖 cur
 | |
|             cur.val = tmp.val;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| public class binary_search_tree {
 | |
|     [Test]
 | |
|     public void Test() {
 | |
|         /* 初始化二叉搜索树 */
 | |
|         BinarySearchTree bst = new();
 | |
|         // 请注意,不同的插入顺序会生成不同的二叉树,该序列可以生成一个完美二叉树
 | |
|         int[] nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15];
 | |
|         foreach (int num in nums) {
 | |
|             bst.Insert(num);
 | |
|         }
 | |
| 
 | |
|         Console.WriteLine("\n初始化的二叉树为\n");
 | |
|         PrintUtil.PrintTree(bst.GetRoot());
 | |
| 
 | |
|         /* 查找节点 */
 | |
|         TreeNode? node = bst.Search(7);
 | |
|         Console.WriteLine("\n查找到的节点对象为 " + node + ",节点值 = " + node?.val);
 | |
| 
 | |
|         /* 插入节点 */
 | |
|         bst.Insert(16);
 | |
|         Console.WriteLine("\n插入节点 16 后,二叉树为\n");
 | |
|         PrintUtil.PrintTree(bst.GetRoot());
 | |
| 
 | |
|         /* 删除节点 */
 | |
|         bst.Remove(1);
 | |
|         Console.WriteLine("\n删除节点 1 后,二叉树为\n");
 | |
|         PrintUtil.PrintTree(bst.GetRoot());
 | |
|         bst.Remove(2);
 | |
|         Console.WriteLine("\n删除节点 2 后,二叉树为\n");
 | |
|         PrintUtil.PrintTree(bst.GetRoot());
 | |
|         bst.Remove(4);
 | |
|         Console.WriteLine("\n删除节点 4 后,二叉树为\n");
 | |
|         PrintUtil.PrintTree(bst.GetRoot());
 | |
|     }
 | |
| }
 |