线索二叉树(threaded binary search tree) C#

本文介绍了一种特殊的二叉搜索树——线程二叉搜索树(Threaded Binary Search Tree)的实现方法,包括插入、删除操作及中序遍历等核心功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. using System;
  2. namespace ThreadedBinaryTree
  3. {
  4.     class Node
  5.     {
  6.         public Node lchild;
  7.         public int lthread;//0 represent a thread,1 represent a link
  8.         public int data;
  9.         public Node rchild;
  10.         public int rthread;
  11.         public Node(int Data,int Lthread,int Rthread,Node Lchild,Node Rchild)
  12.         {
  13.             data = Data;
  14.             lchild = Lchild;
  15.             rchild = Rchild;
  16.             lthread = Lthread;
  17.             rthread = Rthread;
  18.         }
  19.     }
  20.     class ThreadedBST
  21.     {
  22.         private Node head;
  23.         public ThreadedBST()//Constructor
  24.         {
  25.             head = new Node(0, 0, 1, nullnull);
  26.             head.lchild = head;
  27.             head.rchild = head;
  28.         }
  29.         public void find(int element, ref Node parent, ref Node currentNode)
  30.         {
  31.             if (head.lthread != 0)//tree is not empty
  32.             {
  33.                 currentNode = head.lchild;//the top element of the tree
  34.                 parent = head;
  35.                 while (currentNode != null && currentNode.data != element)
  36.                 {
  37.                     parent = currentNode;
  38.                     if (element < currentNode.data && currentNode.lthread == 1)
  39.                         currentNode = currentNode.lchild;
  40.                     else if (element < currentNode.data && currentNode.lthread == 0)//reach the leaf node of left subtree
  41.                         currentNode = null;
  42.                     else if (element > currentNode.data && currentNode.rthread == 1)
  43.                         currentNode = currentNode.rchild;
  44.                     else if (element > currentNode.data && currentNode.rthread == 0)//reach the leaf node of right subtree
  45.                         currentNode = null;
  46.                 }
  47.             }
  48.             else//tree is empty
  49.             {
  50.                 parent = head;
  51.                 Console.WriteLine("Tree is empty");
  52.             }
  53.         }
  54.         public void insert(int element)
  55.         {
  56.             Node newNode, currentNode=null, parent=null;
  57.             find(element,ref parent,ref currentNode);
  58.             if (currentNode != null)
  59.                 return;
  60.             newNode = new Node(element, 0, 0, nullnull);
  61.             if (parent != head)//if tree is not empty
  62.             {
  63.                 if (element < parent.data)
  64.                 {
  65.                     newNode.lchild = parent.lchild;
  66.                     newNode.rchild = parent;
  67.                     parent.lthread = 1;
  68.                     parent.lchild = newNode;
  69.                 }
  70.                 else if (element > parent.data)
  71.                 {
  72.                     newNode.rchild = parent.rchild;
  73.                     newNode.lchild = parent;
  74.                     parent.rthread = 1;
  75.                     parent.rchild = newNode;
  76.                 }
  77.             }
  78.             else//if tree is empty
  79.             {
  80.                 head.lthread = 1;
  81.                 head.lchild = newNode;
  82.                 newNode.lchild = newNode.rchild = head;
  83.             }
  84.         }
  85.         //if the right child of the node is a link, then we can traverse to the leftmost node in the 
  86.         //right subtree of that node to find its inorder successor.However, if the right child of the 
  87.         //node is a thread, then the thread will point to the inorder successor of that node
  88.         public Node Inorder_successor(ref Node currentNode)//search the successor of currentNode
  89.         {
  90.             Node inorder_current=null;
  91.             if (currentNode.rthread == 0)
  92.             {//if the right child of currentNode is a thread,then the node which the thread point to is successor
  93.                 return currentNode.rchild;
  94.             }
  95.             inorder_current = currentNode.rchild;//make currentNode point to the right child of currentNode
  96.             while (inorder_current.lthread != 0)//loop until reach the leaf node of left subtree
  97.                 inorder_current  = inorder_current.lchild;
  98.             return inorder_current;
  99.         }
  100.         public Node Inorder_predecessor(ref Node currentNode)//search the predecessor of currentNode
  101.         {
  102.             Node inorder_current = null;
  103.             if (currentNode.lthread == 0)
  104.                 return currentNode.lchild;
  105.             inorder_current = currentNode.lchild;
  106.             while (inorder_current.rthread != 0)
  107.                 inorder_current = inorder_current.rchild;
  108.             return inorder_current;
  109.         }
  110.         public void Inorder_traversal()
  111.         {
  112.             Node currentNode;
  113.             if (head.lthread == 0)
  114.             {
  115.                 Console.WriteLine("Tree is empty");
  116.                 return;
  117.             }
  118.             currentNode = head.lchild;
  119.             while (currentNode.lthread != 0)//the fist-visit node is the leftmost node of the tree
  120.                 currentNode = currentNode.lchild;
  121.             Console.Write(currentNode.data + "   ");
  122.             while (currentNode.rchild != head)
  123.             {
  124.                 currentNode = Inorder_successor(ref currentNode);
  125.                 Console.Write(currentNode.data + "   ");
  126.             }
  127.         }
  128.         public void delete(int element)
  129.         {
  130.             Node parent=null, currentNode=null, child=null, successor=null, predecessor=null, inorder_parent=null;
  131.             find(element, ref parent, ref currentNode);
  132.             if (currentNode != null)
  133.             {
  134.                 successor = Inorder_successor(ref currentNode);
  135.                 predecessor = Inorder_predecessor(ref currentNode);
  136.                 if (currentNode.lthread == 0 && currentNode.rthread == 0)//node to be deleted is a leaf node
  137.                 {
  138.                     if (parent != head)
  139.                     {
  140.                         if (parent.lchild == currentNode)
  141.                         {
  142.                             parent.lthread = 0;
  143.                             parent.lchild = currentNode.lchild;
  144.                         }
  145.                         else
  146.                         {
  147.                             parent.rthread = 0;
  148.                             parent.rchild = currentNode.rchild;
  149.                         }
  150.                     }
  151.                     else
  152.                     {
  153.                         head.lthread = 0;
  154.                         head.lchild = head;
  155.                     }
  156.                 }
  157.                 else if ((currentNode.lthread == 0 && currentNode.rthread != 0)
  158.                     || (currentNode.lthread != 0 && currentNode.rthread == 0))
  159.                 //node to be deleted has one child
  160.                 {
  161.                     if (currentNode.lthread == 1)//if currentNode has a left child
  162.                     {
  163.                         child = currentNode.lchild;
  164.                         if (parent.lchild == currentNode)//if currentNode is the left child of parent
  165.                             parent.lchild = child;
  166.                         else
  167.                             parent.rchild = child;
  168.                         predecessor.rchild = successor;
  169.                         predecessor.rthread = 0;
  170.                     }
  171.                     else//current has a right child
  172.                     {
  173.                         child = currentNode.rchild;
  174.                         if (parent.lchild == currentNode)
  175.                             parent.lchild = child;
  176.                         else
  177.                             parent.rchild = child;
  178.                         successor.lchild = predecessor;
  179.                         successor.lthread = 0;
  180.                     }
  181.                 }
  182.                 else if (currentNode.lthread == 1 && currentNode.rthread == 1)
  183.                 {//node to be delete has two children
  184.                     find(successor.data, ref parent, ref successor);
  185.                     inorder_parent = parent;//the parent of successor
  186.                     currentNode.data = successor.data;
  187.                     currentNode = successor;//now delete the successor ,make currentNode point to the successor
  188.                     if (currentNode.lthread == 0 && currentNode.rthread == 0)//node to be deleted is a leaf node
  189.                     {
  190.                         if (parent != head)
  191.                         {
  192.                             if (parent.lchild == currentNode)
  193.                             {
  194.                                 parent.lthread = 0;
  195.                                 parent.lchild = currentNode.lchild;
  196.                             }
  197.                             else
  198.                             {
  199.                                 parent.rthread = 0;
  200.                                 parent.rchild = currentNode.rchild;
  201.                             }
  202.                         }
  203.                         else
  204.                         {
  205.                             head.lthread = 0;
  206.                             head.lchild = head;
  207.                         }
  208.                     }
  209.                     if ((currentNode.lthread == 0 && currentNode.rthread != 0)
  210.                         || (currentNode.lthread != 0 && currentNode.rthread == 0))
  211.                     //node to be deleted has one child
  212.                     {
  213.                         if (currentNode.lthread == 1)//if currentNode has a right child
  214.                         {
  215.                             child = currentNode.lchild;
  216.                             if (parent.lchild == currentNode)//if currentNode is the left child of parent
  217.                                 parent.lchild = child;
  218.                             else
  219.                                 parent.rchild = child;
  220.                             successor.lchild = predecessor;
  221.                             successor.lthread = 0;
  222.                         }
  223.                         else//current has a left child
  224.                         {
  225.                             child = currentNode.rchild;
  226.                             if (parent.lchild == currentNode)
  227.                                 parent.lchild = child;
  228.                             else
  229.                                 parent.rchild = child;
  230.                             successor.lchild = predecessor;
  231.                             successor.rthread = 0;
  232.                         }
  233.                     }
  234.                 }
  235.             }
  236.         }
  237.         static void Main(string[] args)
  238.         {
  239.             ThreadedBST b = new ThreadedBST();
  240.             while (true)
  241.             {
  242.                 Console.Clear();
  243.                 Console.Write("Inorder traverse:");
  244.                 b.Inorder_traversal();
  245.                 Console.WriteLine("/nMenu");
  246.                 Console.WriteLine("1. Implement insert operation");
  247.                 Console.WriteLine("2. Implement delete operation");
  248.                 Console.WriteLine("3. Exit");
  249.                 Console.Write("/nEnter your Choice:");
  250.                 char ch = Convert.ToChar(Console.ReadLine());
  251.                 switch (ch)
  252.                 {
  253.                     case '1':
  254.                         {
  255.                             Console.Write("Enter a number: ");
  256.                             int num =Convert.ToInt32( Console.ReadLine());
  257.                             b.insert(num);
  258.                         }
  259.                         break;
  260.                     case '2':
  261.                         {
  262.                             Console.Write("Enter a number: ");
  263.                             int num =Convert.ToInt32( Console.ReadLine());
  264.                             b.delete(num);
  265.                         }
  266.                         break;
  267.                     case '3':
  268.                         return;
  269.                     default:
  270.                         Console.WriteLine("Invalid option");
  271.                         break;
  272.                 }
  273.             }
  274.         }
  275.     }
  276. }

<think>嗯,用户想了解关于完整二叉搜索树的概念和实现方法。首先,我需要明确什么是完整二叉搜索树(Complete Binary Search Tree,CBST)。根据之前学过的知识,二叉树中的完全二叉树(Complete Binary Tree)是指除了最后一层外,其他层都是满的,并且最后一层的节点都尽可能靠左排列。而二叉搜索树(Binary Search Tree,BST)的特点是每个节点的左子树所有节点的值都小于该节点的值,右子树则都大于。所以完整二叉搜索树应该是结合了这两种特性的数据结构,即同时满足完全二叉树的结构和二叉搜索树的排序性质。 接下来,我需要确认完整二叉搜索树的具体定义和特点。完全二叉树的特性使得它可以用数组高效地存储,而不需要指针,这对于内存管理是有优势的。而二叉搜索树的特性则保证了高效的查找、插入和删除操作,平均时间复杂度为O(log n)。结合起来,CBST可能在保持高效操作的同时,优化存储结构。不过,用户可能想知道如何实现这样的数据结构,或者它的具体应用场景。 然后,实现方法方面,可能需要考虑如何构建这样的树。由于是完全二叉树,节点的位置可以通过数组的索引来确定,比如对于节点i,左子节点在2i+1,右子节点在2i+2。同时,作为二叉搜索树,必须满足左子树的值小于根节点,右子树的值大于根节点。因此,构建CBST可能需要将给定的有序数组按照完全二叉树的结构进行排列。例如,对于有序数组,中序遍历完全二叉树的结构应该能得到有序序列,因此可能需要找到中间节点作为根,递归构建左子树和右子树。 另外,用户可能关心插入和删除操作在CBST中的处理。因为完全二叉树的结构要求最后一层尽可能左对齐,插入和删除可能需要调整树的结构以维持完全性,这可能会影响二叉搜索树的性质。这时候可能需要特定的算法来保持两者的平衡,或者在某些情况下,CBST可能更适合静态数据,而不是频繁变动的数据,因为维护结构可能代价较高。 还需要考虑CBST与其他类型二叉搜索树的区别,比如平衡二叉搜索树(如AVL树、红黑树)。CBST可能在存储上更紧凑,但可能在动态操作上不如平衡树高效。因此,用户可能想知道在什么情况下选择CBST更合适,比如数据静态且需要快速查找的情况下。 此外,用户的问题中提到了“实现方法”,可能需要给出具体的代码示例,比如如何从有序数组构建CBST,或者如何插入节点。例如,可以通过递归方法,每次选择中间元素作为根节点,然后递归构建左右子树,确保完全二叉树的结构。这部分需要结合算法步骤和代码实现来说明。 最后,需要验证自己的理解是否正确,是否有遗漏或错误的地方。例如,是否混淆了完全二叉树和满二叉树的概念,或者是否正确处理了二叉搜索树的排序性质与完全二叉树结构之间的冲突。比如,在构建过程中,如何确保节点位置既满足完全性,又满足左小右大的顺序,可能需要特定的构建策略,如中序遍历填充。</think>### 完整二叉搜索树(Complete Binary Search Tree)概念解析 完整二叉搜索树是**完全二叉树**和**二叉搜索树**的结合体,需同时满足以下特性: 1. **完全二叉树结构**:所有层除最后一层外均为满层,最后一层节点左对齐排列[^1] 2. **二叉搜索树性质**:任意节点的左子树值均小于该节点,右子树值均大于该节点 $$ \text{设节点索引为}i,\ \text{左子节点索引}=2i+1,\ \text{右子节点索引}=2i+2 $$ ### 核心实现步骤(以数组存储为例) 1. **数据预处理**:将输入数据排序为升序序列 2. **递归构建**: ```python def build_cbst(sorted_arr, tree, root_index=0): if not sorted_arr: return n = len(sorted_arr) mid = n // 2 # 计算中间索引 tree[root_index] = sorted_arr[mid] # 递归构建左子树(左半部分) build_cbst(sorted_arr[:mid], tree, 2*root_index+1) # 递归构建右子树(右半部分) build_cbst(sorted_arr[mid+1:], tree, 2*root_index+2) ``` 3. **空间分配**:根据完全二叉树特性预分配数组空间 $$ \text{数组长度}=2^h-1\ \text{(h为树的高度)} $$ ### 关键特性对比 | 特性 | 普通BST | 完整BST | |---------------------|---------|--------------| | 空间利用率 | 动态 | 100%(数组) | | 查找时间复杂度 | O(h) | O(log n) | | 插入/删除复杂度 | O(h) | O(n) | | 适合场景 | 动态数据| 静态数据 | ### 应用场景 1. 预先生成的静态数据集快速查询(如字典数据) 2. 需要固定存储空间的嵌入式系统 3. 需要快速序列化/反序列化的场景[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值