본문 바로가기
자바/스터디

[자바 스터디] 4주차 과제 : 제어문

by jeonghaemin 2020. 12. 11.
728x90

본 게시글은 백기선 님의 live-study 과제를 수행하면서 작성한 글입니다.

선택문(switch 문)

if 문의 경우 경우의 수가 많아질수록 계산해야 하는 조건식이 많아져 처리 시간이 오래 걸리며 가독성도 좋지 않을 수 있다.

이에 반해 Swtich 문은 하나의 조건식으로 많은 경우의 수를 처리할 수 있으며 표현도 간결하여 처리할 경우의 수가 많은 경우 Switch 문을 사용하는 것이 좋다.

switch 문은 조건식을 계산한 다음, 그 결과와 일치하는 case 문으로 이동 후 해당 case 문 아래에 있는 코드들을 실행하며 break 문을 만나면 switch 문을 빠져나가게 된다.

위 예시 코드를 보면 num 값은 2이기 때문에 (1) 과정에서 case 2:로 이동하여 (2) 과정에서 case 2: 아래에 있는 코드들을 실행하게 되고 case 3:에 있는 코드까지 실행하고 나서야 break 문을 만나 switch 문을 빠져나가게 된다.

조건식의 결과와 일치하는 값을 못 찾는 경우 default 문으로 이동하게 된다. if 문의 else 문과 같다고 생각하면 된다.

switch 문은 몇 개의 제약 조건이 있다.

  1. switch 문의 조건식 결과는 정수 또는 문자열
  2. case 문의 값은 정수 상수, 문자열 리터럴만 가능하며 중복 허용되지 않음. (JDK 1.7버전부터는 문자열 리터럴도 사용 가능)
final int NUM = 1;
int a = 0;

switch(조건식) {
  case '5': // 문자 리터럴 '5'는 아스키 코드 값으로 53 정수이기 때문에 가능.
  case NUM : // 정수 상수이기 때문에 가능. 
  case "Hi": // 문자열 리터럴은 JDK 1.7부터 가능.
  case a: // 변수는 불가능
  case 5.0: // 실수는 불가능
}

switch문도 if-else 문과 같이 중첩해서 사용 가능하다.

switch(조건식1) {
  case 값1:
    switch(조건식2) {
      case 값11:
      default:
    }
  case 값2:
  default:
}

반복문

반복문은 특정 코드가 반복적으로 수행되도록 할 때 사용하며, 자바에서 반복문은 for 문, while 문, do-while 문이 있다.

for문

for(초기화; 조건식; 증감식;) {
    // 반복할 코드
}
  • 초기화 : 반복문에 사용될 변수를 초기화하는 부분으로 처음 한 번만 수행된다.
  • 조건식 : 조건식의 값이 true 이면 반복문을 계속해서 실행하고 false 이면 실행을 중단하고 빠져나간다.
  • 증감식 : 반복문을 제어하는 변수의 값을 증가시키거나 감소시키는 부분으로 증감식에 의해서 값이 변화하여 조건식이 false가 되면 반복문을 빠져나가게 된다.
// for문 예시
for(int i = 0; i < 5; i++) {
  System.out.print(i + " ");
}
// 결과 : 0 1 2 3 4

예를 들어 다음과 같은 반복문이 있다면 초기화 부분에서 변수 i는 0으로 초기화되고 반복 시마다 i의 값은 1씩 증가하고, 계속되는 반복 과정에서 i < 5 조건식의 결과가 false가 되면 반복을 중단하게 된다.

향상된 for문(JDK 1.5 버전 이상)

JDK 1.5부터 배열이나 컬렉션의 요소에 기존보다 편리하게 접근할 수 있도록 새로운 for 문이 추가되었다.

for(타입 변수명 : 배열 or 컬렉션) {
    // 반복할 코드
}

타입은 배열 또는 컬렉션의 타입이어야 하며, 배열 또는 컬렉션에 있는 값들이 순차적으로 매 반복마다 변수명으로 지정한 변수에 저장되어 {} 안의 코드에서 사용할 수 있게 된다.

int arr[] = {1,2,3,4,5};

for(int n : arr) {
  System.out.print(n + " ");
}
// 결과 : 1 2 3 4 5

while 문

while(조건식) {
  // 반복할 코드
}

while문은 조건의 결과가 false가 될 때까지 반복한다.

// for문과 while문의 비교

// for문
for(int i = 0; i < 5; i++) {
  System.out.println(i);
}

// while문
int i = 0;
while(i < 5) {
    System.out.println(i++);
}

do-while문

do {
    // 반복할 코드
} while(조건식) 

do-while 문은 while과 구조가 비슷하지만 최초 반복문의 실행 시부터 조건을 검사하는 while 문과 달리 반복할 코드를 먼저 수행하고 그다음에 조건을 검사한다.

결과적으로 while 문은 조건식의 결과에 따라 반복문이 한 번도 실행되지 않을 수 있지만 do-while 문은 반복문이 최소 한 번은 실행된다.

continue문

continue 문은 반복문 내에서만 사용되며, continue 문을 만나면 나머지 코드를 실행하지 않고 해당 반복문의 끝으로 이동하여 다음 반복을 넘어간다.

break 문

break 문은 앞서 보았듯이 switch 문과 반복문 내에서 사용할 수 있으며, 반복문에서 사용 시 자신이 포함된 가장 가까운 반복문을 빠져나가게 된다.

과제 0. JUnit 5 학습하세요.

과제1 live-study 대시 보드를 만드는 코드를 작성하세요.

import org.kohsuke.github.*;

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

public class App {

    public static void main(String[] args) throws IOException {
        GitHub gitHub = new GitHubBuilder().withOAuthToken(MY_TOKEN).build();

        GHRepository repo = gitHub.getRepository("whiteship/live-study");

        List<GHIssue> issues =  repo.getIssues(GHIssueState.ALL);

        HashMap<String, Integer> userInfo = new HashMap<>();

        for (GHIssue issue : issues) {
            List<GHIssueComment> comments = issue.getComments();

            for(GHIssueComment comment : comments) {
                String userName = comment.getUser().getName();
                if (comment.getUser().getName() != null) {
                    userInfo.put(userName, userInfo.getOrDefault(userName, 0) + 1);
                }
            }
        }

        for(String username : userInfo.keySet()) {
            System.out.printf( "%s : %.2f%%\n", username, (float)userInfo.get(username)/issues.size()*100);
        }
    }
}

과제 2. LinkedList를 구현하세요.

연결리스트(Linked List)란?

연결 리스트는 데이터 다음 요소를 가리키는 포인터로 이루어진 노드들이 연결된 형태로 구성되어 있는 자료구조이다.

연결리스트와 배열의 비교

배열

  • 데이터를 연속적인 메모리 공간에 순차적으로 저장한다.
  • 인덱스를 가지고 있기 때문에 데이터 접근 속도가 빠르다.
  • 데이터를 삽입 또는 삭제하는 경우, 삽입 또는 삭제를 수행한 위치로부터 다음에 있는 모든 요소들의 위치를 변경해야 하기 때문에 비효율적이다.

연결리스트

  • 데이터를 불연속적인 공간에 순차적으로 저장한다.
  • 배열과 달리 인덱스는 없고 현재 노드의 다음이나 이전 위치 포인터를 가지고 있다.
  • 데이터에 접근하려면 헤드 노드부터 하나씩 순차적으로 접근해 나가야 하므로 배열에 비해 비효율적이다.
  • 데이터의 삽입 또는 삭제는 삽입 또는 삭제하고자 하는 위치의 노드들을 연결해 주기만 하면 되므로 배열에 비해 효율적이다.

연결리스트 구현

  • 정수를 저장하는 ListNode 클래스구현.
  • ListNode add(ListNode head, ListNode nodeToAdd, int position)를 구현.
  • ListNode remove(ListNode head, int positionToRemove)를 구현.
  • boolean contains(ListNode head, ListNode nodeTocheck)를 구현.
public class ListNode {

    public ListNode(int data) {
        this.data = data;
        this.nextNode = null;
    }

    int data;
    ListNode nextNode;

    public static ListNode add(ListNode head, ListNode nodeToAdd, int position) {
        if (position == 0) {
            nodeToAdd.nextNode = head.nextNode;
            head.nextNode = nodeToAdd;

            return nodeToAdd;
        }

        ListNode curNode = head;

        for(int i = 0; i < position; i++) {
            if (curNode.nextNode == null) {
                return null;
            }

            curNode = curNode.nextNode;
        }

        nodeToAdd.nextNode = curNode.nextNode;
        curNode.nextNode = nodeToAdd;

        return nodeToAdd;
    }

    public static ListNode remove(ListNode head, int positionToRemove) {
        if (positionToRemove == 0) {
            head.nextNode = head.nextNode.nextNode;
            return head.nextNode;
        }

        ListNode curNode = head;

        for (int i = 0; i < positionToRemove; i++) {
            if (curNode.nextNode == null) {
                return  null;
            }

            curNode = curNode.nextNode;
        }

        ListNode removeNode = curNode.nextNode;
        curNode.nextNode = removeNode.nextNode;

        return removeNode;
    }

    public static boolean contains(ListNode head, ListNode nodeToCheck) {
        boolean isContains = false;
        ListNode curNode = head;

        while(curNode.nextNode != null) {
            curNode = curNode.nextNode;

            if (curNode == nodeToCheck) {
                return true;
            }
        }

        return false;
    }

    public static void printList(ListNode head) {
        ListNode curNode = head;

        System.out.print("[");
        while(curNode.nextNode != null) {
            curNode = curNode.nextNode;
            System.out.print(curNode.data + ", ");
        }
        System.out.print("]");
        System.out.println();
    }
}

과제 3. Stack을 구현하세요.

  • int 배열을 사용해서 정수를 저장하는 Stack을 구현하세요.
  • void push(int data)를 구현하세요.
  • int pop()을 구현하세요.
public class ArrayStack {
    private int size;
    private int[] arr;
    private int curPos;

    public ArrayStack() {
        this(10);
    }

    public ArrayStack(int size) {
        this.size = size;
        this.arr = new int[size];
        this.curPos = -1;
    }

    public void push(int data) {
        if (curPos == size-1) {
                      int[] temp = new int[size + size/2];
            System.arraycopy(this.arr, 0, temp, 0, size);

            this.arr = temp;
            this.size += (size/2);
        }

        arr[++curPos] = data;

    }

    public int pop() {
            if (isEmpty()) {
                System.out.println("Stack is empty!!");
                return -1;
            }

            return arr[curPos--];
    }

    public boolean isEmpty() {
        return curPos == -1;
    }

    public void printStack() {
        if (curPos == -1) {
            System.out.println("[ ]");
            return;
        }

        System.out.print("[");
        for (int i = 0; i <= curPos; i++) {
            System.out.print(arr[i] + ", ");
        }
        System.out.print("]");
        System.out.println();
    }
}

과제 4. 앞서 만든 ListNode를 사용해서 Stack을 구현하세요.

  • ListNode head를 가지고 있는 ListNodeStack 클래스를 구현하세요.
  • void push(int data)를 구현하세요.
  • int pop()을 구현하세요.
public class LinkedListStack {
    ListNode head;

    public LinkedListStack() {
        this.head = new ListNode(-1);
    }

    public void push(int data) {
        ListNode.add(this.head, new ListNode(data), 0);
    }

    public int pop() {
        ListNode removeNode = ListNode.remove(this.head, 0);

        if (removeNode == null) {
            System.out.println("Stack is empty!!");
            return -1;
        } else {
            return removeNode.data;
        }
    }

    public void print() {
        ListNode.printList(this.head);
    }

      public boolean isEmpty() {
        return this.head.nextNode == null;
    }
}

과제 5. Queue를 구현하세요.

  • 배열을 사용해서 한번
  • ListNode를 사용해서 한번.

ArrayQueue

public class ArrayQueue {

    int[] arr;
    int frontPos;
    int rearPos;

    public ArrayQueue() {
        this(10);
    }

    public ArrayQueue(int size) {
        arr = new int[size+1];
        frontPos = 0;
        rearPos = 0;
    }

    public void  offer(int data) {
        if (getNextPos(rearPos) == frontPos) {
            System.out.println("Queue is full!");
            return;
        }

        rearPos = getNextPos(rearPos);
        arr[rearPos] = data;
    }

    public int poll() {
        if (isEmpty()) {
            System.out.println("Queue is empty!!");
            return -1;
        }

        frontPos = getNextPos(frontPos);
        return arr[frontPos];
    }

    public boolean isEmpty() {
        return frontPos == rearPos;
    }

    public int peek() {
        if (isEmpty()) {
            System.out.println("Queue is empty!!");
            return -1;
        }

        return arr[getNextPos(frontPos)];
    }

    private int getNextPos(int pos) {
        if (pos == arr.length-1) {
            return 0;
        } else {
            return ++pos;
        }
    }
}

LinkedListQueue

public class LinkedListQueue {

    ListNode head;
    ListNode tail;

    public LinkedListQueue() {
        head = new ListNode(-1);
        tail = head;
    }

    public void offer(int data) {
        ListNode newNode = new ListNode(data);

        tail.nextNode = newNode;
        tail = newNode;
    }

    public int poll() {
        if (isEmpty()) {
            System.out.println("Queue is empty!!");
            return -1;
        }

        head = head.nextNode;
        return head.data;
    }

    public int peek() {
        if (isEmpty()) {
            System.out.println("Queue is empty!!");
            return -1;
        }

        return head.nextNode.data;
    }

    public boolean isEmpty() {
        return head.nextNode == null;
    }
}

참고

  • 윤성우의 열혈 자료구조
  • 자바의 정석 3판(남궁성 저)

댓글