2015년 2월 25일 수요일

20150226 Scala start

Programming in Scala를 읽으면서
가~~끔 메모를 했는데
앞으로는 꾸준히 하기 위해서 기록을 남기기로 결정했다.

지금까지 메모 한 것을 뭉탱이로 던지고,
앞으로는 조금 정리해서 쓰도록 할 예정!



------------------------------------------------
스카라는 이뮤터블(final). 병행성 문제가 나타나지 않는다!
스카라는 statically typed 의 랭기쥐 이다.




unit function = retrun 타입이 void인것?!인듯?!

스칼라에 set, map은 immutable 과 mutable 이 있는데 immutable 이 기본이고 mutable을 사용하려면
scala.collection.mutable.HashMap
scala.collection.mutable.Map
등을 사용하자

import scala.collection.mutable.Map
val treasureMap = Map[Int, String]()
의 경우 factory method에 인자가 없으므로 타입을 [ ] 안에 명시해 줘야 하지만

val romanNumeral = Map(
1 >
"I", 2 >
"II", 3 >
"III", 4 >
"IV", 5 >
"V"
)
의 경우 factory method에 인자가 있으므로 스칼라 compiler 가 타입 추론을 하고 따라서 타입을 명시해줄 필요가 없다.

val형의 타입만 있는 경우가 바로 펑셔널 스타일이다!(즉 var가 없어야 한다 -> 모든게 final이다?!)

If you’re coming from an imperative background, such as Java, C++, or
C#, you may think of var as a regular variable and val as a special kind of
variable. On the other hand, if you’re coming from a functional background,
such as Haskell, OCaml, or Erlang, you might think of val as a regular variable
and var as akin to blasphemy.

하지만 스칼라는 val이나 var이나 모두 중요한 거라고 생각하니깐 이런 생각의 전환을 잘 하도록 한다.

스칼라의 side effect 는 해당 변수나 인자를 가지고 뚝딱하지 않으면 side effect 라고 부르는듯?
side effect :
def printArgs(args: Array[String]): Unit = {
args.foreach(println)
}

no side effect :
def formatArgs(args: Array[String]) = args.mkString("\n")


PIS 8.9 tail recursive
언뜻 이해가 되지 않아 이너넷 검색 후 결과를 남김

tail recursive는 외관상으로 차이가 이렇다
맨 마지막(결과?리턴?)값이 function() 이면 tail recursive
function() 외에 다른 연산?이 들어가면 그냥 재귀 ex) function()*2 등...
둘 중에 더 안정적이고 사용스러운?것은 tail recursive이다
이유는 그냥 재귀함수의 경우는 함수 호출시 스택에 push를 계속 하고 결과가 나와야 pop이 되어 스택에 새로운 함수가 계속 누적된다(스택오버 플로우가 날 수 있음)
하지만 tail recursive의 경우 부모 함수는 사라지고 자식함수를 호출하기 때문에 스택오버 플로우가 나지 않는다.
즉, 최초 부모 함수가 실행 된 후 재귀 구문을 만나면 함수는 사라지고 재귀함수가 부모가 된다
부모1 - 자식1
부모(자식1) - 자식2
부모(자식2) - 자식3 ...
최종 결과 값에 예외를 던지도록 해 보면 tail recursive인지 아닌지 알 수 있다.

2015년 2월 22일 일요일

20150223 Error updating database

### Error updating database. Cause: org.apache.ibatis.binding.BindingException: Parameter 'param1' not found. Available parameters are [1, 0, param1, param2]
### The error may involve xxx.mybatis.ContentsMapper.insertContents-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO table(param1, param2) values(?,?)
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'param1' not found. Available parameters are [1, 0, param1, param2]

이런 에러가 나면
mybatis 설정 xml에서
1.namespace나 alias 등을 유심히 살펴볼것 ( 내가만든 DO랑 alias의 이름 매치 등)

2.interface를 이용하는 경우 @Param을 이용하자!T_T

20150223 mysql 과 어노테이션 에러 : Parameter index out of range (1 > number of parameters, which is 0)

mysql 과 mybatis 를 이용해 보려고 이런식의 어노테이션을 사용했는데
@Select("SELECT * FROM table WHERE id like '%#{id}%'")


 Parameter index out of range (1 > number of parameters, which is 0)
에러를 만났다.

즉, 1개 이상의 파라메터를 넣었는데 니가 쓴 어노테이션에는 파라메터가 필요 없다!
는 말인것 같았다..

슬슬 깊은 빡침이 몰려왔고,,,

이리저리 구글링한 결과 concat이라는 함수를 알게 되었다.
그래서 이렇게 어노테이션 sql문을 바꿧더니...
@Select("SELECT * FROM table WHERE id like CONCAT('%', #{id}, '%')")

잘 되는것 같다...ㅡ.,ㅡ? ㅎ ㅔ ㅎ ㅔ

2015년 2월 16일 월요일

20150217 업무?

그런거 없다..
여전히 똑가탕....

5개월째 노는 신입입니다..ㅠㅠ

블로그를 다른 템플릿으로 바꿔봤어요..
이젠 이렇게 해서 꾸준히 또 한번 걸어봐야... ㅎㅎ

꾸준히 와 적당히는 참 힘들어용!!

20150109 우연히 알게된 사실.

작년 잉여생활을 할 때
14.8.27.. 우연히 google(GDG seoul) 세미나를 참석했었다.
그때 node.js 를 사용하신 분이 발표를 하셨었는데
오늘 알고보니 outsider님이셨다.. ㅡ,.ㅡ;;
나야 뭐 학원 출신의 비전공자로서 14년 1월 처음 컴터를 접한 뉴비여서... ㅎㅎ

어쨋거나 신기해서 남겨본다.
이제 다음주나 다다음주 부터 나도 업무라는 것의 맛뵈기를 탐방할 수 있겠지?
ㅎ ㅔㅎ ㅔ

20141230 채팅 프로그램 분해 조립...

--20150422
https://github.com/freenice12/ChatRoomForJAVABeginner
--

이 글은 앞으로 수정이 계속 되면서 길어질 예정임.ㅠㅠ
한 번에 쓰기에는 의외로 크기가 큰 클래스 들이 있음...

어떤 요구사항으로 만들어진 후로그램인지 이전 글에 설명 해놨음.

-- v.01

서버의 메인 메소드가 있는 클래스로
필드는 서버소켓과 각 클라이언트를 담당해줄 소켓 그리고 채팅방들과 클라이언트들을 담당해줄 메니저 클래스가 있다.
일단 채팅방을 만들 때 십여개의 클래스로 채팅방이 완성 되었다는 신기하고,
혼자만 쓰는게 아니고 다른 사람과 사용해보고 싶고 설치형 파일로 만들어 보고 싶지만
일단은 시간 관계상 이클립스 틴구의 도움을 받아 local에서만 실행할 수 있도록 함.


import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

// 로거로 상태를 체크
import org.apache.log4j.Logger;

public class ServerChat {
private ServerSocket serverSocket; // 서버용 소켓
private Socket clientSocket; // 클라이언트 담당 소켓
private ChatManager chatManager; // 채팅방, 클라이언트 담당 클래스


public ServerChat() {
chatManager = new ChatManager(); // 생성자에서 매니저 생성
}

public Socket getClientSocket() { // 클라이언트를 담당하는 스레드인 eachClientThread에서 사용할 게터
return clientSocket;
}

public ChatManager getChatManager() { // 클라이언트를 담당하는 스레드인 eachClientThread에서 사용할 게터
return chatManager;
}

private Logger logger = Logger.getLogger(this.getClass()); // Log4J 를 이용한 로깅

public static void main(String[] args) {
new ServerChat().serverRun();
}

private void serverRun() {
try {
serverSocket = new ServerSocket(5000);
logger.info("Server Running..."); // log4j 사용법은 매우 간단함
while (true) {
logger.info("Waiting for connection");
clientSocket = serverSocket.accept(); // 서버용 소켓이 클라이언트의 접속을 받음(블로킹)
logger.info("got a connection");
// 각 클라이언트별 스레드를 생성
// 차후에 위 블로킹과 클라이언트별 스레드생성을 하지 않고 nio를 이용한 채팅방으로 바꿀 고 싶음..ㅎㅎ
Thread eachClientThread = new Thread(new ClientController(this));
eachClientThread.start();
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}

}



}

20141211 Java 채팅 프로그램

--20150422
https://github.com/freenice12/ChatRoomForJAVABeginner
--

약 한 달간 작업했다.

아직도 리팩토링할 부분이 많지만 차차 리뷰해보도록 할 예정이다.

일단
... !! 특징 !!
을 쓰기전에 엄청나게 정교하게 설계를 하고 코드를 구현해야 리팩토링이 한결 쉬워진다는 것을 깨달았다.
클린 코드라는 책을 읽었는데, 30% 정도밖에 이해를 못했음에도 불구하고 많은 도움을 받았다.
1. byte Array 를 이용한 소켓 통신을 구현
  - 부가적으로 버퍼의 사용 이유와 byte array 를 이용해 저 수준의 통신을 구현할 수 있었음
  - 저 수준의 통신 구현 후에 Object...Stream을 통해서 Object를 주고 받는 통신을 구현
  - System.arraycopy 와 배열, String을 다루는 법을 많이 알게 되었음
  - 저 수준 통신 -> Object...Stream 으로 리팩토링 하면서 코드의 줄 수가 굉장히 줄어드는 마법을 경험
  - 일정부분 리팩토링 된 소스를 대체하는 과정은 생각보다 쉬웠고 위의 마법은 단지 30분 만에 일어났... ㄷㄷㄷ

  = 반면에 더 공부해야 할 부분은 java nio!

2. 프로토콜을 규정해 프로토콜로 통신을 했다고 생각함.(솔직히 이 부분은 아직도 가려움..ㅠㅠ)
  - Object...Stream을 사용하면서 프로토콜(?)을 읽고 해석하는 기능은 소멸됨ㅋ

3. Swing 을 이용한 GUI를 구현, 각종 기능들에 대해서 많이 찔끔 공부하였고,

4. 적어도 '내 생각'에는 "유니 캐스트, 멀티 캐스트, 브로드 캐스트"를 구현했다고 생각함
- 브로드 캐스트는 다른 개념이더구만요?!

5. 클래스 다이어그램을 작성했는데 이건 공부하면서 그린거라 잘 그린건지 모르겠음
  - 꽉찬 다이아, 텅빈 다이아, 상속, 구현 등 많은 것을 봤는데 용어가 기억 안나는 건 왜지?ㅠㅠ

등등 더 있겠지만,
이런 프로그램을 만들다 보니 욕심이 생겨서 기능도 추가하고, 곧 메신저도 만들어 보고싶고,
실행파일을 만들어서 서버를 설치해 실제로 돌아 가는지 시험해 보고 싶기도 하고,
누군가 쓸 수 있는 형태로 바꿔 설치해 주고 싶기도 하다.

어쨋든 일단 오늘은 폴더 2개의 압축 파일을 남겨본다.
주석은 없다. 쉽게 읽히도록 코드를 작성하려 노력했고 같은 느낌으로 리팩토링도 진행했다.
먼저 byte 어쩌고 하는 폴더가 프로토콜을 이용한 채팅 프로그램
object 어쩌고 하는 폴더가 프로토콜 날리고 오브젝트를 주고 받는 소스이다(간결).

라고 쓰고 게시물을 업데이트 했는데 파일을 추가할 수 없다.
차근차근 코드를 뜯고 씹으면서 게시물로 승화 시켜야겠다.



덧. 프로그램을 만들다가
ObjectInputStream과 ObjectOutputStream 을 사용할 때 황당? 한 블로킹이 됐다.
ObjectInputStream 을 먼저 사용하고
ObjectOutputStream 을 나중에 써주면 (서버와 클라이언트 모두 같은 순서)

서로 읽으려고 깝치면서 일종의 데드락? 이 걸리는 것 같았다.. 이런식으로 경험할 줄이야?
둘중의 하나를 ObjectOutputStream 이 먼저 오게 바꿔주면 해결이 된다.

그리고 그 이유는
http://ubuntuforums.org/showthread.php?t=1682680
여기서 찾았는데.

맞나 모르겄다~!
읽어보니 그런것 같기두?

20141123 목표?

일 시작한지 두 달이 되어간다.

그동안 공부만 했었는데, 내가 알고 있다고 생각한 것 중 제대로 알고 있는 것은 많지 않았다. 공부를 하면 할 수록 몰랐던 것은 더 많아지고 알아야 할 것은 더욱 많아졌다. 그리고 무언가 주제를 정하고 프로그램을 설계(혹은 코딩)하려고 하면, 내가 뭘 모르는지 모르는 상태가 되어 혼란 스럽다. 가끔은 사회 생활의 '접바둑'과 '다면기'에 짜증이 날 때도 있지만 그래도 묵묵히 걸어가고 있다. 

연애를 할 때는 모든 사랑노래가 내 이야기 같을 때가 있다. 지금의 나는 내 첫 인턴 시절을 떠올려 보면서 지금의 회사 생활을 곱씹어 보고 있다. 물론 감정에 차 있는 것 아니냐 할 수 있지만 절대 그렇지 않다고 확신한다. 왜냐면, 이미 인턴 시절에 겪었던 감정이니까.

무슨말을 하고 있는지도 모르겠다. 행복한 신혼생활에 어쩌면 즐거운 회사생활까지...
다 겪어가는...
최종 목표가 진짜 목표인지 모르겠지만, 그러기 위해서는 지금 기본기를 확실하게 닦아야 할 때인 것은 확실하다.

근데 그 목표가... 목표가... 사실 멀어지는 느낌은 왜 때문인지 모르겠다.
형! 우리 진짜 한 번 해봐요. 한 번 사는 세상인데!...ㅠㅠ

뭘 모르는지 모르기 때문에...
목표가 목표인지 모르기 때문에...

지금에 일단 충실하잡.

20141106 더블 링크드 리스트로 이진 검색 트리 구현

2014-11-10 리팩토링

이전에 망친거를 다시 복구함.

물론 고수의 눈에는 항상 망가져있음.

아...어렵다..

이런거 배우면서 대학생활 하신 분들은 정말 즐거웠을 듯?!
이라고 즐거운척 하면서 울어봅니다...

패키지는 빼고, 해보면 될껀데..

이제 스레드 돌려서 테스트 하는거 해봐야 하는데..
시작도 엄두가 안나는데
누가 힌트좀 줬으면 좋겠다...



package dataStructure3;

public class Node {
private Node parents;
private Integer data;
private Node leftChild;
private Node rightChild;

public Node() {
this.parents = null;
this.data = null;
this.leftChild = null;
this.rightChild = null;
}
public Node(Integer data) {
this();
this.data = data;
}
public Node getParents() {
return parents;
}
public void setParents(Node parents) {
this.parents = parents;
}
public Integer getData() {
return data;
}
public void setData(Integer data) {
this.data = data;
}
public Node getLeftChild() {
return leftChild;
}
public void setLeftChild(Node leftChild) {
this.leftChild = leftChild;
}
public Node getRightChild() {
return rightChild;
}
public void setRightChild(Node rightChild) {
this.rightChild = rightChild;
}

}
package dataStructure3;

public class DLLTree {
private Node root;

public DLLTree() {
this.root = null; 
}

public DLLTree(Node root) {
this();
this.root = root;
}

public Node getRoot() {
return root;
}

public void setRoot(Node root) {
this.root = root;
}
// 검색 - 데이터
public boolean searchData(int data){
return searchData(root, data);
}

private boolean searchData(Node node, int data) {
if(node == null){
return false;
}
if(data < node.getData()){
return searchData(node.getLeftChild(), data);
}
if(data > node.getData()){
return searchData(node.getRightChild(), data);
}
if(data == node.getData()){
return true;
}
return false;
}
// 삽입
public boolean insertData(int data){
if(searchData(data)){ // 같은 데이터는 삽입 불가
return false;
}
Node newNode = new Node(data);
return insertData(root, newNode, data);
}

private boolean insertData(Node node, Node newNode, int data) {
if(data < node.getData()){
if(node.getLeftChild() != null){
return insertData(node.getLeftChild(), newNode, data);
}else{
node.setLeftChild(newNode);
newNode.setParents(node);
return true;
}
}
if(data> node.getData()){
if(node.getRightChild() != null ){
return insertData(node.getRightChild(), newNode, data);
}else{
node.setRightChild(newNode);
newNode.setParents(node);
return true;
}
}
return false;
}
public boolean deleteData(int data){
if(data == root.getData()){
return false;
}
if(searchData(data)){
Node targetNode = searchNodeToDelete(data);
return deleteNode(targetNode);
}
return false;
}
// 검색 - 노드
private Node searchNodeToDelete(int data){
return searchNode(root, data);
}

private Node searchNode(Node node, int data) {
if(node == null){
return null;
}
if(data < node.getData()){
return searchNode(node.getLeftChild(), data);
}
if(data > node.getData()){
return searchNode(node.getRightChild(), data);
}
if(data == node.getData()){
return node;
}
return null;
}
private boolean deleteNode(Node node) {
// child = 0
if(node.getLeftChild() == null && node.getRightChild() == null){
if(node.getParents().getLeftChild() == node){
node.getParents().setLeftChild(null);
}else{
node.getParents().setRightChild(null);
}
node = null;
return true;
}
// child = 2
if(node.getLeftChild() != null && node.getRightChild() != null){
if(node.getParents().getLeftChild() == node){
node.getParents().setLeftChild(null);
}else{
node.getParents().setRightChild(null);
}
node.setParents(null);
insertData(root, node.getLeftChild(), node.getLeftChild().getData());
insertData(root, node.getRightChild(), node.getRightChild().getData());
return true;
}
// child = 1
if(node.getLeftChild() != null || node.getRightChild() != null){
if(node.getParents().getLeftChild() == node){
node.getParents().setLeftChild(null);
}else{
node.getParents().setRightChild(null);
}
if(node.getLeftChild() != null){
insertData(root, node.getLeftChild(), node.getLeftChild().getData());
}else{
insertData(root, node.getRightChild(), node.getRightChild().getData());
}
node = null;
return true;
}
return false;
}

}


public class DLLTree{
private Node root;

public DLLTree() {
this.root = null;
}

public DLLTree(Node root) {
this();
this.root = root;
}

public Node getRoot() {
return this.root;
}

public void setRoot(Node root) {
this.root = root;
}


// 검색 - 데이터
public boolean searchData(int data){
return searchData(this.root, data);
}

@SuppressWarnings("boxing")
private boolean searchData(Node node, int data) {
if(node == null){
return false;
}

if(data < node.getData()){
return searchData(node.getLeftChild(), data);
}
if(data > node.getData()){
return searchData(node.getRightChild(), data);
}
if(data == node.getData()){
return true;
}
return false;
}



// 삽입
@SuppressWarnings("boxing")
public boolean insertData(int data){
if(searchData(data)){ // 같은 데이터는 삽입 불가
return false;
}
Node newNode = new Node(data);
insertData(this.root, newNode, data);
return true;
}

@SuppressWarnings("boxing")
private void insertData(Node node, Node newNode, int data) {

if(data < node.getData()){
if(node.getLeftChild() != null){
insertData(node.getLeftChild(), newNode, data);
return ;
}
node.setLeftChild(newNode);
newNode.setParents(node);
return ;

}

if(node.getRightChild() != null ){
insertData(node.getRightChild(), newNode, data);
return ;
}
node.setRightChild(newNode);
newNode.setParents(node);
return ;


}

@SuppressWarnings("boxing")
public boolean deleteData(int data){
if(data == this.root.getData()){
System.out.println(data+" is rootData.");
return false;
}

if(searchData(data)){
Node targetNode = searchNodeToDelete(data);
return deleteNode(targetNode);
}
return false;
}

// 검색 - 노드
private Node searchNodeToDelete(int data){
return searchNode(this.root, data);
}

@SuppressWarnings("boxing")
private Node searchNode(Node node, int data) {
if(node == null){
return null;
}
if(data == node.getData()){
return node;
}

if(data < node.getData()){
return searchNode(node.getLeftChild(), data);
}
if(data > node.getData()){
return searchNode(node.getRightChild(), data);
}

return null;
}


@SuppressWarnings("boxing")
private boolean deleteNode(Node node) {
disconnectFromParentNode(node);
if(node.getLeftChild() != null){
insertData(this.root, node.getLeftChild(), node.getLeftChild().getData());
}
if(node.getRightChild() != null){
insertData(this.root, node.getRightChild(), node.getRightChild().getData());
}
deleteNodeself(node);
return true;
}

private static void disconnectFromParentNode(Node node){
if(node.getParents().getLeftChild() == node){
node.getParents().setLeftChild(null);
}else{
node.getParents().setRightChild(null);
}
node.setParents(null);
}

private static void deleteNodeself(Node node){
node.setParents(null);
node.setLeftChild(null);
node.setRightChild(null);
}
}


리펙토링.

20141031 protected vs default in java

Protected~ 너어~! ㅋㅋㅋㅋ

간만에 Bback hit...

 - protected와 default의 다른점
 = 디폴트는 해당 패키지 안에서 맴버 변수나 메소드에 접근할 수 있고 상속받을 수 있지만
   다른 패키지에서는 접근도 상속도 받을 수 없다
   하지만 protected로 지정된 멤버 변수가 있는 클래스를 상속받은 하위 클래스는
   다른 패키지에서도 protected로 지정된 메소드를 상속받아 오버라이딩 할 수 있다.

라는 걸 몇 줄로 설명된 책들이나 블로그들의 설명으론 이해가 안되서
엄청 고생했네....

"강이"의 강의는 진짜..... ㅎㄷㄷㄷㄷㄷㄷ
http://alecture.blogspot.kr/2011/05/access-modifier-public-protected-no.html

20141021 더블 링크드 리스트로 이진 검색 트리 구현

조만간 다시 부모가 한 개인 것을 만드러야 겠다.//2014.10.31

Implements BinarySearchTree using DoubleLinkedList;
내가 확실히 모르는 것
 1. 자료 구조
 2. 알고리즘
 3. Linked List
 4. Double Linked List
 5. Tree
 6. Binary Tree
 7. Java
 8. Exception(예외 처리)

임을 고려한 후 소스를 보면 소오름이 끼칠 것이다.
솔직히 맞는 지도 모르겠고, 이론적으로 적합하게 구현한지도 모르겠다.
그냥 이런게 아닐까 하고 만들어 본것.


그냥 DLL로는 어떻게 트리를 구현하나 찾다가 하도 안나와서 빡쳐서 만듬.
틀린거 있으면 누가좀 알려주세요!? ㅠㅠ
부모가 두개라니... 망했어...

/*
 * 트리 예 :
 *             10
 *       5           11
 *    3     7           12
 *         6 8
 *  
 */
위 트리 보고 구현해봄.

// 클래스 하나
public class DLLTreeNode {
DLLTreeNode leftP; // 좌측 부모
DLLTreeNode leftC; // 좌측 자손
int data; // 값
DLLTreeNode rightC; // 우측 자손
DLLTreeNode rightP; // 우측 부모
// 생성자
public DLLTreeNode(int data) {
this.data = data;
}
// Getter & Setter
public DLLTreeNode getLeftP() {
return leftP;
}
public void setLeftP(DLLTreeNode leftP) {
this.leftP = leftP;
}
public DLLTreeNode getLeftC() {
return leftC;
}
public void setLeftC(DLLTreeNode leftC) {
this.leftC = leftC;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public DLLTreeNode getRightC() {
return rightC;
}
public void setRightC(DLLTreeNode rightC) {
this.rightC = rightC;
}
public DLLTreeNode getRightP() {
return rightP;
}
public void setRightP(DLLTreeNode rightP) {
this.rightP = rightP;
}
}
// 클래스 둘

public class DLLTree {
DLLTreeNode root;

public DLLTree(int data) {
root = new DLLTreeNode(data);
}
// 트리가 잘 만들어 졌는지 확인용 메소드
public DLLTreeNode getLeftP() {
return root.getLeftP();
}
public DLLTreeNode getLeftC() {
return root.getLeftC();
}
public int getData() {
return root.getData();
}
public DLLTreeNode getRightC() {
return root.getRightC();
}
public DLLTreeNode getRightP() {
return root.getRightP();
}
// 확인용 끝
/**
 * <b>이진 검색 트리의 데이터 삽입</b><br>
 * 뿌리 노드의 값보다 작으면 왼쪽 크면 오른쪽 자식이 된다.<br>
 * 부모 노드에 대해서도 마찬가지 <br>
 * 
 * @param data : 삽입할 값을 입력
 */
public void insertData(int data){
if(root != null){
insertData(root, data);
}else{
return;
}
}
private void insertData(DLLTreeNode root, int data){
if(data < root.getData()){
if(root.getLeftC() != null){
insertData(root.getLeftC(), data);
}else{
DLLTreeNode insertNode = new DLLTreeNode(data);
root.setLeftC(insertNode);
insertNode.setRightP(root);
}
}else if(data > root.getData()){
if(root.getRightC() != null){
insertData(root.getRightC(), data);
}else{
DLLTreeNode insertNode = new DLLTreeNode(data);
root.setRightC(insertNode);
insertNode.setLeftP(root);
}
}else{
System.out.println("에러 :+: 같은 값은 입력 ㄴㄴ");
return;
}
}
/**
 * <b>이진 검색 트리의 데이터 삭제</b><br>
 * 뿌리 노드의 값보다 작으면 왼쪽 크면 오른쪽 자식을 검색<br>
 * 해당 노드를 찾을 때 까지 검색 후 삭제 <br>
 * 
 * 1. 자식이 둘 다 없을 때 : 해당 노드 부모의 자식 노드를 null로 set 후 해당 노드의 부모 노드를 null로 set<br>
 * 2. 자식이 둘 다 있을 때 : 해당 노드 부모의 자식 노드를 null로 set 후 자식 노드들을 다시 트리에 삽입(작은 것 부터)<br>
 * 3. 자식이 한 쪽만 있을 때 : 해당 노드의 부모 노드를 해당노드의 자식 노드로 set 후 해당 노드의 자식 노드의 부모 노드를 해당 노드의 부모 노드로 set<br>
 * 
 * @param data : 삭제할 값을 입력
 */
public void deleteData(int data){
if(root != null){
deleteData(root, data);
}else{
return ;
}
}
private void deleteData(DLLTreeNode root, int data){
if(data < root.getData()){
deleteData(root.getLeftC(), data);
}else if(data > root.getData()){
deleteData(root.getRightC(), data);
}else{
if(root.getLeftC() == null && root.getRightC() == null){
if(root.getRightP() != null){
root.getRightP().setLeftC(null);
root.setRightP(null);
}else if(root.getLeftP() != null){
root.getLeftP().setRightC(null);
root.setLeftP(null);
}
}else if(root.getLeftC() != null && root.getRightC() != null){
if(root.getRightP() != null){
DLLTreeNode left = root.getLeftC();
DLLTreeNode right = root.getRightC();
root.getRightP().setLeftC(null);
root.setRightP(null);
insertDataAfterDelete(root, left);
insertDataAfterDelete(root, right);
}else if(root.getLeftP() != null){
DLLTreeNode left = root.getLeftC();
DLLTreeNode right = root.getRightC();
root.getLeftP().setRightC(null);
root.setLeftP(null);
insertDataAfterDelete(root, left);
insertDataAfterDelete(root, right);
}
}else if(root.getLeftC() != null && root.getRightC() == null){
if(root.getRightP() != null){
if(root.getLeftC() != null){
root.getRightP().setLeftC(root.getLeftC());
root.getLeftC().setRightP(root.getRightP());
}else{
root.getLeftP().setRightC(root.getLeftC());
root.getLeftC().setLeftP(root.getLeftP());
}
}else if(root.getLeftP() != null){
if(root.getRightC() != null){
root.getLeftP().setRightC(root.getRightC());
root.getRightC().setLeftP(root.getLeftP());
}else{
root.getLeftP().setRightC(root.getLeftC());
root.getLeftC().setLeftP(root.getLeftP());
}
}
}else{
if(root.getRightP() != null){
if(root.getLeftC() != null){
root.getRightP().setLeftC(root.getLeftC());
root.getLeftC().setRightP(root.getRightP());
}else{
root.getRightP().setLeftC(root.getRightC());
root.getRightC().setRightP(root.getRightP());
}
}else if(root.getLeftP() != null){
if(root.getRightC() != null){
root.getLeftP().setRightC(root.getRightC());
root.getRightC().setLeftP(root.getLeftP());
}else{
root.getLeftP().setRightC(root.getLeftC());
root.getLeftC().setLeftP(root.getLeftP());
}
}
}
}
}
// 자식이 모두 있을 때 다시 루트에 삽입하는 메소드
private void insertDataAfterDelete(DLLTreeNode root, DLLTreeNode subNode) {
if(subNode.getData() < root.getData()){
if(root.getLeftC() != null){
insertDataAfterDelete(root.getLeftC(), subNode);
}else{
root.setLeftC(subNode);
subNode.setRightP(root);
}
}else{
if(root.getRightC() != null){
insertDataAfterDelete(root.getRightC(), subNode);
}else{
root.setRightC(subNode);
subNode.setLeftP(root);
}
}
}

/**
 * <b>이진 검색 트리의 데이터 검색</b><br>
 * 뿌리 노드의 값보다 작으면 왼쪽 크면 오른쪽 자식을 검색<br>
 * 해당 값을 찾을 때 까지 검색 후 노드를 리턴 <br>
 * <br>
 * 모든 검색 후 해당 값을 찾으면 경로를 출력<br>
 * or Print 'Cannot found'
 * 
 * @param data : 검색할 값을 입력
 */
public void searchData(int data){
if(root != null)
searchData(root, data);
else
System.out.println(":+: null :+:");
if(isThere)
System.out.println(path.toString());
}
StringBuffer path = new StringBuffer("path : ");
boolean isThere = true;
private void searchData(DLLTreeNode root, int data) {
if(data < root.getData()){
if(root.getLeftC() != null){
path.append("("+root.getData()+") LeftC -> ");
searchData(root.getLeftC(), data);
}else{
System.out.println("값 읎음");
isThere = false;
}
}else if(data > root.getData()){
if(root.getRightC() != null){
path.append("("+root.getData()+") RightC -> ");
searchData(root.getRightC(), data);
}else{
System.out.println("값 없음");
isThere = false;
}
}else{
path.append(root.getData()+" found! ");
}
}
}

// 실험해본 main 클래스



public class DLLTreeTest {
/*
 * 트리 예 :
 *             10
 *       5           11
 *    3     7           12
 *         6 8
 *  
 */
public static void main(String[] args) {
DLLTree root = new DLLTree(10);
root.insertData(5);
root.insertData(3);
root.insertData(7);
root.insertData(6);
root.insertData(8);
root.insertData(11);
root.insertData(12);
// root.deleteData(8);
root.deleteData(11);
root.searchData(8);
// System.out.println(root.getLeftC().getRightC().getRightC().getData());
// System.out.println(root.getRightC().getData());
// System.out.println(root.getRightC().getRightC().getData());
}

}