✅네이버클라우드 캠프/개발일기

[네이버클라우드캠프] 38일차. 자바 LinkedList와 Node, 인터페이스 규격

우동한그릇 2023. 6. 19. 16:56
반응형

 

 

* ArrayList vs LinkedList

추가/삭제

LinkedList의 장점은 해당 값을 찾은 후 노드 추가/삭제를 하기 때문에

ArrayList보다 빠른 장점이 있다.

 

조회

조회에서는 ArrayList가 인덱스로 조회하기 때문에 LinkedList 보다 빠르다.


* LinkedList - add()

 

 

실습예시)

LinkedList 클래스와 add 메소드 이해하기 (node 사용)

package bitcamp.util;

public class LinkedList {
  Node tail;

  public void add(Object value) {
    Node node = new Node();
    node.value = value;

    if (tail != null) {
      tail.next = node;
    }
    tail = node;
    // 1. 새 노드를 생성한다.
    // 2. 새 노드에 값 저장
    // 3. 리스트의 마지막 노드에 새 노드를 연결
  }
}

 

주어진 코드는 Java에서 단일 연결 목록의 단순화된 구현을 나타낸다.

LinkedList 클래스에는 목록의 마지막 노드를 가리키는 테일 노드에 대한 참조가 있다.

add(객체 값) 메서드는 지정된 값을 가진 새 노드를 연결 목록 끝에 추가하는 데 사용된다.

add 메서드의 작동 방식에 대한 분석 :


1. 새 Node 개체를 만들고 로컬 변수 "node"에 할당

 

Node node = new Node();


2. 새 노드의 값을 지정된 값으로 설정

node.value = value;

 


3. 목록이 비어 있지 않음을 나타내는 꼬리 노드가 null이 아닌지 확인

    목록이 비어 있지 않으면 현재 꼬리 노드의 "다음" 참조를 새 노드로 설정

if (tail != null) {
  tail.next = node;
}


4. 이제 목록의 마지막 노드이므로 새 노드를 가리키도록 꼬리 참조를 업데이트

tail = node;

 

이 구현은 각각의 새 노드가 삽입 순서를 유지하면서 연결된 목록의 끝에 추가되도록 한다.

 


* LinkedList - getList 

LinkedList로 ArrayList를 대체하려면,

우선 기존 ArrayList의 객체는 LinkedList로 바꿔주어야한다.


BoardHandelr 에 있는 printBoards 메소드 LinkedList 적용

 

BoardHandelr 에 있는 printBoards 메소드를 실행하기 위해서 

LinkedList 안에 있는 getList라는 메소드를 생성해주어야한다.

 

  private void printBoards() {
    System.out.println("---------------------------------------");
    System.out.println("번호, 제목, 작성자, 조회수, 등록일");
    System.out.println("---------------------------------------");

    Object[] arr = this.list.getList();
    for (Object obj : arr) {
      Board b = (Board) obj;
      System.out.printf("%d, %s, %s, %d, %tY-%5$tm-%5$td\n", b.getNo(), b.getTitle(), b.getWriter(),
          b.getViewCount(), b.getCreatedDate());
    }
  }
  public Object getList() {
    Object[] arr = new Object[this.size];

    Node node = this.head;
    for (int i = 0; i < this.size; i++) {
      arr[i] = node.value;
      node = node.next;
    }
    return arr;
  }

BoardHandelr 에 있는  viewBoard 메소드 LinkedList 적용

BoardHandelr 에 있는 viewBoard 메소드를 실행하기 위해서

LinkedList 안에 있는 retrieve라는 메소드를 생성해주어야한다.

 

  private void viewBoard() {
    int boardNo = this.prompt.inputInt("번호? ");

    Board board = (Board) this.list.retrieve(new Board(boardNo));
    if (board == null) {
      System.out.println("해당 번호의 게시글이 없습니다!");
      return;
    }

    System.out.printf("제목: %s\n", board.getTitle());
    System.out.printf("내용: %s\n", board.getContent());
    System.out.printf("작성자: %s\n", board.getWriter());
    System.out.printf("조회수: %s\n", board.getViewCount());
    System.out.printf("등록일: %tY-%1$tm-%1$td\n", board.getCreatedDate());
    board.setViewCount(board.getViewCount() + 1);
  }
  public Object retrieve(Object value) {
    Node cursor = this.head;

    while (cursor != null) {
      if (cursor.value.equals(value)) {
        return cursor.value;
      }
      cursor = cursor.next;
    }
    return null;
  }

BoardHandelr 에 있는  deleteBoard 메소드 LinkedList 적용

BoardHandelr 에 있는 deleteBoard 메소드를 실행하기 위해서

LinkedList 안에 있는 remove 라는 메소드를 생성해주어야한다.

 

이 경우, 삭제할 노드가 중간노드,끝노드,처음노드 일 경우마다 고려해주어야한다.

 

[코드]

  private void deleteBoard() {
    if (!this.list.remove(new Board(this.prompt.inputInt("번호? ")))) {
      System.out.println("해당 번호의 게시글이 없습니다!");
    }
  }
  public boolean remove(Object value) {
    Node prev = null;
    Node cursor = this.head;

    while (cursor != null) {
      if (cursor.value.equals(value)) {
        if (prev == null) {
          // 삭제할 노드가 시작 노드라면
          head = cursor.next;

          // 삭제할 노드가 끝 노드라면
          if (head == null) {
            tail = null;
          }

        } else if (cursor.next == null) {
          // 삭제할 노드가 끝 노드라면
          tail = prev;
          tail.next = null;

        } else {
          // 중간 노드라면, 다음 노드의 주소를 이전 노드에 저장한다.
          prev.next = cursor.next;
        }
        size--;

        // 가비지 객체를 초기화시켜서 가비지가 인스턴스를 가리키지 않도록 한다.
        cursor.next = null;
        cursor.value = null;

        return true;
      }

      // 현재 커서가 가리키는 노드를 prev에 보관한다.
      prev = cursor;

      // 현재 커서를 다음 노드로 이동한다.
      cursor = cursor.next;
    }

    return false;
  }

 

 

#(중간노드) deleteBoard 메소드 LinkedList 적용 

이부분이 특히 중요하다. 최근의 자바의 가비지 콜렉터는 이러한 경우에도

청소를 하지만, 알고 있는 것이 중요하다.

        // 가비지 객체를 초기화시켜서 가비지가 인스턴스를 가리키지 않도록 한다.
        cursor.next = null;
        cursor.value = null;

 

#(끝노드) deleteBoard 메소드 LinkedList 적용 

삭제할 노드가 끝 노드라면 tail이 가리키는 노드를 바꾸어 줄 필요가 있다.

 

이 부분을 추가해주어서 삭제 할 노드가 끝 노드일때, tail 값을 이전 노드로 옮겨주도록 해야한다.

else if (cursor.next == null) {
          // 삭제할 노드가 끝 노드라면
          tail = prev;
          tail.next = null;

 

#(시작노드) deleteBoard 메소드 LinkedList 적용 

삭제할 노드가 시작 노드라면 tail이 가리키는 노드를 바꾸어 줄 필요가 있다.

 

이 부분을 추가해주어서 삭제할 노드가 시작 노드일때, tail 값을 다음 노드로 옮겨주도록 해야한다.

        if (prev == null) {
          // 삭제할 노드가 시작 노드라면
          head = cursor.next;

 

#(시작이면서 끝노드) deleteBoard 메소드 LinkedList 적용 

삭제할 노드가 시작이면서  노드라면 tail이 가리키는 노드를 바꾸어 줄 필요가 있다.

        if (prev == null) {
          // 삭제할 노드가 시작 노드라면
          head = cursor.next;

          // 삭제할 노드가 끝 노드라면
          if (head == null) {
            tail = null;
          }

 


 

List를 통해 인터페이스 규격을 추가한다.

package bitcamp.util;

public interface List {
  boolean add(Object value);

  Object get(int index);

  Object[] toArray();

  Object remove(int index);

  boolean remove(Object value);

  int size();
}

 

 

 

리팩토링

Object[] arr = this.list.toArray();

for (Object obj : arr) {

Member m = (Member) obj;
for (int i = 0; i < list.size(); i++) {

Member m = (Member) this.list.get(i);
반응형