Java List - 직접 구현해보기 3
다음으로 직접 만든 배열에 추가 기능을 만들어주도록 한다.
- add(Index, Data)
- add(Data) 메소드에서 오버로딩한다.
- Index 위치한 배열의 데이터를 추가하는 작업이다.
- remove(Index)
- Index 위치한 배열의 데이터를 삭제한다.
기존의 add() 메소드는 배열 마지막에 데이터 추가이므로 기존 데이터는 이동하지 않고 유지하였다. 그렇지만 추가 기능으로 배열 중간 또는 처음 배열 인덱스에 기존 데이터를 위치를 한 칸씩 움직이고 데이터를 추가하는 작업을 진행할 것이다. 구현이 복잡할 수 있다.
삭제도 마찬가지로 마지막 데이터를 삭제하고 기존 데이터를 이동하지 않았다. 중간에 있는 데이터 삭제 시 빈자리를 채우도록 기존 데이터 한 칸씩 왼쪽으로 이동한다.
add(data) 기존 로직
1. add("a")
"a"
↓
+---+---+---+---+---+
| a | ? | ? | ? | ? |
+---+---+---+---+---+
size = 1, capacity = 5
2. add("b")
"b"
↓
+---+---+---+---+---+
| a | b | ? | ? | ? |
+---+---+---+---+---+
size = 2, capacity = 5
3. add("c")
"c"
↓
+---+---+---+---+---+
| a | b | c | ? | ? |
+---+---+---+---+---+
size = 3, capacity = 5
- add() 사용해 데이터 추가 시 size 기준으로 마지막 부분만 이어서 추가하였다.
- 기존 데이터를 옮기지 않으므로 O(1) 속도로 추가된다.
신규 add, remove 동작 과정
신규 기능으로 add(index, data), remove(index) 동작 과정을 살펴보자
elementData 배열 상태
+---+---+---+---+---+
| a | b | c | ? | ? |
+---+---+---+---+---+
size = 3, capacity = 5
먼저 배열 데이터는 다음과 같이 size 3개에 a,b,c 각각 들어있는 상태로 확인해보자.
add() - 배열 마지막에 데이터 추가
1. add(3, "d")
"d"
↓
+---+---+---+---+---+
| a | b | c | ? | ? |
+---+---+---+---+---+
size = 4, capacity = 5
- index(3, "d") 사용해 원하는 위치로 데이터 추가하였다.
- 추가한 인덱스 우측에는 아무것도 없으므로 기존 데이터 옮기는 작업이 없다.
- O(1) 속도로 유지하고 있다.
add() - 배열 맨 앞에 데이터 추가
1. add(0, "e")
"e"
↓
+---+---+---+---+---+
| e | a | b | c | d |
+---+---+---+---+---+
size = 5, capacity = 5
- add(0, "e") 사용해 원하는 위치로 데이터 추가하였다.
- 먼저 데이터 손실이 발생되지 않도록 기존 데이터를 옮기는 작업을 한다.
- 모든 기존 데이터를 옮겼다면 원하는 인덱스 부분에 값을 삽입한다.
- O(n) 속도로 추가된다.
remove() - 배열 마지막에 데이터 삭제
1. remove(4)
"null"
↓
+---+---+---+---+---+
| e | a | b | c | d |
+---+---+---+---+---+
size = 5, capacity = 5
## Complate remove() ##
+---+---+---+---+---+
| e | a | b | c | ? |
+---+---+---+---+---+
size = 4, capacity = 5
- remove 사용으로 원하는 위치에 데이터를 삭제할 수 있다.
- 마지막 위치인 경우 기존 데이터를 옮길 필요가 없다.
- 삭제 완료 후 size를 감소한다.
- O(1) 속도로 삭제한다.
remove() - 배열 앞에 데이터 삭제
1. remove(0)
"null"
↓
+---+---+---+---+---+
| e | a | b | c | ? |
+---+---+---+---+---+
size = 4, capacity = 5
## Complate remove() ##
+---+---+---+---+---+
| a | b | c | ? | ? |
+---+---+---+---+---+
size = 3, capacity = 5
- remove 사용해 원하는 위치에 데이터를 삭제하였다.
- 마지막 위치가 아닌 데이터 위치 기준으로 데이터를 옮기는 작업이 필요하다.
- 데이터 이동에는 O(n) 요구된다.
- O(n)으로 표현된다.
add 메소드 추가
add() shiftRightForm(), remove(), shiftLeftForm() 메소드를 각각 추가한다.
add()
public void add(int index, Object e) {
// 코드 추가
if (size == elementData.length) {
grow();
}
// 데이터 이동
shiftRightForm(index);
elementData[index] = e;
size++;
}
- 데이터 이동에는 별도의 shiftRightForm 메소드로 처리한다.
shiftRightForm()
// 코드 추가 요소 마지막까지 데이터 밀기
private void shiftRightForm(int index) {
for (int i = size; i > index; i--) {
elementData[i] = elementData[i - 1];
}
}
- for문 초기값을 배열의 사이즈로 선택한다.
- 배열의 인덱스에서 앞에 있는 인덱스를 불려와 채우도록 한다.
remove()
// 코드 추가
public Object remove(int index) {
Object oldValue = get(index);
shiftLeftFrom(index);
// 데이터 이동
size--;
elementData[size] = null;
return oldValue;
}
- remove 에서는 변경의 set 했던 것과 유사한 코드이다. 배열에 할당 할 때에는 null 값으로 주어진다.
- shiftLeftFrom 에서 기존 데이터를 옮기는 작업이 있다.
shiftLeftForm()
// 코드 추가 요소의 index 부터 마지막까지 왼쪽으로 밀기
private void shiftLeftFrom(int index) {
for (int i = index; i < size - 1; i++) {
elementData[i] = elementData[i + 1];
}
}
- 삽입한 인덱스와 배열 사이즈 사이의 기존 데이터를 안으로 당겨줘야 한다.
테스트
Main.class
CList list = new CList();
System.out.println("** 데이터 추가하기 **");
list.add("a");
list.add("b");
list.add("c");
System.out.println(list);
System.out.println("** addLast **");
list.add(3, "addList");
System.out.println(list);
list.add(0, "addFirst");
System.out.println(list);
Object rev = list.remove(4);
System.out.println("removed(4) = " + rev);
System.out.println(list);
Object first = list.remove(0);
System.out.println("removed(0) = " + first);
System.out.println(list);
** 데이터 추가하기 **
[a, b, c], size = 3, capacity = 10
** addLast **
[a, b, c, addList], size = 4, capacity = 10
[addFirst, a, b, c, addList], size = 5, capacity = 10
removed(4) = addList
[addFirst, a, b, c], size = 4, capacity = 10
removed(0) = addFirst
[a, b, c], size = 3, capacity = 10
정리
지금까지 리스트 자료구조를 만들었고 내부 배열로(Array) 보관하여 부가기능을 추가해 편리하게 사용할 수 있었다.
배열 리스트의 빅오
- 데이터 추가
- 마지막 데이터 추가 O(1)
- 중간에 데이터 추가 O(n)
- 데이터 삭제
- 마지막 데이터 삭제 O(1)
- 중간에 데이터 삭제 O(n)
- 데이터 조회 O(1)
- 데이터 검색 O(n)
배열 리스트 마지막 부분을 추가하거나 데이터 삭제에는 O(1) 매우 빠르나 중간 데이터 추가에는 O(n) 만큼 느리다.
배열은 순서대로 출력하거나 삭제하는 것이 가장 빠르고, 만약 맨 앞의 데이터를 추가하거나 삭제할 경우 다른 자료구조에 비해 현저리 느려진다.