[Java] 진법 변환 토이 프로젝트 (N진수를 K진수로 변환하기, No Library)
개요
코딩 테스트에서 진법 변환 문제가 나왔습니다.
여러 조건 때문에 결국 못 풀어서 한이 남아 아예 프로젝트를 하나 만들고 포스팅으로 박제하고자 합니다.
한번 익혀두면 잊어버리지 않으니, 공부하면 좋은 지식이 될 거라 생각합니다.
N진수를 입력 받아 N진수를 K진수로 변환하는 방법을 알아보겠습니다.
ex) 1111(2) -> 17(8)
N = (2 ~16) 진수
K = (2~16)진수
NotationConversion
NotationConversion은 제가 지은 프로젝트 이름입니다.
N진수를 K진수로 바꾸는 변환 과정은 다음과 같습니다.
N진법으로 표기된 숫자를 10진법으로 바꾸고 바꾼 10진수를 K진법으로 바꿔줬습니다.
자바 코드로 먼저 확인해보겠습니다.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /* N진수를 받아 K진법으로 만드는 프로젝트 2진수 ~16진수를 입력받아, 2진수 ~16진수로 변환해주는 프로그램 진수를 입력받고 10진수로 변환한 다음, 다시 원하는 진수로 변환시켜보자. */ public class NotationConversion { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("몇 진수를 입력하시겠습니까? (2~16만입력만 가능합니다.)"); int N = Integer.parseInt(br.readLine()); System.out.println("수를 입력해 주세요. 10이상은 대문자를 입력하십시오."); String number = br.readLine(); // 먼저 입력 받은 각각의 진수를 10진법으로 바꿔준다. int decimal = toDecimal(N, number); System.out.println("몇 진수로 바꾸시겠습니까?"); int K = Integer.parseInt(br.readLine()); String answer = conversionToK(decimal, K); System.out.print("결과 : " + answer); } // N진수를 10진수로 변환. public static int toDecimal(int N, String number) { int result = 0; // 입력이 10진법인 경우 바로 리턴 if(N == 10) { return Integer.parseInt(number); } else if(N >= 2 && N <= 16){ char[] num = number.toCharArray(); /* 0부터 시작하여 진수와 곱해주고 각 자리 수 숫자를 더해준다. 그리고 그 결과를 다음 자리수로 갈 때 진수와 곱해주고 현재 자리수 값을 더해준다. 반복. */ for(int i=0; i<num.length; i++) { if(!errorCheck(num[i], N)) { System.out.println("잘못된 입력입니다. 프로그램을 다시 실행하십시오."); System.exit(0); } // 10이상의 숫자는 'A'를 빼고 +10을 해주면 된다. if(num[i] >= 'A') { result = result * N + (num[i] - 'A' + 10); } else { result = result * N + (num[i] - '0'); } } } else { System.out.println("계산할 수 없는 진수입니다. 프로그램을 다시 실행하십시오."); System.exit(0); } return result; } // 10진수를 K진수로 변환. public static String conversionToK(int decimal, int K) { StringBuilder sb = new StringBuilder(); int current = decimal; while(current > 0) { // N진법으로 나누었는데 10보다 작으면 바로 추가 if(current % K < 10) { sb.append(current % K); } // 10이상은 알파벳으로 표기한다. else { // 10진수를 구해주는 법과 반대로 수행해주면 된다. 10이상의 수부터 표현할 수 있기 때문에 10을 빼주는 것이다. sb.append((char)(current % K - 10 + 'A')); } current /= K; } return sb.reverse().toString(); } // 주어진 진법 보다 높은 숫자가 입력으로 들어오면 오류. public static boolean errorCheck(char num, int notation) { int n = 0; if(num >= 'A') { n = num - 'A' + 10; } else { n = num - '0'; } if(n >= notation) { return false; } return true; } }
Step 1. 입력받은 N진수를 10진수로 변환.
N진수에서 10진수로 변환할 때, 각 자릿수마다 10진수 결과에 N을 곱해주면서 각 자릿수의 값을 더해주는 방식으로 해결했습니다.
맨 마지막 자릿수(일의 자리)는 0승을 곱해주기 때문에 처음 시작할 때의 result 값을 0으로 설정해줬습니다.
1111(8)을 10진수로 변환하는 과정을 표로 보여드리겠습니다. 1111(8) = 585(10)
i | num[i] | result = result * 8 + (num[i]) |
0 | 1 | 1 = 0 * 8 + (1) |
1 | 1 | 9 = 1 * 8 + (1) |
2 | 1 | 73 = 9 * 8 + (1) |
3 | 1 | 585 = 73 * 8 + (1) |
Step2. 10진수를 K진수로 변환.
10진수를 K진수로 변환하는 방법은 간단합니다. 수학적으로는 10진법으로 표기된 숫자를 K로 나누어 그 나머지를 표시하고 더 이상 나누어지지 않을 때까지 반복하면 됩니다.
여기서 주의할 점은 일반적으로 String 타입으로 정답을 도출해 낼 것입니다. 이 과정에서 최종 String값을 reverse()해줘야 정상적인 답이 도출됩니다.
BinaryToHexadecimal (2진법 -> 16진법)
10진법의 변환 과정을 거치지 않고 2진법에서 16진법으로 바로 바꾸는 방법입니다.
이 방법은 자주 출제되고 여기저기 노출되는 유형이기 때문에 정리하겠습니다.
사실 이 메소드를 구현하는 것이 코딩 테스트에 나왔었는데, 하 너무 아쉽습니다.
정말 간단합니다.
16^1 = 2^4인 점을 생각한다면,
2진수의 4비트가 16진수의 1비트를 나타내는 원리를 이용하는 것이 핵심 포인트입니다.
코드로 확인하겠습니다.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class binary2Hex { // 2진법 -> 16진법 변환하기 public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print("2진수를 입력하십시오 : " ); String binary = br.readLine(); System.out.println(binToHex(binary)); } public static String binToHex(String binary) { String answer = ""; StringBuilder sb = new StringBuilder(); int length = binary.length(); // 4로 나누어 떨어질 때까지 0을 앞에다 추가해준다. // 4자리로 끊기 위함. while(length % 4 != 0) { sb.append("0"); length++; } binary = sb.toString() + binary; // 전체 길이에서 4로 나눠줌으로써 총 반복횟수 결정. for(int i=0; i<length / 4; i++) { // 4자리씩 끊은 2진수 저장. String subBinary = binary.substring(i*4, i*4+4); int Hex = 0; // 10진법의 수를 K진법으로 바꾸는 방법과 유사. // 앞에서부터 진법을 차례대로 곱해가면서 현재 자리의 수를 더해준다. for(int j = 0; j<subBinary.length(); j++) { char num = subBinary.charAt(j); if(num >= '0' && num <= '9') { Hex = Hex * 2 + (num-'0'); } else { Hex = Hex * 2 + (num - 'A' + 10); } } if(Hex >= 10) answer += (char)(Hex - 10 + 'A'); else answer += Hex; } return "0x"+answer; } }
주의사항
☞ 2진수는 4자리씩 끊어지지 않을 수 있습니다.
- (16진수의 길이) % 4 == 0이 될 때까지, 기존 16진수 앞에 "0"을 붙여줍니다.
☞ 4자리씩 끊어서 나온 2진수의 각 자릿수 합을 16진수의 한 자릿수로 바꿔줍니다.
- 예를 들어, 28(10) = 11100(2)
-> "0" 추가
-> 0001 1100
-> 4자리씩 10진수 도출 = 1, 12
-> 16진수로 변환 = 1, C
☞ 16진수임을 표시하기 위해 앞에 "0x"를 붙여줍니다.
-> "0x" 추가
= 0x1C
※ 간단하게 진행한 알고리즘 토이 프로젝트라 미흡하고 오류가 많을 수 있습니다. 피드백은 환영합니다.
'공부 || 정리 > Algorithm' 카테고리의 다른 글
[Java] 다익스트라(Dijkstra) 알고리즘. (0) | 2021.05.28 |
---|---|
[Java] 이분 탐색(Binary Search) (2) | 2021.05.15 |
[Java]투 포인터 / 슬라이딩 윈도우 알고리즘 (6) | 2021.05.13 |
[Java] DFS, BFS 정리 (4) | 2020.12.15 |
[Java] 스택(Stack) 정리 및 구현 (1) | 2020.06.17 |
댓글
이 글 공유하기
다른 글
-
[Java] 다익스트라(Dijkstra) 알고리즘.
[Java] 다익스트라(Dijkstra) 알고리즘.
2021.05.28공부가 목적인 포스팅으로, 미흡한 점이 있다면 피드백 부탁드리겠습니다. 다익스트라로 불리는 이 알고리즘은 그래프의 가중치를 활용하여 최단 경로를 구하는 알고리즘입니다. 이 알고리즘은 어떤 한 정점(노드)에서 나머지 모든 정점(노드)에 대하여 최단 거리를 알려줍니다. 하지만 이때 단 하나의 음의 간선(음의 가중치)이 존재하면 안됩니다. 말 그대로 '최단 거리'를 구하고자 하는 것이기 때문에 음의 간선이 존재하면 최단 거리의 의미가 퇴색됩니다. 다익스트라 알고리즘은 그리디 알고리즘 + 다이나믹 프로그래밍(DP) 알고리즘을 합친 버전이라 볼 수 있습니다. 방문하지 않은 정점 중 가장 가중치가 적은 정점을 선택하는 방법(그리디) + 하나의 최단 거리를 구할 때 그 이전에 구한 최단 거리 정보를 이용하는 방법(D… -
[Java] 이분 탐색(Binary Search)
[Java] 이분 탐색(Binary Search)
2021.05.15공부를 목적으로 진행하는 포스팅으로 만약 틀린 부분이 있거나 미흡한 점이 있으면 피드백 부탁드리겠습니다. 이분 탐색 혹은 이진 탐색이라 불리는 이 알고리즘은 간단하면서 굉장히 효율적인 알고리즘입니다. 이 알고리즘을 수행하기 위해서는 기본적으로 정렬이 되어있어야 합니다. 정렬된 자료구조 안에서 특정 값을 찾을 때 절반씩 나누어 값을 찾는다는 것이 핵심적인 아이디어입니다. 이분 탐색은 탐색을 진행할 때마다 탐색 범위를 반으로 줄입니다. 분할 정복(Divide Conquer)알고리즘과 유사한데 이분 탐색은 분할 정복 알고리즘의 한 예입니다. 만약 탐색 범위가 더이상 나눠지지 않는 1이 될 때의 탐색 횟수를 T라고 하고, 정렬된 배열의 길이가 N인 자료구조에서 이분 탐색을 했을 경우의 시간 복잡도를 표로 보여드… -
[Java]투 포인터 / 슬라이딩 윈도우 알고리즘
[Java]투 포인터 / 슬라이딩 윈도우 알고리즘
2021.05.13 -
[Java] DFS, BFS 정리
[Java] DFS, BFS 정리
2020.12.15DFS( 깊이 우선 탐색 , Depth-First Search) 루트 노드( 혹은 다른 임의의 노드)에서 다음 분기(branch)로 넘어가기 전에, 해당 분기(branch)를 모두 탐색하는 방법. 탐색 후에는 다시 원점으로 돌아가 다른 분기를 탐색합니다. 특징 자기 자신을 호출하는 순환 알고리즘의 형태를 지닙니다. (재귀 or 스택) 이 알고리즘을 구현할 때 가장 큰 차이점은 그래프 탐색의 경우 어떤 노드를 방문했었는지 여부를 반드시 검사해야한다는 것입니다. (이를 검사하지 않을 경우 무한루프에 빠질 수 있다. ) ex) visit[index] = true; 미로를 탐색할 때, 해당 분기에서 갈 수 있을 때까지 계속 가다가 더 이상 갈 수 없게 되면 다시 가장 가까운 갈림길로(새로운 분기)로 돌아와서 다…
댓글을 사용할 수 없습니다.