Array 란, 예제문제 정복하기

이창호·2023년 2월 15일
1

자료구조

목록 보기
3/6

Array

Array란

  • 배열의 정의

배열(Array)은 동일한 데이터 타입의 변수들이 메모리에 연속해서 할당된 자료구조이다.

  • 배열의 특징

  • 인덱스(index)를 통해 배열 요소(element)에 접근할 수 있다.

  • 고정된 크기를 가지며, 크기를 변경할 수 없다.

  • 동일한 데이터 타입의 요소를 가지고 있다.

  • 메모리의 연속된 위치에 할당된다.

Array의 선언과 초기화

  • Array의 선언 방법

  • 배열 선언
    데이터타입[] 배열이름; (ex: int[] num = new int[4];)

  • 배열 초기화
    배열이름 = new 데이터타입[배열크기]; (ex: int[] num = {1,2,3,4};)

  • 배열의 길이

int[] arr = {1, 2, 3, 4, 5};
int length = arr.length; // 배열 arr의 길이는 5입니다.

다차원 Array

  • 2차원 배열

// 2차원 배열 선언
int[][] arr = new int[3][4];

// 2차원 배열 초기화
int[][] arr = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};
  • 3차원 배열

// 3차원 배열 선언
int[][][] arr = new int[3][4][5];

// 3차원 배열 초기화
int[][][] arr = {
    {
        {1, 2, 3, 4, 5},
        {6, 7, 8, 9, 10},
        {11, 12, 13, 14, 15},
        {16, 17, 18, 19, 20}
    },
    {
        {21, 22, 23, 24, 25},
        {26, 27, 28, 29, 30},
        {31, 32, 33, 34, 35},
        {36, 37, 38, 39, 40}
    },
    {
        {41, 42, 43, 44, 45},
        {26, 27, 28, 29, 30},
        {31, 32, 33, 34, 35},
        {36, 37, 38, 39, 40}
    }
    }

Array의 복사

  • 얕은 복사(Shallow Copy)

얕은 복사란 원본 배열과 복사된 배열이 같은 메모리 주소를 참조하는 복사 방법이다.

밑에 코드에서 arr2의 첫번째 값을 변경하였더니 arr1의 첫번째 값도 바뀌어 버렸다.

int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = arr1; // 얕은 복사

arr2[0] = 6;
System.out.println(Arrays.toString(arr1)); // [6, 2, 3, 4, 5]
  • 깊은 복사(Deep Copy)

깊은 복사란 원본 배열과 복사된 배열이 서로 다른 메모리 주소를 참조하는 복사 방법이다.

얕은 복사와는 다르게 arr2의 첫번째 값을 바꿔도 arr1에 영향을 주지않는다.

int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = new int[arr1.length]; // 깊은 복사
System.arraycopy(arr1, 0, arr2, 0, arr1.length);

arr2[0] = 6;
System.out.println(Arrays.toString(arr1)); // [1, 2, 3, 4, 5]

Array의 활용

  • for-each

for-each문은 배열의 요소를 순회하는 데 유용한 반복문이다.

int[] arr = {1, 2, 3, 4, 5};
for (int num : arr) {
    System.out.print(num + " ");
}
// 출력 결과: 1 2 3 4 5
  • Arrays 클래스

Arrays 클래스는 배열과 관련된 메서드들을 제공한다.

int[] arr = {3, 2, 1, 5, 4};
Arrays.sort(arr); // 배열을 오름차순으로 정렬
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5]

예제문제

문제: 접미사 배열(백준 11656번)

접미사 배열은 문자열 S의 모든 접미사를 사전순으로 정렬해 놓은 배열이다.

baekjoon의 접미사는 baekjoon, aekjoon, ekjoon, kjoon, joon, oon, on, n 으로 총 8가지가 있고, 이를 사전순으로 정렬하면, aekjoon, baekjoon, ekjoon, joon, kjoon, n, on, oon이 된다.

문자열 S가 주어졌을 때, 모든 접미사를 사전순으로 정렬한 다음 출력하는 프로그램을 작성하시오.

입력
첫째 줄에 문자열 S가 주어진다. S는 알파벳 소문자로만 이루어져 있고, 길이는 1,000보다 작거나 같다.

출력
첫째 줄부터 S의 접미사를 사전순으로 한 줄에 하나씩 출력한다.

예제 입력
baekjoon

예제 출력
aekjoon
baekjoon
ekjoon
joon
kjoon
n
on
oon

나의 생각

  • 입력값을 받는다.
  • 접미사 배열을 만든다. 크기는 입력값의 길이만큼 설정한다.
  • for문과 substring함수로 맨앞자리를 지워주면서 만들어둔 배열에 넣어준다.
  • Arrays클래스에서 지원하는 sort함수를 사용해 오름차순으로 정렬하고 출력해준다.

구현

import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) throws IOException {

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder br = new StringBuilder();

        String word = in.readLine(); // 단어를 입력받는다.
        String[] arr = new String[word.length()]; // 접미사배열을 단어의 길이만큼 잡는다.

        for(int i=0;i<word.length();i++)
        {
        	// 맨앞자리 인덱스를 증가시키면서, 단어를 하나씩 배열에 담는다.
            arr[i] = word.substring(i,word.length());
        }

		//배열을 오름차순으로 정렬한다.(String은 알파벳순으로 정렬된다.)
        Arrays.sort(arr);

        for(String str:arr)
        {
        	//StringBuilder에 배열의 단어를 하나씩 담는다.
            br.append(str).append("\n"); 
        }
        System.out.println(br); //출력

        in.close(); // BufferedReader의 버퍼를 비워주고 닫아준다.
    }

}

Stream을 사용할 수도 있다.

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

public class Array01 {

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb =new StringBuilder();
        String word = in.readLine();
        String[] arr = new String[word.length()];

        for (int i = 0; i < word.length(); i++) {
            arr[i] = word.substring(i);
        }

        Arrays.stream(arr)
                .sorted()
                .forEach(i -> sb.append(i).append("\n"));

        System.out.println(sb.toString());
    }

}

마무리

  • 오늘은 StringBuilder를 써봤다.

  • String은 불변(immutable)의 속성을 갖는다

  • String +=연산은 새로운 메모리영역을 가리키게 변경되고 처음 선언했던 string에 값이 할당되어 있던 메모리 영역은 Garbage로 남아있다가 GC(garbage collection)에 의해 사라지게 된다고 한다. 이런 비효율적인 동작 때문에
    StringBuilder와 StringBuffer클래스가 나왔다.

  • String 클래스는 불변하기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성된다라고 정리할 수 있다.

  • 즉 변하지 않는 문자열을 자주 읽어들이는 경우 String을 사용해 주시면 좋은 성능을 기대할 수 있다. 변경이 자주 일어나면 성능은 떨어진다.

  • StringBuffer : 문자열 연산이 많고 멀티쓰레드 환경일 경우 안전하다.

  • StringBuilder : 문자열 연산이 많고 단일쓰레드이거나 동기화를 고려하지 않아도 되는 경우 StringBuffer보다 성능이 좋다.

  • 나는 StringBuilder를 사용해보았다.

  • BufferedReader의 경우 close()를 꼭 사용해야하나라는 글들을 찾아서 읽어보았다. BufferedWriter의 경우 문제가되지만, reader의 경우 문제가 없다는 개발자들도 있었다. 결국 Garbage Collector의 존재 때문에 논쟁이 되는것 같다.
    하지만, 좋은 개발자가 되려면 메모리를 스스로 생각하고 관리할 줄 알아야 한다.
    Garbage Collector를 맹신하지않고 close()하는 습관을 들여야한다.

인터넷에서 떠도는 문서나, 오렐리같은사람이 쓴 책을 보면
그냥 close()를 해주는것도 모자라

finally{

if(inputSteam != null) {

try{inputSteam.close();}catch(){}

...

try-catch문까지 사용한다고한다.

test, 로컬에서 장애가 일어나지 않는다고하여, 정상적인 프로그램이라고 확신할 수 없다.
이 문장이 인상적이였다.

profile
어떻게든 해결한다.

0개의 댓글