2-3-4树(2)实现
2010-10-11 15:49 Clingingboy 阅读(655) 评论(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); } }