[Java] 배열, ArrayList, Stack 관련 정리 및 활용
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"); // 요소 존재 여부 확인