프로그래밍 언어/Java

[Java] 배열, ArrayList, Stack 관련 정리 및 활용

허 진 2024. 11. 8. 18:23

Java의 강력한 특징 중 하나는 객체 지향 프로그래밍(Object Oriented Programming)을 지원한다는 점이다. 
이러한 객체 지향적 특성을 활용하여 Java는 다양한 자료구조를 이미 인터페이스와 구현체로 제공하고 있어, 개발자는 효율적으로 코드를 작성할 수 있다.


이번 포스팅에서는 Java 개발에서 가장 기본이 되는 자료구조인 Array(배열)부터 Collection Framework의 핵심인 ArrayList, Stack, Queue 정리하고자 한다.

 

 

 


1. 배열(Array)

배열은 소위 0부터 시작하는 인덱스와 그 에 일대일로 대앙하는 value를 관리하는 자료구조 이다.

이데이터를 저장할수 있는 공간과 일대일 대응하므로 어떤 위치에 존재하든 한번에 접근이 가능하다.(O(1))

(배열은 길이가 고정인 대신 접근이 빠릅니다. But 삽입, 삭제 시 중간의 요소들을 이동이 필요할 수 있어 비효율 적입니다.)

 

- 배열 선언

        //1차원 배열
        int[] numbers = new int[5];
        int[] number2 = {1, 2, 3, 4, 5};

        //arr1 과 arr은 결과값이 동일하다.
        int[] arr = {0, 0, 0, 0, 0, 0};
        int[] arr1 = new int[6];

        //2차원 배열
        int[][] matrix = new int[3][4];
        int[][] matrix2 = {{1,2}, {3,4}};

 

여기서 arr 과 arr1은 Java에서 정수(int)배열을 생성할 때 자동으로 0으로 초기화 하기 때문에 동일하다.

 

- 배열 관련 주요 메소드

배열 복사

int[] source = {1, 2, 3, 4, 5};
int[] dest = new int[5];
System.arraycopy(source, 0, dest, 0, source.length);

 

첨삭을 덧붙이면 source -> 복사할 원본 배열, dest -> 복사된 값을 저장할 대상 배열,  2,4 번째 para는 복사를 시작할 위치(인덱스), 마지막 para는 복사할 요소의 개수 이다.

 

// Arrays 클래스를 사용하기 위해 import
// 아래 둘중 맘에 드는거 사용
import java.util.Arrays;

import java.util.*; //막 권장하진 않지만 util 패키지의 모든 클래스 import

// 1. 배열 정렬
int[] numbers = {5, 2, 8, 1, 9};
Arrays.sort(numbers);  // [1, 2, 5, 8, 9]

Arrays.sort(numbers, Collections.reverseOrder());
// int[]는 불가능! Integer[]로 변환 필요

// 2. 배열 검색 (정렬된 배열에서만 사용)
int index = Arrays.binarySearch(numbers, 5);  // 요소의 인덱스 반환

// 3. 배열 비교
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
boolean isEqual = Arrays.equals(arr1, arr2);  // true
// equals는 동등성 비교인거 생각
// ==은 동일성 비교

// 4. 배열 채우기
int[] arr = new int[5];
Arrays.fill(arr, 7);  // [7, 7, 7, 7, 7]

// 5. 배열을 문자열로 변환
String arrayString = Arrays.toString(numbers);  // "[1, 2, 5, 8, 9]"

// 6. 배열 복사
int[] copied = Arrays.copyOf(numbers, numbers.length);
int[] partial = Arrays.copyOfRange(numbers, 1, 4);  // 인덱스 1부터 3까지 복사

// 7. 다차원 배열 정렬 및 비교
int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 4}};
boolean isMatrix2Equal = Arrays.deepEquals(matrix1, matrix2);  // true
String matrixString = Arrays.deepToString(matrix1);  // "[[1, 2], [3, 4]]"

 

- 추가적으로 Java 배열에서는 음수 인덱스를 지원하지 않으니 주의(?)하시면 될 거 같습니다.

 

2. ArrayList

ArrayList는 배열과 달리 가변적 길이를 가집니다.(동적할당 지원) 배열과 달리 메모리에 연속적으로 나열 되어 있는 구조가 아닌, 주소로 연결되어 있는 형태이기 때문에 1번의 배열보다는 접근 속도가 느립니다.

 

- ArrayList 생성

import java.util.ArrayList;

// 기본 생성
ArrayList<Integer> list1 = new ArrayList<>();

//ArrayList는 제네릭을 사용하므로 Int가 아닌 래퍼런스 타입(Wrapper 클래스)인 
//Integer을 사용해야 합니다

		/* 참고사항
        byte    -> Byte
        short   -> Short
        int     -> Integer
        long    -> Long
        float   -> Float
        double  -> Double
        char    -> Character
        boolean -> Boolean
        */
//제네릭은 기본형 직접사용 불가능

// 초기 용량 지정
ArrayList<String> list2 = new ArrayList<>(10);

// 다른 컬랙션으로 부터 생성
ArrayList<Integer> list2 = new ArrayList<>(Arrays.asList("A", "B", "C"));

 

- ArrayList 관련 매소드

// 기본적인 사용 예시
ArrayList<Integer> numbers = new ArrayList<>();

// 요소 추가
numbers.add(1);
numbers.add(2);
numbers.add(3);
System.out.println(numbers);  // [1, 2, 3]

// 2. 특정 위치에 요소 추가 (index는 0부터)
numbers.add(1, 5);  // [1, 5, 2, 3]

// 3. 요소 삭제
numbers.remove(1);  // 인덱스가 1인 요소 삭제
numbers.remove(Integer.valueOf(2));  // 숫자 2를 가진 요소 삭제(주의하기)

// 숫자형 Wrapper 클래스(Integer, Double 등)를 사용할 때, 
// 숫자를 직접 넘기면 컴파일러가 이를 인덱스로 해석

// 4. 반복문 사용
for (Integer num : numbers) {
    System.out.println(num);
}

// 5. 스트림 API 활용
numbers.stream()
       .filter(n -> n > 2)
       .forEach(System.out::println);

// 6. 정렬 예시
ArrayList<String> names = new ArrayList<>(
    Arrays.asList("John", "Alice", "Bob")
);
names.sort(String::compareTo);  // 알파벳 순 정렬

 

3. Stack

Stack은 Lifo(last in first out의 약자)로 먼저 들어온 데이터가  나중에 빠져나가는 구조이다.

깊이 우선 탐색(DFS)과 재귀에서 많이 이용된다.

 

- Stack 생성 

// Stack 생성
import java.util.Stack;
import java.utili.*; //둘중 하나 사용

// 1. 기본 생성
Stack<Integer> stack = new Stack<>();
//ArrayList와 마찬가지, wrapper 클래스 주의

// 2. 초기값 넣기
Stack<String> stack2 = new Stack<>();
stack2.addAll(Arrays.asList("A", "B", "C"));

- Stack 관련 메소드

Stack<String> stack = new Stack<>();

// 1. 삽입 관련 메소드
stack.push("A");        // 요소 추가 (스택의 top에 삽입)
stack.add("B");         // push와 동일 (List 인터페이스에서 상속)
stack.addElement("C");  // push와 동일 (Vector 클래스에서 상속)

// 2. 삭제 관련 메소드
String top = stack.pop();     // top 요소 제거하고 반환
stack.remove(0);             // 특정 인덱스의 요소 제거
stack.clear();               // 모든 요소 제거

// 3. 조회 관련 메소드
String peek = stack.peek();   // top 요소 반환 (제거하지 않음)
boolean empty = stack.empty(); // 스택이 비어있는지 확인
int size = stack.size();      // 스택의 크기
int position = stack.search("A"); // 요소의 위치 검색 (1-based, 없으면 -1 반환)
boolean exists = stack.contains("A"); // 요소 존재 여부 확인