'Programming/File Structure'에 해당되는 글 1건

  1. 2011.12.23 B-Tree in Java
Programming/File Structure2011. 12. 23. 17:22
File Structure assignment, it works perfectly well BTree.java
import java.io.*;
import java.util.*;

// 실제로 BTree를 구현할 class

public class BTree {
	
	
	public BTreeNode rootNode;
	
	public BTree()
	{
		rootNode = new BTreeNode();
	}
	
	public boolean insert(BTreeData data) throws Exception			// 생성부분 완료
	{
		Stack stack = new Stack();		// 삽입시 참조되는 순서를 저장하게 될 stack

		BTreeNode parentNode = null; 		
		BTreeNode currentNode = rootNode;
		BTreeNode newNode = null;
		
		currentNode = rootNode;
		int i=0;
		
		//int totalCount = 
		while(currentNode != null)
		{
			parentNode = currentNode;
			stack.push(parentNode);		// Stack에 부모노드들이 차근 차근 쌓아둔다.(나중에 split or merge시 사용)
			
			for(i=0;i data.key)	// 만약 bucket의 키 값이, data key보다 클 경우
				{											// 그 의미는 곧 삽입해야할 곳을 찾았다는 의미
					break;
					
				}
			}
			currentNode = currentNode.childNode[i];		// 실제 insert 될 곳의 node는 여기 들어간다.
		}
		if(parentNode == null)	// root에 아무것도 없는 경우
		{
			rootNode.data[0] = data;
			rootNode.elementCount = 1;
		}
		else		// root노드가 비어있지 않은 경우(일반정인 경우라면)(그리고 여기선 순서대로 저장되야 한다. sort함수를 사용하자)
		{
			insertDataBTree(parentNode,data, null);
			splitNode(stack);
		}
		return true;
	}
	
	
	//실제 Data를 입력하는 함수이다.
	public void insertDataBTree(BTreeNode currentNode, BTreeData data, BTreeNode RChildNode) throws Exception
	{
		@SuppressWarnings("null")
		int elementIndex = currentNode.elementCount;
		int i=0;			// 실제로 삽입될 index
		
		for( i = elementIndex-1 ; i>=0;i--)		// 자료를  이동하는 함수
		{
			int tempKey = currentNode.data[i].key;
			
			if(tempKey> data.key)			// 한칸씩 땡기게 된다.
			{
				currentNode.data[i+1] = currentNode.data[i];
				currentNode.childNode[i+2] = currentNode.childNode[i+1];
			}
			else
				break;
		}
		
		currentNode.data[i+1] = data;					// 실제 데이터 삽입부분, i--이므로
		currentNode.childNode[i+2] = RChildNode;		// 우 노드를 삽입한다(이는 merge와 split시 필요하다)
		currentNode.elementCount++;					// 
	}
	
	public void showBTree()					// 출력 함수
	{
		if(rootNode == null)
		{
			System.out.println("There is no data!!! BTree is empty!");
		}
		else
		{
			showBTreeByRecur(rootNode);
		}
	}
	
	public void showBTreeByRecur(BTreeNode Node)			// 출력 부분
	{
		// post-order traversals.
		if(Node != null)
		{
			for(int i=0;i stack) 		// 분할 함수 부분
	{
		BTreeNode parentTreeNode = null;
		BTreeNode currentTreeNode = null;
		BTreeNode newNode = null;
		BTreeData middleElement = null;
		BTreeNode tempNode;
		int middleIndex = 5/2;
		currentTreeNode = stack.pop();		// 가장 최상위 stack의 값을 가져온다.
		while(currentTreeNode != null)
		{
			//currentTreeNode = tempNode; 
			if(currentTreeNode.elementCount >= 5)	// 만약 5보다 element가 크다면(실제로 데이터는 M-1개 즉 4개밖에 저장하지 못한다)
			{
				newNode = new BTreeNode();		
				middleElement = new BTreeData();
				middleElement = currentTreeNode.data[middleIndex];		// 중간요소를 저장한다.
				currentTreeNode.data[middleIndex] = null;			// 이 부분을 없애준다.
				
				int j =0;
				int i;
				for(i= middleIndex + 1 ; i<5; i++)		// 중간 이후의 노드들은 분할되기 위해서 다 복사된다.
				{
					newNode.data[j] = currentTreeNode.data[i];
					newNode.childNode[j] = currentTreeNode.childNode[i];
					currentTreeNode.data[i] = null;
					currentTreeNode.childNode[i] = null;
					j++;
				}
				newNode.childNode[j] = currentTreeNode.childNode[i];		// m원 트리에서 node개수는 m-1개 subTree는 m개이기 떄문에
				currentTreeNode.childNode[i] = null;						// 이 작업을 반드시 해줘야한다.
				
				newNode.elementCount = 5/2;			// 분할되면 2개만 저장하게 된다.(5개 이므로)
				currentTreeNode.elementCount = 5/2;		// 현재 노드의 element 개수도 반이 된다고 명시해준다.
				
				// 여기서부터는 상위 부모 노드를 가져온다.
				try
				{
					parentTreeNode = stack.pop();		// 부모노드 가져오기
					insertDataBTree(parentTreeNode, middleElement, newNode);
				}
				catch(Exception e)			// 더 이상 pop하지 못하면 이 예외가 발생하게 된다.
				{
					rootNode = new BTreeNode();		// root노드를 하나 새로이 다시 만들고
					rootNode.data[0] = middleElement;		// 중간값을 새로 집어 넣고
					rootNode.elementCount++;		// 전체 개수를 증가 시킨 후
					rootNode.childNode[0] = currentTreeNode;		// 왼쪽 subtree는 현재껄로
					rootNode.childNode[1] = newNode;		// 다른쪽은 새로운 걸로 삽입한다.
				}
			}
			currentTreeNode = parentTreeNode;			// 계속해서 올라가야 한다.
			parentTreeNode = null;
		}
		
	}
	
	
	public boolean removeNode(int key) throws Exception
	{	
		int i = 0; 	// counter 변수
		//int index = 0;
		boolean isFind = false;		// 만약 검색해서 해당 노드를 찾지 못할경우 이 flag가 쓰인다.
		BTreeNode parentNode = null;
		BTreeNode currentNode = null;
		Stack stack = new Stack();		// stack을 하나 생성한다(노드 분할 및 balance를 위해서 쓰인다)
		
		currentNode = rootNode;
		
		while(currentNode != null && isFind == false)			// 이부분은 insert함수와 똑같지만, 찾을 때까지 수행하는 것만 다르다.
		{
			parentNode = currentNode;
			stack.push(parentNode);		// Stack에 부모노드들이 차근 차근 쌓아둔다.(나중에 split or merge시 사용)
			
			for(i=0;i key)	// 만약 bucket의 키 값이, data key보다 클 경우
				{											// 그 의미는 곧 삽입해야할 곳을 찾았다는 의미
					break;
				}
			}
			currentNode = currentNode.childNode[i];		// 실제 insert 될 곳의 node는 여기 들어간다.
		}
		
		if(isFind == true)		// 만약 원하는 키를 찾았다면
		{
								// 먼저 leaf node가 잇는지 검사한다.
			if(parentNode.childNode[0] == null)		// 현재노드가 아무것도 가리키지 않을 경우
			{
				deleteKeyBTree(parentNode, i);
				// deleteKeyBt 를 수행하는 부분
			}
			else			// leaf 노드가 잇다면
			{
				parentNode = replaceLeafNodeBTree(parentNode, i, stack);		// leaf 노드의 맨 끝 부분을 끌어 당기는 함수
				// replaceLeafNodebt를 수행한다.
			}			
			if(parentNode.elementCount < 5/2)		// 만약 최소 개수보다 작다면
			{
				balanceBTree(stack);
				//
			}
			return true;
			
		}
		else
		{
			System.out.println("The Key cannot be found! Try this again");
			return false;
		}
	}
	
	public void balanceBTree(Stack stack) throws Exception
	{
		BTreeNode parentNode = null;
		BTreeNode currentNode = null;
		BTreeNode newNode = null;
		BTreeNode leftNode = null;
		BTreeNode rightNode = null;
		
		BTreeData pivotData = new BTreeData();		// stack 가장 윗부분에 있는 node
		int index = 0;			// parentNode로부터 currentNode의 위치를 받을 변수
		int i= 0;
		
		currentNode = stack.pop();
		
		if(currentNode.elementCount >= 5/2)			// 만약 balance 유지할 필요가 없다면(1/2보다 크다)
			return;
		
		try
		{
			parentNode = stack.pop();					// 2번째 stack을 받는다(부모 노드)
		}
		catch(Exception e)			// 만약 부모노드에 아무것도 없다면 return한다.
		{
			return;
		}
		
		for(int j=0;i= ((5/2) + 1)))
		{
			borrowRightNodeBTree(parentNode,currentNode,index,parentNode.childNode[index+1]);
		}
		else if(index > 0 && (parentNode.childNode[index-1].elementCount >= ((5/2) + 1)))		// 왼쪼깅 다 많다면
		{
			// 여기는 왼쪽에서 빌린다.
			borrowLeftNodeBTree(parentNode,currentNode,index,parentNode.childNode[index+1]);
		}
		else		// 그렇지 않으면 merge한다.
		{
			mergeNodeBTree(stack,parentNode,currentNode,index);
		}
		
	}
	
	public void mergeNodeBTree(Stack stack, BTreeNode parentNode, BTreeNode currentNode, int index) throws Exception
	{
		BTreeNode leftNode = null;
		BTreeNode rightNode = null;
		BTreeData parentData = new BTreeData();
		BTreeNode parentParentNode = null;		//조상 노드.
		
		int i=0;
		int pivotIndex = 0;
		// 예외 처리 생략
		
		// 오른쪽으로 병합하는 경우
		if(index< parentNode.elementCount)
		{
			leftNode = currentNode;			// 현재노드가 left node가 되고
			rightNode = parentNode.childNode[index+1];	// 오른쪽 node는 parent의 오른쪽이 되고
			pivotIndex = index;				// pivot은 현재 index가 되고
			parentData = parentNode.data[pivotIndex];	// 그 데이터는 원래 index가 되고
		}
		else		// 왼쪽으로 합병하는 경우
		{
			leftNode = parentNode.childNode[index-1];
			rightNode  = currentNode;
			pivotIndex = index - 1;
			parentData = parentNode.data[pivotIndex];
		}
		insertDataBTree(leftNode, parentData, rightNode.childNode[0]);	// 0번째 요소에 왼쪽 data를 넣는다. 왼쪽에 parent 자료 추가
		
		for(i=0;i stack)
	{
		BTreeNode returnNode = null;
		BTreeData leafNodeData = new BTreeData();
		BTreeNode childNode = null;
		BTreeNode parentNode = deleteNode;
		int elementCount = index;
		do		// stack에 하나하나 다 쌓아둔다(나중에 balance를 유지할 때 필요하다)
		{
			childNode = parentNode.childNode[elementCount];		// parentNode의 삭제될 부분 뒤부터
			stack.push(childNode);		// 하나하나 씩 stack에 쌓아 논다.
			
			elementCount = childNode.elementCount;		// elementCount는 새로운 childNode의 elementCount가 되고 
			parentNode = childNode;		// 반복하여 수행한다.
			
		}while(childNode.childNode[elementCount] != null);
		
		leafNodeData = childNode.data[childNode.elementCount-1];		// 가장 오른쪽 끝에 있는걸 가져오고
		deleteNode.data[index] = leafNodeData;				// 삭제할 노드의 끝부분에다가 왼쪽끝의 요소를 대체한다.
		deleteKeyBTree(deleteNode, elementCount-1);			// 그리고 그 삭제될 바로 앞에 있는 요소를 삭제한다(원래 우리가 삭제하길 원했던 부분이다)
		returnNode = childNode;
		
		return returnNode;
	}
	
	
	public void deleteKeyBTree(BTreeNode parentNode, int index)		// 삭제 후 요소들을 한칸 씩 당기는 함수
	{
		int i=0;
		if(parentNode != null)
		{
			for(i = index + 1; i < parentNode.elementCount; i++)		// 앞으로 한칸 씩 떙긴다
			{
				parentNode.data[i-1] = parentNode.data[i];
				parentNode.childNode[i] = parentNode.childNode[i+1];
			}
			parentNode.data[parentNode.elementCount - 1] = null;		// 요소를 하나 삭제하고
			parentNode.childNode[parentNode.elementCount] = null;		// 역시 끝에 포인터도 null로 만든다.
			parentNode.elementCount--;									// 전체 요소의 개수를 줄이고
			
		}
		
	}
}


BTreeData.java

import java.io.*;

public class BTreeData 		// 데이터 부분
{
	public int key;
	public Object value; 
	BTreeData(int _key, Object _value)		// 2개의 부분으로 overloading 되어 있다.
	{
		key = _key;
		value = _value;
	}
	BTreeData()
	{
		key=0;
		value = null;
	}
}



BTreeNode.java

import java.io.*;



public class BTreeNode
{
	public BTreeNode childNode[];
	public BTreeData data[];
	public int elementCount;				// 총 Element Count가 있다.
	
	BTreeNode()
	{
		childNode = new BTreeNode[6];		// M-5 트리, 추가로 하나의 여유분을 둔다.. 우선 insert한후에 split하기 위해서
		data = new BTreeData[5];			
	}
	public void setData(int index, BTreeData TreeData)
	{
		data[index] = TreeData;
		
	}
}

mainFunction.java

import java.io.Console;
import java.util.Scanner;


public class mainFunction {

	public static void main(String args[]) throws Exception
	{
		BTree bt = new BTree();					// B-Tree 생성
		Scanner scan = new Scanner(System.in);	// Scanner 생성
		System.out.println("Welcome to B-Tree's world!!!!!");		
		int input=0;
		do
		{
			System.out.println("\n1. Input Data");				// Menu 출력
			System.out.println("2. Remove Data with Key value");
			System.out.println("3. Show B-Tree by post-order traversal method");
			System.out.println("Please Enter the menu number(Exit is 0)\n");	
			
			String temp = scan.nextLine();				// 입력받기
			try
			{
				input = Integer.valueOf((temp));		// switch 문을 위해서 변환을 해준다.
			}
			catch(Exception e)							// 예외 처리
			{
				System.out.println("Please enter the correct number please");
				continue;
			}
			
			switch(input)								
			{
			case 1:										// 1번은 insert function
				String temp1 = new String();
				String temp2 = new String();
				System.out.println("Please Enter the Key number");
				temp1 = scan.nextLine();
				System.out.println("Please Enter the Any String Data you want");
				temp2 = scan.nextLine();
				BTreeData tmpData = new BTreeData(Integer.valueOf(temp1),temp2);		// 입력받은 값을 가지고 data를 생성한다.
				if(bt.insert(tmpData))
					System.out.println("Successful!");
				else
					System.out.println("Failed");
				break;
			case 2:										// 2번은 remove function
				String tempRemoveKey = new String();
				System.out.println("Please Enter the key you want to remove from B-Tree");
				tempRemoveKey = scan.nextLine();
				if(bt.removeNode(Integer.valueOf(tempRemoveKey)))			// 삭제한다.
					System.out.println("Successful!");
				else
					System.out.println("Failed");
				break;
			case 3:						// 3번은 출력 
				System.out.println("\nThe B-Tree will be shown soon\n");
				bt.showBTree();				// 출력한다.
				break;
			case 0:						// 0은 프로그램 종료
				System.out.println("The program will be terminated");
				break;
			default:
				System.out.println("Please Enter correct number");
				break;
			}
		}while(input!=0);
		

	}
}


/*
BTreeData b1 = new BTreeData(69, "b1");			BTreeData b2 = new BTreeData(7, "b2");
BTreeData b3 = new BTreeData(150, "b3");		BTreeData b4 = new BTreeData(19, "b4");
BTreeData b5 = new BTreeData(70, "b5");		BTreeData b6 = new BTreeData(20, "b6");
BTreeData b7 = new BTreeData(128, "b7");		BTreeData b8 = new BTreeData(18, "b8");
BTreeData b9 = new BTreeData(42, "b9");		BTreeData b10 = new BTreeData(120, "b10");
BTreeData b11 = new BTreeData(140, "b11");		BTreeData b12 = new BTreeData(16, "b12");
BTreeData b13 = new BTreeData(100, "b13");		BTreeData b14 = new BTreeData(26, "b14");
BTreeData b15 = new BTreeData(145, "b15");		BTreeData b16 = new BTreeData(15, "b16");
BTreeData b17 = new BTreeData(110, "b17");		BTreeData b18 = new BTreeData(30, "b18");
BTreeData b19 = new BTreeData(40, "b19");		BTreeData b20 = new BTreeData(132, "b20");
BTreeData b21 = new BTreeData(138, "b21");		BTreeData b22 = new BTreeData(50, "b22");
BTreeData b23 = new BTreeData(43, "b23");		BTreeData b24 = new BTreeData(130, "b24");
BTreeData b25 = new BTreeData(136, "b25");		BTreeData b26 = new BTreeData(41, "b26");
BTreeData b27 = new BTreeData(59, "b27");		BTreeData b28 = new BTreeData(54, "b28");
BTreeData b29 = new BTreeData(122, "b29");		BTreeData b30 = new BTreeData(124, "b3o");


bt.insert(b1);		bt.insert(b2);		bt.insert(b3);		bt.insert(b4);	
bt.insert(b5);		bt.insert(b6);		bt.insert(b7);		bt.insert(b8);		
bt.insert(b9);		bt.insert(b10);		bt.insert(b11);		bt.insert(b12);		
bt.insert(b13);		bt.insert(b14);		bt.insert(b15);		bt.insert(b16);		
bt.insert(b17);		bt.insert(b18);		bt.insert(b19);		bt.insert(b20);
bt.insert(b21);		bt.insert(b22);		bt.insert(b23);		bt.insert(b24);	
bt.insert(b25);		bt.insert(b26);		bt.insert(b27);		bt.insert(b28);		
bt.insert(b29);		bt.insert(b30);

System.out.println("All datas have been inserted, it will be shown by post-order traversal");

bt.showBTree();		

System.out.println("Removing data........");


bt.removeNode(138);		bt.removeNode(50);		bt.removeNode(43);
bt.removeNode(130);		bt.removeNode(136);		bt.removeNode(41);
bt.removeNode(59);		bt.removeNode(54);		bt.removeNode(122);
bt.removeNode(124);

System.out.println("Removing task has been completed, now printing B-Tree");

bt.showBTree();		
*/


Posted by 박세범