2-3-4树(2)实现
2010-10-11 15:49 Clingingboy 阅读(656) 评论(0) 编辑 收藏 举报
为了简单起见,内部将不采用数组,而采用.net的List列表,此部分与用到的算法无关,所以可以忽略
Node的数据项操作
private static int MaxItems = 3; private List<int> itemArray = new List<int>(MaxItems); public bool IsFull { get{ return (itemArray.Count == MaxItems) ? true : false; } } public int NumItems { get { return itemArray.Count; } } public int FindItemIndex(int key) { return itemArray.IndexOf(key); } public int GetItem(int index) { return itemArray[index]; } public int InsertItem(int key) { itemArray.Add(key); itemArray.Sort(); return -1; } public int RemoveItem() { var item = itemArray[itemArray.Count - 1]; itemArray.RemoveAt(itemArray.Count - 1); return item; }
在没有数组的影子下是如此的easy
Node的节点查找
以下图为例子
如果现在要查找55
查找步骤:- 每次都从根节点出发开始查找
- 先从节点内部的数据项开始匹配,如果匹配到则直接返回
- 如果不匹配则判断该节点是否有子节点,若有的话则继续
- 以查找关键字与该节点从左到右进行比较,找出比关键字大的节点(如62比55大,那么子节点的索引则是1)
- 重复2-4步骤(所以该查找同样也适用同内部的Node)
private List<Node234> childNodes = new List<Node234>(MaxItems+1); public int FindNodeIndex(int value) { var curNode = this; int childNumber; while (curNode!=null) { if ((childNumber = curNode.FindItemIndex(value)) != -1) return childNumber; else if (curNode.IsLeaf) return -1; else curNode = FindChildNode(value); } return -1; } private Node234 FindChildNode(int value) { var i = 0; for (; i <itemArray.Count; i++) { if (value < itemArray[i]) return childNodes[i]; } return childNodes[i]; }
插入与分裂
情况1:如果没有分裂的情况下,插入非常的简单,如上先找到节点,然后就可以插入了
public void Insert(int value) { var curNode = this; while (true) { if (curNode.IsLeaf) break; curNode = FindChildNode(curNode, value); } curNode.InsertItem(value); }
情况2:根节点满
现在必须来解决分裂的问题,我们根据2种规则来分裂
首先要解决连接问题
public void ConnectChild(Node234 child) { if (child == null) return; childNodes.Add(child); childNodes=childNodes.OrderBy(e=>e.itemArray[0]).ToList(); if (child != null) child._parent = this; } public Node234 DisconnectChild(int index) { if (childNodes.Count - 1 <= index) return null; var node = childNodes[index]; childNodes.RemoveAt(index); return node; }
规则1:根满
- 创建了2个新节点
- C(成为兄弟节点)
- B成为新的根节点,并成为A,C的父节点
- A保持不变
- 右侧2个节点断开与C连接,左侧2个节点保持不变
private void SplitRoot() { var itemC = this.RemoveItem(); var itemB = this.RemoveItem(); Node234 parent = null, rightNode = null; parent = new Node234(); //Connect Node parent.ConnectChild(this); var index=parent.InsertItem(itemB); for (var i = this.itemArray.Count-1; i >index; i--) { var child = this.DisconnectChild(i); parent.ConnectChild(child); } var child2 = this.DisconnectChild(2); var child3 = this.DisconnectChild(3); //Connect RightNode rightNode = new Node234(); rightNode.InsertItem(itemC); rightNode.ConnectChild(child2); rightNode.ConnectChild(child3); parent.ConnectChild(rightNode); Root = parent; }
规则2:不是根满的情况
- C被移到新的节点中
- B被移动到父节点
- A保持不变
- 断开右侧两个子节点并与新节点连接C,将新节点与父节点连接
private void SplitSubNode() { //move C var itemC = this.RemoveItem(); var newNode = new Node234(); newNode.InsertItem(itemC); //move B var itemB = this.RemoveItem(); Node234 parent = this.Parent; parent.InsertItem(itemB); //Connect RightNode var child2 = this.DisconnectChild(2); var child3 = this.DisconnectChild(3); newNode.ConnectChild(child2); newNode.ConnectChild(child3); //Connect Parent With NewNode parent.ConnectChild(newNode); }
在Insert方法中添加判断
if (curNode.IsFull) { curNode.Split(); curNode = curNode.Parent; // back up // search once curNode = curNode.FindChildNode(value); }
代码中可能还有未知的错误,这里没有写tree234,只写了node,所以加了一个全局的node变量.全代码贴上吧.
只做技术演示而用
public class Node234 { public Node234() { if (Node234.Root == null) Node234.Root = this; } public bool IsLeaf { get {return (childNodes.Count==0) ? true : false; } } private int numItems; private List<Node234> childNodes = new List<Node234>(MaxItems+1); public int FindNodeIndex(int value) { var curNode = this; int childNumber; while (curNode!=null) { if ((childNumber = curNode.FindItemIndex(value)) != -1) return childNumber; else if (curNode.IsLeaf) return -1; else curNode = FindChildNode(value); } return -1; } private Node234 FindChildNode(int value) { var i = 0; for (; i <itemArray.Count; i++) { if (value < itemArray[i]) return childNodes[i]; } return childNodes[i]; } public void Insert(int value) { var curNode = this; while (true) { if (curNode.IsFull) { curNode.Split(); curNode = curNode.Parent; // back up // search once curNode = curNode.FindChildNode(value); } if (curNode.IsLeaf) break; curNode = FindChildNode(value); } curNode.InsertItem(value); } private Node234 _parent; public Node234 Parent { get { return _parent; } } public void ConnectChild(Node234 child) { if (child == null) return; childNodes.Add(child); childNodes=childNodes.OrderBy(e=>e.itemArray[0]).ToList(); if (child != null) child._parent = this; } public Node234 DisconnectChild(int index) { if (childNodes.Count - 1 <= index) return null; var node = childNodes[index]; childNodes.RemoveAt(index); return node; } private void SplitRoot() { var itemC = this.RemoveItem(); var itemB = this.RemoveItem(); Node234 parent = null, rightNode = null; parent = new Node234(); //Connect Node parent.ConnectChild(this); var index=parent.InsertItem(itemB); for (var i = this.itemArray.Count-1; i >index; i--) { var child = this.DisconnectChild(i); parent.ConnectChild(child); } var child2 = this.DisconnectChild(2); var child3 = this.DisconnectChild(3); //Connect RightNode rightNode = new Node234(); rightNode.InsertItem(itemC); rightNode.ConnectChild(child2); rightNode.ConnectChild(child3); parent.ConnectChild(rightNode); Root = parent; } private void SplitSubNode() { //move C var itemC = this.RemoveItem(); var newNode = new Node234(); newNode.InsertItem(itemC); //move B var itemB = this.RemoveItem(); Node234 parent = this.Parent; parent.InsertItem(itemB); //Connect RightNode var child2 = this.DisconnectChild(2); var child3 = this.DisconnectChild(3); newNode.ConnectChild(child2); newNode.ConnectChild(child3); //Connect Parent With NewNode parent.ConnectChild(newNode); } public static Node234 Root; public void Split() { if (this.Parent == null) { SplitRoot(); } else SplitSubNode(); } private static int MaxItems = 3; private List<int> itemArray = new List<int>(MaxItems); public bool IsFull { get{ return (itemArray.Count == MaxItems) ? true : false; } } public int NumItems { get { return itemArray.Count; } } public int FindItemIndex(int key) { return itemArray.IndexOf(key); } public int GetItem(int index) { return itemArray[index]; } public int InsertItem(int key) { itemArray.Add(key); itemArray.Sort(); return itemArray.IndexOf(key); } public int RemoveItem() { var item = itemArray[itemArray.Count - 1]; itemArray.RemoveAt(itemArray.Count - 1); return item; } public Node234 GetChild(int index) { return childNodes[index]; } public static void TestInsert() { var node = new Node234(); node.Insert(30); node.Insert(10); node.Insert(20); node.Insert(40); node.Insert(50); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现