*참고: Java SE 17 기준 API Docs

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ArrayList.html#method-summary

 

 

 

Field

  • elementData : 내부적으로 요소를 저장하기 위한 배열
  • size : 현재 ArrayList에 저장된 요소의 수
  • modCount

Constructor

  • ArrayList(): 기본 생성자 - 초기 용량 10
  • ArrayList(int initialCapacity) : 입력값으로 초기 용량 설정

Method

CRUD 추가(add)
  • boolean add(E e): 리스트의 끝에 요소를 추가합니다.
  • void add(int index, E element): 지정한 위치에 요소를 추가합니다.
O(1)
단, 용량 초과시 O(n)
접근(get)
  • E get(int index): 지정한 인덱스의 요소 반환
O(1)
수정(set)
  • E set(int index, E e): 지정한 인덱스의 요소를 새로 수정
 
제거(remove)
  • boolean remove(Object o): 지정한 요소를 제거합니다.
  • E remove(int index): 지정한 인덱스의 요소를 제거하고 반환합니다.
O(n)
제거 후 요소 이동 필요
기타 크기 반환
  • int size(): 리스트에 저장된 요소의 수를 반환합니다.
 
 
  • boolean isEmpty()
 
 
  • boolean contains(Object o): 리스트에 지정한 요소가 포함되어 있는지 확인합니다.
 
오버라이드 메소드  
  • String toString()
 
 
  • Iterator<E> iterator()
 

 


Field
// Field
private Object[] elementData;   // 내부적으로 요소를 저장하기 위한 배열
private int size;               // 현재 ArrayList에 저장된 요소의 수
private int arraySize = 10;     // default값 10

 

Constructor
// 기본 생성자 - 초기 용량 10
public __ArrayList() {
    elementData = new Object[arraySize]; //
}

// 커스텀 생성자 - 입력값으로 초기 용량 설정
public __ArrayList(int initialCapacity) {
    this.arraySize = initialCapacity;   // arraySize 초기화
    elementData = new Object[initialCapacity];
}

 

boolean add(E e)
// C - add
public boolean add(E e) {
    // Case 1 : elementData 배열에 빈 공간이 있다면
    if (size < arraySize) {
        elementData[size] = e;
        size++;
        return true;
    }

    // Case 2 : 배열에 남은 공간이 없다면
    // (1) 배열 크기 2배로 확장
    arraySize *= 2;

    // (2) 기존 요소 옮겨 담기
    Object[] tempArr = new Object[arraySize]; // 옮겨 담을 어레이
    for (int i=0; i<size; i++) {    // 반복 조건: 현재 존재하는 요소 개수만큼
        tempArr[i] = elementData[i];
    }

    // (3) 그 다음 위치에 새 요소 삽입
    tempArr[size] = e;  // 첫번째 실행이라면 10번째에 넣고
    size++;             // 그 다음부터 11번째, 12번째 ...

    // (4) 새로운 배열을 elementData로 설정
    elementData = tempArr;
    return true;
}

 

E get(int index)
// R - get
public E get(int index) {
    // 인덱스 범위 검사
    if(index < 0 || index >= size) {
        throw new ArrayIndexOutOfBoundsException("인덱스의 범위를 벗어났습니다.");
    }
    // 반환 (Object -> 제네릭 타입으로)
    return (E)elementData[index];
}

 

E set(int index, E e)
// U - set
public E set(int index, E e) {
    // 인덱스 범위 검사
    if(index < 0 || index >= size) {
        throw new ArrayIndexOutOfBoundsException("인덱스의 범위를 벗어났습니다.");
    }

    // 반환할 E: 수정되기 전의 요소
    E prev = (E) elementData[index]; // 임시저장

    // 새로운 E로 해당 인덱스의 값 수정
    elementData[index] = e;

    // 반환
    return prev;
}

 

E remove(int index)
// D - remove
public E remove(int index) {
    // 인덱스 범위 검사
    if(index < 0 || index >= size) {
        throw new ArrayIndexOutOfBoundsException("인덱스의 범위를 벗어났습니다.");
    }

    // 삭제될 타겟 요소 임시 저장
    E prev = (E) elementData[index];

    // 인덱스 땡겨주기
    for (int i = index; i< size -1; i++) {
        elementData[i] = elementData[i+1];  // 덮어쓰기
    }

    elementData[size-1] = null; // 맨 마지막 요소는 수동으로 삭제
    size--;     // 전체 요소 크기 줄여주기

    return prev;    // 삭제된 요소 반환
}

 

Iterator<E> iterator()
// Iterable 인터페이스 - 메소드 구현
@Override
public Iterator<E> iterator() {
    // 익명클래스 방식
    return new Iterator<E>() {
        private int pointer;

        @Override
        public boolean hasNext() {
            return pointer < size();
        }

        @Override
        public E next() {
            E e = get(pointer);
            pointer++;
            return e;
        }
    };
}

 

 

전체 코드
import java.util.Arrays;
import java.util.Iterator;

public class __ArrayList<E> implements Iterable<E> {
    // Field
    private Object[] elementData;   // 내부적으로 요소를 저장하기 위한 배열
    private int size;               // 현재 ArrayList에 저장된 요소의 수
    private int arraySize = 10;     // default값 10

    // 기본 생성자 - 초기 용량 10
    public __ArrayList() {
        elementData = new Object[arraySize]; //
    }

    // 커스텀 생성자 - 입력값으로 초기 용량 설정
    public __ArrayList(int initialCapacity) {
        this.arraySize = initialCapacity;   // arraySize 초기화
        elementData = new Object[initialCapacity];
    }

    // size()
    public int size() {
        return this.size;
    }

    // isEmpty()
    public boolean isEmpty() {
        return this.size == 0;
    }

    // C - add
    public boolean add(E e) {
        // Case 1 : elementData 배열에 빈 공간이 있다면
        if (size < arraySize) {
            elementData[size] = e;
            size++;
            return true;
        }

        // Case 2 : 배열에 남은 공간이 없다면
        // (1) 배열 크기 2배로 확장
        arraySize *= 2;

        // (2) 기존 요소 옮겨 담기
        Object[] tempArr = new Object[arraySize]; // 옮겨 담을 어레이
        for (int i=0; i<size; i++) {    // 반복 조건: 현재 존재하는 요소 개수만큼
            tempArr[i] = elementData[i];
        }

        // (3) 그 다음 위치에 새 요소 삽입
        tempArr[size] = e;  // 첫번째 실행이라면 10번째에 넣고
        size++;             // 그 다음부터 11번째, 12번째 ...

        // (4) 새로운 배열을 elementData로 설정
        elementData = tempArr;
        return true;
    }

    // R - get
    public E get(int index) {
        // 인덱스 범위 검사
        if(index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("인덱스의 범위를 벗어났습니다.");
        }
        // 반환 (Object -> 제네릭 타입으로)
        return (E)elementData[index];
    }

    // U - set
    public E set(int index, E e) {
        // 인덱스 범위 검사
        if(index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("인덱스의 범위를 벗어났습니다.");
        }

        // 반환할 E: 수정되기 전의 요소
        E prev = (E) elementData[index]; // 임시저장

        // 새로운 E로 해당 인덱스의 값 수정
        elementData[index] = e;

        // 반환
        return prev;
    }

    // D - remove
    public E remove(int index) {
        // 인덱스 범위 검사
        if(index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("인덱스의 범위를 벗어났습니다.");
        }

        // 삭제될 타겟 요소 임시 저장
        E prev = (E) elementData[index];

        // 인덱스 땡겨주기
        for (int i = index; i< size -1; i++) {
            elementData[i] = elementData[i+1];  // 덮어쓰기
        }

        elementData[size-1] = null; // 맨 마지막 요소는 수동으로 삭제
        size--;     // 전체 요소 크기 줄여주기

        return prev;    // 삭제된 요소 반환
    }

    // toString
    @Override
    public String toString() {
        return "__ArrayList{" +
                "elementData=" + Arrays.toString(elementData) +
                ", size=" + size +
                ", arraySize=" + arraySize +
                '}';
    }

    // Iterable 인터페이스 - 메소드 구현
    @Override
    public Iterator<E> iterator() {
        // 익명클래스 방식
        return new Iterator<E>() {
            private int pointer;

            @Override
            public boolean hasNext() {
                return pointer < size();
            }

            @Override
            public E next() {
                E e = get(pointer);
                pointer++;
                return e;
            }
        };
    }
}

 

Node 클래스
public class Node<E> {
    private Node<E> next;   // 다음 노드 (null 가능)
    private E data;         // element값 == data (제네릭 타입)

    // 생성자
    public Node(E data) {
        super();
        this.data = data;
    }

    // getter: next(다음 노드) 반환
    public Node<E> next() {
        return next;
    }

    // setter: next(다음 노드) 지정
    public void next(Node<E> next) {
        this.next = next;
    }

    // setter: data(element) 지정
    public void data(E data) {
        this.data = data;
    }

    // getter: data(element) 반환
    public E data() {
        return data;
    }

    // toString
    @Override
    public String toString() {
        return data.toString();
    }
}

 

LinkedList 클래스
import c_datastructure.Node;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class _LinkedList<E> implements Iterable<E> {
    private Node<E> head;
    private int size;

    // size()
    public int size() {
        return size;
    }

    // isEmpty()
    public boolean isEmpty() {
        return size <= 0;
    }

    // CRUD
    // C: add()
    public boolean add(E e) {
        Node<E> node = new Node<>(e);
        // head가 null이면 첫번째 요소를 삽입.
        if (head == null) {
            head = node;
            size++;
            return true;
        }
        // head가 null이 아님
        // 마지막 노드(rear)는 next가 없음
        Node<E> link = head;
        while (link.next() != null) {
            link = link.next();
        }
        // 찾은 마지막 노드(link)의 옆에 넣을 노드를 추가
        link.next(node);
        size++;
        return true;
    }

    // R: get()
    public E get(int index) {
        // 잘못된 인덱스를 참조하려고 할 때
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        // 정상 인덱스라면
        Node<E> link = head;    // 노드 이동용 참조 변수
        for (int i=0; i<index; i++) {
            link = link.next();
        }

        return link.data(); // 담겨있는 데이터 반환
    }

    // Update: set()
    public E set(int index, E e) {
        // 인덱스 검사
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        Node<E> link = head;
        for (int i=0; i<index; i++) {
            link = link.next();
        }
        E prev = link.data(); // 이전 데이터
        link.data(e);
        return null;
    }

    // Delete: remove()
    public E remove(int index) {
        // 인덱스 검사
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }

        Node<E> link = head;    // 이동 추적용 변수
        Node<E> prevNode = head;    // 이전 데이터
        for (int i=0; i<index; i++) {
            prevNode = link;
            link = link.next();
        }

        prevNode.next(link.next());
        E prev = link.data();
        size--;
        return null;
    }

    // toString
    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("[");
        for (int i=0; i<size; i++) {
            sb.append(get(i));
            if (i == size-1) break;
            sb.append(", ");;
        }
        sb.append(" ]");
        return sb.toString();
    }

    // Iterator
    @Override
    public Iterator<E> iterator() {
        //익명클래스 방식
        return new Iterator<E>() {
            // 현재 노드는 head부터 시작(초기화)
            private Node<E> current = head;

            @Override
            public boolean hasNext() {
                // 현재 노드가 null 이면 false 반환, null이 아니면 true 반환
                return current != null ? true: false;
            }

            @Override
            public E next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                E data = current.data();  // 현재 노드의 데이터 반환
                current = current.next(); // 현재 노드를 다음 노드로 초기화
                return data;
            }
        };
    }
}

 

 

테스트 실행용 클래스
public class Run {

    public static void main(String[] args) {
       testAdd();
       testGet();
       testSet();
       testRemove();
        testIterable();
    }

    static void testAdd() {

        _LinkedList<Integer> list = new _LinkedList<Integer>();

        for (int i = 0; i < 30; i++) {
            list.add(i);
        }

        System.out.println(list);
    }

    static void testGet() {

        _LinkedList<Integer> list = new _LinkedList<Integer>();

        for (int i = 0; i < 30; i++) {
            list.add(i);
        }

        for (int i = 5; i < 8; i++) {
            System.out.println(list.get(i));
        }
    }

    static void testSet() {
        _LinkedList<Integer> list = new _LinkedList<Integer>();

        for (int i = 0; i < 30; i++) {
            list.add(i);
        }

        for (int i = 5; i < 8; i++) {
            list.set(i, 9999);
        }

        System.out.println(list);
    }

    static void testRemove() {
        _LinkedList<Integer> list = new _LinkedList<Integer>();

        for (int i = 0; i < 30; i++) {
            list.add(i);
        }

        for (int i = 5; i < 8; i++) {
            list.remove(i);
        }

        System.out.println(list);
    }

    static void testIterable() {
        _LinkedList<Integer> list = new _LinkedList<Integer>();

        for (int i = 0; i < 10; i++) {
            list.add(i);
        }

        // 1. Iterable 인스턴스의 iterator 메서드를 호출해서 Iterator 객체를 반환 받음
        Iterator<Integer> it = list.iterator();

        // 2. hasNext를 호출해서 다음 요소가 존재하는지 확인
        while (it.hasNext()) {
            // 3. 존재하면 next()를 통해 반환받음
            Integer e = it.next();
            System.out.println(e);
        }

/*      for-each문으로 다시 테스트
        for (Integer i : list) {
            System.out.println(i);
        }*/
    }
}

큐 클래스
public class ArrayQueue {
    private int front;
    private int rear;
    private int maxSize;

    private Object[] queueArray;

    public ArrayQueue(int maxSize) {
        this.maxSize = maxSize;

        front = 0;
        rear = -1;

        queueArray = new Object[maxSize];
    }

    // 큐 공간이 비어 있는지
    public boolean isEmpty() {
        return (front == rear + 1);     // 둘 다 인덱스 0번이면 비어 있음
    }

    // 큐 공간이 가득 차 있는지
    public boolean isFull() {
        return (rear == maxSize - 1);   // 최후단이 배열의 총 크기와 같으면 다 차 있음
    }

    // 추가 -- rear와 연관 (늘어남)
    public void push(Object item) {
        if (isFull()) {
            System.out.println("큐 공간이 가득 차 있습니다");
            return;         // break
        }
        rear++;             // -1에서 0번지로
        queueArray[rear] = item;
    }

    // 삭제 -- front와 연관
    public Object pop() {
        Object item = peek();
        if (item == null) return null;

        front++;
        return item;
    }

    // 산출
    public Object peek() {
        if (isEmpty()) {
            System.out.println("큐 공간이 비어 있습니다");
            return null;
        }
        return queueArray[front];
    }
}

 

메인 클래스
public class MainClass {
    public static void main(String[] args) {

        // 배열 사이즈 5로 큐 초기화
        ArrayQueue queue = new ArrayQueue(5);
        
        // 첫번째 요소 삽입
        Integer in = 111;
        queue.push(in);

        // 두번째 요소 삽입
        in = 222;
        queue.push(in);

        // 세번째 요소 삽입
        in = 222;
        queue.push(in);

        // front 위치의 데이터 산출
        Integer peek = (Integer) queue.peek();
        System.out.println(peek);
        
        // 1개 삭제 (front 위치에서)
        queue.pop();

        // front 위치의 데이터 산출
        peek = (Integer) queue.peek();
        System.out.println(peek);
    }
}

 

isFull 메소드 // isEmpty 메소드
Work Flow

Stack 클래스
public class ArrayStack {
    private int top;
    private int maxSize;
    private Object[] stackArray;            // Object == 어떤 클래스든 다 담을 수 있음

    // 생성자 (배열 크기 -> 배열 초기화, top은 비어있음)
    public ArrayStack (int maxSize) {
        this.maxSize = maxSize;
        stackArray = new Object[maxSize];
        top = -1;
    }

    // 스택 공간이 비어 있는지
    public boolean isEmpty() {
        return (top == -1);                 // -1이면 true고, -1이 아니면 false
    }

    // 스택 공간이 가득 차 있는지
    public boolean isFull() {
        return (top == maxSize -1);         // 배열 사이즈가 10이면 top은 0~9번지 -> 9
    }

    // 추가 -- push
    public void push(Object item) {
        if (isFull()) {
            System.out.println("스택 공간이 가득 차 있음");
            return;             // break
        }
        top++;                  // top은 -1 에서 0
        stackArray[top] = item; // 0번지에 item 삽입
    }

    // 삭제 -- pop
    public Object pop() {       // 삭제된 데이터를 Return -- 반환타입 Object
        Object item = peek();   // top 위치의 아이템을 일단 확인
        if (item == null) {
            System.out.println("스택 공간이 비어 있음");
            return null;
        }
        top--;                  // top은 n에서 n-1
        return item;
    }

    // top(최상단)에 해당되는 데이터 (반환)
    public Object peek() {
        if (isEmpty()) {
            System.out.println("스택 공간이 비어 있음");
            return null;
        }
        return stackArray[top];
    }
}

 

 

메인함수 코드
public class MainClass {
    public static void main(String[] args) {
    /*
        Stack
        First in last out = FILO
        push, pop, peek
        isEmpty, isFull
     */

        // 크기가 5로 Stack 초기화
        ArrayStack stack = new ArrayStack(5);

        // 1번째 요소 삽입
        String str = "AAA";
        stack.push(str);

        // 2번째 요소 삽입
        str = "BBB";
        stack.push(str);

        // 3번째 요소 삽입
        str = "CCC";
        stack.push(str);

        // 최상단 데이터 확인
        String peek = (String) stack.peek();
        System.out.println(peek);

        // 최상단 데이터 삭제
        stack.pop();

        // 최상단 데이터 확인
        peek = (String) stack.peek();
        System.out.println(peek);

    }
}

 

Collection
Map : interface
HashMap : class == 사전 (dict)
          key : value 쌍
          tree 구조
          index로 접근하는 것이 아님!! - key로 접근함
          key는 중복을 허용하지 않음 (중복으로 입력하면 덮어쓰기 됨)
          web에서는 json
TreeMap : HashMap + Sorting

 

1. 해시맵 선언 (구조)

HashMap<Key 타입, Value 타입> 변수명 = new HashMap<>();

보통 Map으로 더 많이 받는다.

// HashMap<Integer, String> hMap = new HashMap<>();
Map<Integer, String> hMap = new HashMap<>();

 

2. 해시맵에 요소 추가 - put( key, value )

hMap.put(111, "백십일");
hMap.put(222, "이백이십이");
hMap.put(333, "삽백삼십삼");

 

3. 해시맵의 크기 반환 - size()

System.out.println(hMap.size());

 

4. Key값을 인덱스로 활용하여 Value를 취득 - get( key값 )

★ HashMap은 중복 key를 허용하지 않는다.

  • get 메소드는 value값을 리턴한다.
String value = hMap.get(333);
System.out.println(value);

 

5. HashMap의 모든 요소를 출력 - Iterator와 get을 활용 ☆

  • Iterator는 일종의 포인터 역할을 한다
  • Iterator < Key값의 자료타입 > (이터레이터)변수명 = (해시맵)변수명.keySet().iterator();
  • it.hasNext()를 한 번 사용하고 나면, 다시 쓰려면 끝을 가리키고 있는 포인터를 초기화 시켜줘야 한다. (새로 대입)
Iterator<Integer> it = hMap.keySet().iterator();
while (it.hasNext()) {
    Integer _key = it.next();
    String _value = hMap.get(_key);
    System.out.println("key = " + _key + "\tvalue = " + _value);
}

 

6. 삭제 - remove( key값 )

  • 삭제된 key의 value값을 리턴해준다.
String remove_value = hMap.remove(222);
System.out.println("삭제된 값 = " + remove_value);

 

7. 검색 - containsKey( Key값) 과 get()을 활용

  • containsKey( k )는 boolean을 리턴한다.
// 검색
// boolean b = hMap.containsKey(333);
if (hMap.containsKey(333)) {
    String val = hMap.get(333);
    System.out.println(val);
}

 

8. 수정 - replace(  Key값, 새로운 Value값 )

  • 키 값을 수정할 수는 없다!
// 수정 -- 키 값은 수정 안되고 value만
String str = "300 + 30 + 3";
hMap.replace(333, str);

 

 

9. 해쉬맵의 정렬 - 트리맵을 사용한다.

[메모]

  • HashMap의 확장판 == TreeMap
  • (ArrayList의 확장판 == LinkedList)
  • HashMap + 정렬 기능 이라서 더 무겁다 ( 정렬할때만 쓰고, 잘 안 씀)
// Sorting
TreeMap<String, String> tMap = new TreeMap<>( fruitMap );

// 오름차순 (자동) -- keySet()
Iterator<String> it1 = tMap.keySet().iterator();

// 내림차순 (자동) -- descendingKeySet()
Iterator<String> it1 = tMap.descendingKeySet().iterator();

// 출력
while (it1.hasNext()) {
    String k = it1.next();
    String v = tMap.get(k);
    System.out.println("key = " + k + "\tvalue = " + v);
}

 

Collection : 수집

List : 목록

  • 데이터의 관리를 유동적으로 할 수 있는 배열이다.
  • index로 접근을 관리한다
  • 선형 구조 0-0-0-0ArrayList : 검색에 우수
  • 동적 배열
  • 검색 효율이 성능을 좌우한다.LinkedList : 추가/삭제에 효율적

ArrayList 선언

// ArrayList<Integer> al = new ArrayList<>();

List<Integer> list = new ArrayList<>();

ArrayList의 CRUD

1. 삽입(생성)

1.1 맨 뒤에 요소를 삽입 : 

  • add(삽입할 요소)
  • { 1, 2, 3 } -> { 1, 2, 3, 6 }
list.add(300);

1.1 원하는 위치에 요소를 삽입 : 

  • add( 삽입할 인덱스 번호 , 삽입할 요소 )
  • { 1, 2, 3 } -> { 1, 6, 2, 3 };
Integer newNum = 300;
list.add(2, newNum);

 

2. 삭제

  • remove ( 인덱스번호 )   혹은    remove(  Object  )
  • remove 메소드는 return값이 존재한다 (삭제된 요소를 반환해줌)
// 인덱스번호로 삭제
Integer rm = list.remove(1);

// 일치하는 요소를 찾아 삭제
rm = list.remove(333);

 

3. 수정

  • set( 인덱스번호, 새로운요소 )
Integer newNum = 555;
list.set(3, newNum);

 

4. 검색

  • indexOf( 인덱스번호 )
  • return 값으로 인덱스 번호를 넘겨준다 (int형)
Integer findE = 300;
int index = list.indexOf( findE );

System.out.println("index = " + index );

 

  • 혹은 for문 + get으로 어레이에서 했던 것처럼 구현 가능
int index = -1;
for (int i=0; i<list.size(); i++) {
	Integer n = list.get(i);
	if ( n == 300 ) {
		index = i;
		System.out.println(index);
	}
}

 

+ Recent posts