* 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);