java arraylist 구현해보기
array list는 java에서 가장 많이 쓰이는 자료구조라고 전해져오고 있습니다.
우선 컬렉션으로 실습해보는 단계는 이 곳에서 이미 실습해보았으므로, 오늘은 클래스로 직접 구현하여 알아보겠습니다.
특징
array의 특성으로 인해 인덱싱을 할 때 속도가 빠릅니다. 다만, linked list처럼 서로 연결되있는 게 아니라 메모리에 서로 array로 연결되어있습니다.
구현
class
public class Arraylist {
private Object e_data[] = new Object[100];
먼저 private으로 해당 클래스에서만 사용하는 오브젝트 타입의 배열을 100의 크기로 생성합니다.
private int size = 0;
그리고 크기를 구하기 위한 private 변수를 만듭니다.
해당 변수는 변조를 막기위해 getter로만 얻어갈 예정입니다.
public boolean add_last(Object e){
e_data[size] = e;
size ++;
return true;
}
맨 뒤 배열에 값을 추가하는 메소드를 구현했습니다.
인자로 받은 오브젝트 타입의 e를 현재 크기, 즉 마지막 위치의 배열에 추가해줍니다.
그리고 추가해준 그 뒤의 값으로 증가 연산합니다.
public boolean add(int index, Object e) {
for(int i = size-1; i >= index;i--) {
e_data[i+1] = e_data[i];
}
e_data[index] = e;
size++;
return true;
}
원하는 위치에 값을 추가하려면 for문으로 마지막 값을 i로 잡고 원하는 위치까지 증감 연산을 이용하여 수행합니다.
array, 즉 배열의 특성상 중간에 값을 넣으려면 그 뒤에 존재하는 모든 값들을 한 칸씩 미뤄야 되기 때문에 마지막 칸부터 +1로 대입해줍니다.
for문이 끝나게 되면 원하는 위치는 비어있으므로, 오브젝트 타입의 e를 대입해줍니다.
마지막으로 크기가 메소드를 실행하기전에 보다 한칸 증가했으므로 증가 연산을 사용하여 한 칸을 증가시킵니다.
public boolean add_first(Object e) {
return add(0, e);
}
처음에 값을 넣는 것도 생각해보면 첫번째의 위치가 0이므로, add() 메소드를 사용하여 리턴해주면 됩니다.
@Override
public String toString() {
String text = "[";
for (int i = 0; i < size; i++) {
text += e_data[i];
if(i< size-1)
text += ",";
}
return text + "]";
}
기존의 toString 메소드는 arraylist의 값을 나타내지 못하므로 기존의 메소드를 오버라이딩합니다.
for문으로 string에 += 하여 값을 붙혀줍니다.
public boolean remove(int index) {
for(int i = index + 1;i<=size-1;i++ ) {
e_data[i-1] = e_data[i];
}
size--;
e_data[size] = null;
return true;
}
원하는 위치의 값을 제거하는 메소드립니다.
for문으로 삭제를 원하는 위치의 다음 인덱스를 이전 인덱스로 대입합니다.
이 작업을 마지막 값의 위치까지 진행합니다.
그리고 크기를 증감 연산으로 한 칸 줄입니다.
마지막 값을 null로 채워서 없앱니다.
public boolean remove_first() {
return remove(0);
}
처음 값을 없앨 때는 이전의 remove 메소드를 이용하여 0번째 값을 지워줍니다.
public boolean remove_last() {
return remove(size -1 );
}
마지막 값도 첫번째 값처럼 해줍니다.
public Object get(int index) {
return e_data[index];
}
getter를 만들어서 해당 위치에 있는 값을 구해줍니다.
public int size() {
return size;
}
크기도 size 변수가 private 변수이므로 getter를 만들어줍니다.
public int indexOf(Object e) {
for(int i =0; i<size; i++) {
if(e.equals(e_data[i])){
return i;
}
}
return -1;
}
for문을 이용하여 0부터 배열의 마지막 값까지 원하는 오트젝트 타입의 값을 비교해서 찾으면 위치를 반환해줍니다.
못찾으면 음수를 반환합니다.
public Iterator iterator() {
return new Iterator();
}
iterator, 즉 (한국어로) 반복자를 만들어줍니다.
새로운 반복자를 생성해줍니다.
iterator()를 실행하면 새로운 반복자가 반환되므로 메인 메소드에서 Iterator 타입의 변수에 넣어주면 됩니다.
class Iterator{
private int next_i =0;
private 변수로 0으로 초기화 해줍니다.
public Object next() {
Object return_val = e_data[next_i];
next_i++;
return return_val;
}
다음 수를 리턴해줍니다.
시작점이 0이므로 먼저 배열의 0번째 수를 리턴 값에 넣고 위에 선언된 변수를 증가 연산하여 1을 더해줍니다.
이렇게 또 다시 next() 메소드를 불러오면 그 다음의 수를 불러오게 됩니다.
public boolean hasnext() {
return next_i < size;
}
다음의 수가 있는지 검사합니다.
배열의 크기보다 진행된 위치가 앞에 존재하면 true입니다.
public Object prev() {
next_i--;
Object return_val = e_data[next_i];
return return_val;
}
이전 수를 리턴해줍니다.
먼저 다음 수의 변수를 감소시키고, 그 감소된 변수의 수에 위치한 배열의 값을 오브젝트 타입의 변수에 대입해주고 리턴합니다.
public boolean hasprev() {
return next_i > 0;
}
hasnext() 메소드와 비슷하게 0보다 크면 true입니다.
public boolean add(Object e) {
Arraylist.this.add(next_i, e);
next_i++;
return true;
}
반복자가 수형한 위치에 추가하려면 다음 수의 위치를 지정한 변수를 활용합니다.
그리고 추가했으니 다음 수의 위치도 증가시킵니다.
public boolean remove() {
Arraylist.this.remove(next_i-1);
next_i--;
return true;
}
}
}
삭제도 위와 비슷합니다.
main
public class Main {
public static void main(String[] args) {
Arraylist test = new Arraylist();
위에서 직접 구현한 Arraylist의 객체를 생성합니다.
test.add_last(10);
test.add_last(20);
test.add_last(30);
test.add_last(50);
마지막에 추가하므로 [10,20,30,50]
이 됩니다.
test.add(3,40);
3번째 위치에 추가하므로 [10,20,30,40,50]
이 됩니다.
test.add_first(0);
System.out.println(test.toString());
첫번째에 추가하므로 [0,10,20,30,40,50]
가 되고, 출력하게 됩니다.
test.remove(4);
System.out.println(test.toString());
4번째를 삭제하게 되므로 [0,10,20,30,50]
가 되고 출력하게 됩니다.
test.remove_first();
System.out.println(test.toString());
첫번째를 삭제하게 되므로 [10,20,30,50]
가 되고 출력하게 됩니다.
test.remove_last();
System.out.println(test.toString());
마지막을 삭제하게 되므로 [10,20,30]
가 되고 출력하게 됩니다.
System.out.println(test.get(0));
System.out.println(test.get(1));
System.out.println(test.get(2));
각 위치의 값을 출력하게 됩니다.
다만, 위와 같이 반복적으로 코딩하는 것보다 for문이나 while문으로 작성하는 것이 좋습니다.
System.out.println(test.size());
이 Arraylist의 객체 크기를 구합니다.
System.out.println(test.indexOf(30));
30이 어느 위치에 있는지 구합니다.
이 코드 같은 경우 2라고 표시하게 됩니다.
Arraylist.Iterator it = test.iterator();
iterator, 즉 반복자를 생성합니다.
iterator() 메소드를 실행하여 Iterator 클래스 타입의 메소드에 접근할 수 있는 반복자 객체를 생성합니다.
System.out.println(it.hasnext());
System.out.println(it.next());
System.out.println(it.hasnext());
System.out.println(it.next());
System.out.println(it.hasnext());
System.out.println(it.next());
System.out.println(it.hasnext());
System.out.println(it.next());
다음 위치에 수가 있는지 판별하고 다음 수를 출력합니다.
이렇게 코딩하는 것보다 while(it.hasnext())
로 반복시켜주는게 좋습니다.
System.out.println(it.hasprev());
System.out.println(it.prev());
System.out.println(it.hasprev());
System.out.println(it.prev());
System.out.println(it.hasprev());
System.out.println(it.prev());
System.out.println(it.hasprev());
System.out.println(it.prev());
System.out.println(it.hasprev());
이 역시 이렇게 코딩하는 것보다 while(it.hasprev())
로 반복시켜주는게 좋습니다.
it.add(100);
System.out.println(test.toString());
반복자가 수행한 위치에 100을 추가시켜줍니다.
지금 이 코드에는 next와 prev가 수행되며 0번째 위치로 다시 돌아왔기 때문에 0번째에 들어가게 됩니다.
it.remove();
System.out.println(test.toString());
}
}
0번째 그대로에서 삭제해주면 위에 추가한 100이 삭제됩니다.