假设有一家移动电话公司保存着它遍及全世界的数百万的客户信息。每个客户都分配有一个唯一的身份号(id)。可以通过各自id来读取每个客户的记录。这些id需要以排序后的方式进行存储,这样你就能轻松对这些数据进行事务操作,如搜索、插入和删除
using System;
using System.Collections.Generic;
using System.Text;
namespace BinarySearchTree
{
// 二叉排序树节点类
public class Node
{
public string info;//存放节点的值
public Node lchild;//存放左子树的引用
public Node rchild;//存放右子树的引用
public Node(string info, Node lchild, Node rchild)
{
this.info = info;
this.lchild = lchild;
this.rchild = rchild;
}
}
// 二叉排序树类
public class BinaryTree
{
//存放二叉排序树的根节点
public Node root;
public BinaryTree()
{
root = null;//表示二叉排序树是一棵空树
}
//在查找某个元素或插入某个元素时使用
public void find(string element, ref Node parent, ref Node currentNode)
{
currentNode = root;
parent = null;
/*
在二叉排序树查找是否有节点的值等于element。
如果存在,当退出此循环时currentNode就指向这个要查找的节点,
parent指向此节点的父亲节点;
如果不存在,当退出此循环时currentNode就指null,
parent指向要插入节点的父亲节点;
*/
while (currentNode != null)
{
//让父亲指向当前节点
parent = currentNode;
//如果要查找元素的值小于当前节点的值
if (string.Compare(element , currentNode.info)<0)
{
//让当前节点指向当前节点左子树
currentNode = currentNode.lchild;
}
//如果要查找元素的值大于当前节点的值
else if (string.Compare(element, currentNode.info) > 0)
{
//让当前节点指向当前节点右子树
currentNode = currentNode.rchild;
}
else//如果要查找元素的值等于当前节点的值
{
//表明找到,退出循环
break;
}
}
}
//在二叉排序树中插入元素
public void insert(string element)
{
Node tmp;//存放要插入的节点
Node parent = null;//存放要插入节点的父亲节点
Node currentNode = null;//存放当前节点
//第一步,找到要插入元素的父亲节点
find(element, ref parent, ref currentNode);
//第二步,在二叉排序树中插入新节点
//如果要插入元素不在二叉排序树,就可以插入此元素,
//currentNode等于null,parent就指向要插入元素的父亲节点
if (currentNode == null)
{
//创建新节点对象
tmp = new Node(element, null, null);
//如果是空树
if (parent == null)
{
root = tmp;
}
else
{
//如果要插入元素的值小于父亲节点的值
if (string.Compare(element, parent.info) < 0)
{
//将新节点插入到父亲节点的左子树
parent.lchild = tmp;
}
else//如果要插入元素的值大于父亲节点的值
{
//将新节点插入到父亲节点的右子树
parent.rchild = tmp;
}
}
}
//如果要插入元素已经在二叉排序树,currentNode就不等于null
else
{
throw new Exception("二叉树中已经存在值为 " + element +" 的节点");
}
}
//将节点值等于element的节点从二叉排序树中删除
public void delete(string element)
{
Node parent = null, currentNode = null;
//第一步:找到要删除的节点
find(element, ref parent, ref currentNode);
//如果currentNode != null,表明找到要删除的节点
if (currentNode != null)
{
//如果要删除的节点为叶子节点
if ((currentNode.lchild == null) && (currentNode.rchild == null))
{
//如果要删除的节点为根节点
if (currentNode == root)
{
//删除后,就为空树
root = null;
}
//如果要删除的节点是父亲节点的左子树
else if (currentNode == parent.lchild)
{
//将父亲节点的左子树置null
parent.lchild = null;
}
//如果要删除的节点是父亲节点的右子树
else
{
//将父亲节点的右子树置null
parent.rchild = null;
}
}
else if ((currentNode.lchild != null) && (currentNode.rchild != null))//要删除的节点有两个子节点
{
//中序继任节点
Node inorder_suc;
//中序继任节点的父节点
Node inorder_suc_parent;
//让中序继任节点指向要删除节点的右子树
inorder_suc = currentNode.rchild;
//让中序继任节点的父节点指向要删除节点
inorder_suc_parent = currentNode;
//如果中序继任节点不是要删除节点的右儿子节点
if (inorder_suc.lchild != null)
{
//找到中序继任节点,
//说白了就是不断左移的过程,
//直到找到最左边的叶子节点或者只有右子树的节点
while (inorder_suc.lchild != null)
{
//让中序继任节点的父节点指向中序继任节点
inorder_suc_parent = inorder_suc;
//让中序继任节点指向中序继任节点的左子节点
inorder_suc = inorder_suc.lchild;
}
//用中序继任节点的值替换要删除节点的值
currentNode.info = inorder_suc.info;
//删除中序继任节点
inorder_suc_parent.lchild = inorder_suc.rchild;
}
//如果中序继任节点是要删除节点的右儿子节点
else
{
//用中序继任节点的值替换要删除节点的值
currentNode.info = inorder_suc.info;
//删除中序继任节点
inorder_suc_parent.rchild = inorder_suc.rchild;
}
}
else//要删除的节点只有一个子节点
{
Node child;//要删除节点的子节点
//如果要删除的节点只有左子树
if (currentNode.lchild != null)
{
//将要删除节点的左子树赋给child
child = currentNode.lchild;
}
//如果要删除的节点只有右子树
else
{
//将要删除节点的右子树赋给child
child = currentNode.rchild;
}
//如果要删除的节点为父节点的左子节点
if (currentNode == parent.lchild)
{
//让父节点左子节点引用指向child
parent.lchild = child;
}
//如果要删除的节点为父节点的右子节点
else
{
//让父节点右子节点引用指向child
parent.rchild = child;
}
}
}
//如果currentNode == null,表明没有找到要删除的节点
else
{
throw new Exception("没有找到要删除的节点");
}
}
//中序遍历,输入参数为要遍历树的根节点
public void inorder(Node ptr)
{
if (root == null)
{
Console.WriteLine("tree is empty");
}
if(ptr != null)
{
//中序遍历左子树
inorder(ptr.lchild);
//访问根节点的值
Console.Write(ptr.info + " ");
//中序遍历右子树
inorder(ptr.rchild);
}
}
//先序遍历,输入参数为要遍历树的根节点
public void preorder(Node ptr)
{
if (root == null)
{
Console.WriteLine("tree is empty");
}
if (ptr != null)
{
//访问根节点的值
Console.Write(ptr.info + " ");
//先序遍历左子树
preorder(ptr.lchild);
//先序遍历右子树
preorder(ptr.rchild);
}
}
//后序遍历,输入参数为要遍历树的根节点
public void postorder(Node ptr)
{
if (root == null)
{
Console.WriteLine("tree is empty");
}
if (ptr != null)
{
//后序遍历左子树
postorder(ptr.lchild);
//后序遍历右子树
postorder(ptr.rchild);
//访问根节点的值
Console.Write(ptr.info + " ");
}
}
}
}
using System;
using System.Text;
namespace BinarySearchTree
{
/* A Node class consists of three things, the information, reference to the
right child, and reference to the left child. */
class Node
{
public string info;
public Node lchild;
public Node rchild;
public Node(string i, Node l, Node r) /* Constructor for the Node class */
{
info = i;
lchild = l;
rchild = r;
}
}
class BinaryTree
{
public Node ROOT;
public BinaryTree()
{
ROOT = null; /* Initializing ROOT to null */
}
public void insert(string element) /* Inserts a Node in the Binary Search Tree */
{
Node tmp, parent = null, currentNode = null;
find(element, ref parent, ref currentNode);
if (currentNode != null) /* Checks if the node to be inserted is already present or not */
{
Console.WriteLine("Duplicates words not allowed");
return;
}
else /* If the specified Node is not present */
{
tmp = new Node(element, null, null); /* creates a Node */
if (parent == null) /* If the tree is empty */
ROOT = tmp;
else
if (String.Compare(element,parent.info) < 0)
parent.lchild = tmp;
else
parent.rchild = tmp;
}
}
public void find(string element, ref Node parent, ref Node currentNode)
{
/* This function finds the currentNode of the specified Node as well as the
currentNode of its parent. */
currentNode = ROOT;
parent = null;
while ((currentNode != null) && (currentNode.info != element))
{
parent = currentNode;
if (String.Compare(element,currentNode.info)<0)
currentNode = currentNode.lchild;
else
currentNode = currentNode.rchild;
}
}
public void inorder(Node ptr) /* Performs the inorder traversal of the tree */
{
if (ROOT == null)
{
Console.WriteLine("Tree is empty");
return;
}
if (ptr != null)
{
inorder(ptr.lchild);
Console.Write(ptr.info + " ");
inorder(ptr.rchild);
}
}
public void preorder(Node ptr) /* Performs the preorder traversal of the tree */
{
if (ROOT == null)
{
Console.WriteLine("Tree is empty");
return;
}
if (ptr != null)
{
Console.Write(ptr.info + " ");
preorder(ptr.lchild);
preorder(ptr.rchild);
}
}
public void postorder(Node ptr) /* Performs the postorder traversal of the tree */
{
if (ROOT == null)
{
Console.WriteLine("Tree is empty");
return;
}
if (ptr != null)
{
postorder(ptr.lchild);
postorder(ptr.rchild);
Console.Write(ptr.info + " ");
}
}
public void remove() /* Deletes the specified Node from the tree */
{
if (ROOT == null) /* Checks whether the tree is empty */
{
Console.WriteLine("Tree is empty");
return;
}
Node parent = null, currentNode = null;
string element;
Console.Write("Enter the word to be deleted: ");
element = Console.ReadLine();
find(element, ref parent, ref currentNode); /* Finds the currentNode of the Node and its parent */
if (currentNode == null)
{
Console.WriteLine("\nWord not found in the dictionary");
return;
}
/* Depending upon the status of the child nodes, the lines of code below
call the appropriate function for performing the deletion of the specified
node from the tree. */
if (currentNode.lchild == null && currentNode.rchild == null)
case_1(ref parent, ref currentNode);
else if (currentNode.lchild != null && currentNode.rchild == null)
case_2(ref parent, ref currentNode);
else if (currentNode.lchild == null && currentNode.rchild != null)
case_2(ref parent, ref currentNode);
else
case_3(ref parent, ref currentNode);
}
public void case_1(ref Node parent, ref Node currentNode) /* This function is invoked if the Node to be deleted is the leaf Node */
{
if (parent == null)
ROOT = null;
else
{
if (currentNode == parent.lchild)
parent.lchild = null;
else
parent.rchild = null;
}
}
public void case_2(ref Node parent, ref Node currentNode) /* This function is invoked if the node to be deleted has one child (left or right) */
{
Node child;
if (currentNode.lchild != null)
child = currentNode.lchild;
else
child = currentNode.rchild;
if (parent == null)
ROOT = child;
else
if (currentNode == parent.lchild)
parent.lchild = child;
else
parent.rchild = child;
}
public void case_3(ref Node parent, ref Node currentNode) /* This function is invoked when the Node to be deleted has two children */
{
Node inorder_suc, inorder_parent;
inorder_parent = currentNode;
inorder_suc = currentNode.rchild;
while (inorder_suc.lchild != null)
{
inorder_parent = inorder_suc;
inorder_suc = inorder_suc.lchild;
}
currentNode.info = inorder_suc.info;
if (inorder_suc.lchild == null && inorder_suc.rchild == null)
case_1(ref inorder_parent, ref inorder_suc);
else
case_2(ref inorder_parent, ref inorder_suc);
}
static void Main(string[] args)
{
BinaryTree b = new BinaryTree();
while (true)
{
Console.WriteLine("\nMenu");
Console.WriteLine("1. Implement insert operation");
Console.WriteLine("2. Perform inorder traversal");
Console.WriteLine("3. Perform preorder traversal");
Console.WriteLine("4. Perform postorder traversal");
Console.WriteLine("5. Implement delete operation");
Console.WriteLine("6. Exit");
Console.Write("\nEnter your choice (1-6): ");
char ch = Convert.ToChar(Console.ReadLine());
Console.WriteLine();
switch (ch)
{
case '1':
{
Console.Write("Enter a word: ");
string word = Console.ReadLine();
b.insert(word);
}
break;
case '2':
{
b.inorder(b.ROOT);
}
break;
case '3':
{
b.preorder(b.ROOT);
}
break;
case '4':
{
b.postorder(b.ROOT);
}
break;
case '5':
{
b.remove();
}
break;
case '6':
return;
default:
{
Console.WriteLine("Invalid option");
break;
}
}
}
}
}
}
热门源码