[JAVA] 배열, 함수, 삽입정렬
오늘은 배열의 값을 랜덤으로 생성하고 삽입정렬을 통해 오름차순/내림차순으로 정렬하는 프로그램을 작성하였다.
[한글코딩]
시작 안내문 함수() {
삽입정렬 프로그램을 시작합니다! 출력
}
자료형 선택 함수() {
스캐너 선언
입력 저장할 변수 선언
언제 올바르게 입력할지 모르므로 무한루프 {
자료형을 선택해주세요! (char(문자)/int(정수)) 라고 출력
(c 혹은 i 입력 >> ) 라고 출력
입력받기
만약(금지어 함수()) {
대문자를 소문자로 변환
탈출
}
다시 입력해주세요!
}
입력값 리턴
}
금지어 함수(입력 저장할 변수) {
금지어를 담을 배열 선언 및 값 저장
진위형 변수 선언 = 거짓으로 초기화
반복-배열 크기만큼 돌면서 {
만약(배열과 겹치는 값이 있다면) {
진위형 변수 = 참
탈출
}
}
변수 반환
}
랜덤 배열 생성 함수(배열 변수) {
랜덤 변수 선언
반복문-배열 크기만큼{
문자라면{
랜덤값(65~90) 값 저장
}
숫자라면{
랜덤 값 저장
}
}
}
배열 전체 출력 함수(배열, 자료형 선택 변수) {
배열 복사체 출력
만약(c면) {
문자형으로 변환해서 출력
}
아니라면 {
숫자 출력
}
차순 입력 함수() {
스캐너 선언
차순 저장 변수 선언
몇번만에 옳게 입력할지 모른다-무한루프{
차순을 선택해주세요! (1. 오름차순 / 2. 내림차순) 출력
(숫자로 입력해주세요! >>) 출력
사용자 입력 받기
옳게 입력했다면{
탈출
}
에러 안내
}
입력받은 차순 반환
}
// 이하 삽입정렬 함수들
/*
* 차순별로 배열을 정렬하는 함수
*/
함수 보이드형 삽입정렬(정수 차순, 배열) {
삽입정렬이라 위치가 1부터 시작, 횟수가 분명하기에 반복문 사용{
변수 키값 선언
하위 반복 인덱스 선언
횟수가 분명하기에 반복문 사용{
만약(차순별정렬(차순, 키값, 하위 반복문의 현재 인덱스, 배열) 함수호출) { // 거짓이면 탈출
탈출
}
비교값 저장
}
키값을 저장
배열 전체 출력 함수(배열, 자료형 선택 변수)
}
}
/**
* 차순에 따라서 키값과 배열의 현재값을 비교한
* 배열의 다음값과 키값을 비교해야하면 참을 반환하고
* 더 이상 비교할 필요가 없으면 거짓을 반환한다
*/
함수 진위형 차순별정렬(정수 차순, 정수 키값, 정수 배열의 현재위치, 배열) {
만약 (오름차순이면서 키값이 더 크다면) { //누가큰지 호출
반환 참
}
만약 (내림차순이면서 키값이 더 작다면) {
반환 참
}
반환 거짓;
}
/**
* 정수1과 정수 2중에서 큰 값을 반환
*/
함수 정수형 누가큰지(정수1, 정수2) {
반환 정수1이 정수2보다 크다면 정수1 아니면 정수2
}
}
종료인사 함수() {
삽입정렬 프로그램을 종료합니다! 출력
}
public static void main(String[] args) {
시작 안내문 함수();
자료형 선택 변수 선언 및 자료형 선택 함수() 초기화
배열 크기 상수 선언
배열 선언
랜덤 배열 생성 함수(배열 변수);
배열 전체 출력 함수(배열, 자료형 선택 변수)
삽입정렬(차순 입력 함수(), 배열); 함수 호출
종료인사 함수();
}
}
함수는 9개 생성하였다.
함수화 부분 한글 코딩하는데 로직이 쉽게 떠오르지 않는다 ㅠㅠ
이번주 목표는 한글 코딩을 그대로 코드로 바꾸면 바로 작동시킬 수 있도록 정확한 한글 코딩하기!!
자꾸 코드를 설명하려는 식의 한글 코딩을 하게 되는 것 같다. 코드를 한글로 먼저 작성하는 것이지 한글 설명을 달고자 하는게 아닌데..
[작성 코드]
public class Test {
public static void hello() { //시작 안내문 함수() {
System.out.println("삽입정렬 프로그램을 시작합니다."); // 삽입정렬 프로그램을 시작합니다! 출력
}
public static void bye() { // 종료인사 함수()
System.out.println("삽입정렬이 완료! 프로그램을 종료합니다."); //삽입정렬 프로그램을 종료합니다! 출력
}
public static String inputDataType() { // 자료형 선택 함수
Scanner sc = new Scanner(System.in); // 스캐너 변수 선언
String dataType; // 입력 저장할 변수 선언
while(true) { // 언제 올바르게 입력할지 모르므로 무한루프
System.out.println("원하시는 자료형을 선택해주세요! ( char=문자 / int=정수 )"); // 자료형을 선택해주세요! (char(문자)/int(정수)) 라고 출력
System.out.println("=====================");
System.out.print("c 혹은 i를 입력해주세요 >> "); // (c 혹은 i 입력 >> ) 라고 출력
dataType = sc.next(); // 입력받기
System.out.println("=====================");
if(hasInputDataType(dataType)) { // 만약(금지어 함수())
dataType = dataType.toLowerCase(); // 대문자를 소문자로 변환
break; // 탈출
}
System.out.println("옳지 않은 입력입니다! 다시 입력해주세요."); // 다시 입력해주세요!
}
System.out.println(); // 줄바꿈
return dataType; // 입력값 리턴
}
public static boolean hasInputDataType(String dataType) { // 금지어 함수(입력 저장할 변수)
String[] checkDatas = new String[4]; // 금지어를 담을 배열 선언 및 값 저장
checkDatas[0]= "c";
checkDatas[1]= "C";
checkDatas[2]= "i";
checkDatas[3]= "I";
boolean flag = false; // 진위형 변수 선언 = 거짓으로 초기화
for(String v : checkDatas) { // 반복-배열 크기만큼 돌면서
if(v.equals(dataType)) { // 만약(배열과 겹치는 값이 있다면)
flag = true; // 진위형 변수 = 참
break; // 탈출
}
}
return flag; // 변수 반환
}
public static void printDatas(int[] datas, String dataType) { // 배열 전체 출력 함수()
System.out.print("배열 : [ ");
for(int v : datas) { // 배열 복사체 출력
if(dataType.equals("c")) { // c라면
System.out.print((char)v+" "); // 문자로 출력
}
else {
System.out.print(v+" "); // 숫자 출력
}
}
System.out.println("]");
}
public static void printDatas1(int[] datas, String dataType) { // 배열 전체 출력 함수()
System.out.print("배열 : [ ");
if(dataType.equals("c")) {
for(int v : datas) {
System.out.print((char)v+" "); }
} else {
System.out.print(v+" "); // 숫자 출력
}
System.out.println("]");
}
public static int inputOrder() { // 차순을 입력받는 함수
Scanner sc = new Scanner(System.in); // 스캐너 변수 선언
// 저장변수
int order; // 차순을 저장할 변수 선언
while(true) { // 무한루프
System.out.println("차순을 선택해주세요! (1. 오름차순 / 2. 내림차순)");
System.out.print("숫자로 입력해주세요! >>");
order = sc.nextInt(); // 숫자로 입력받음
if(order == 1 || order == 2) { // 옳은 답을 입력하면 탈출
break;
}
System.out.println("올바른 숫자를 입력해주세요!"); // 에러 메시지
}
return order; // 입력한 차순 반환
}
public static void createList(int[] datas, String dataType) { // 랜덤 배열 생성 함수(배열, 문자열)
Random rand = new Random(); // 랜덤 변수 선언
for(int i = 0; i < datas.length; i++) { //반복문-배열 크기만큼
if(dataType.equals("c")) { // 문자라면
datas[i] = rand.nextInt(26)+65; // 랜덤값(65~90) 값 저장
} else { // 숫자라면
datas[i] = rand.nextInt(21)-10; // 랜덤 값 저장
}
}
}
/**
* 삽입정렬을 실행하는 함수
* parameters: int 차순, int[] 정렬할 배열
*/
public static void insertionSort(int order, int[] datas, String dataType) { //함수 보이드형 삽입정렬(정수 차순, 배열)
for (int i = 1; i < datas.length; i++) { //삽입정렬이라 위치가 1부터 시작, 횟수가 분명하기에 반복문 사용{
int key = datas[i]; //변수 키값 선언
int index; //하위 반복 인덱스 선언
for (index = i - 1; index >= 0; index--) { //횟수가 분명하기에 반복문 사용
if (sortByOrder(order, key, datas[index])) { //현재 인덱스에 key가 들어가야하는 조건이라면
break; //탈출
}
datas[index+1] = datas[index]; //비교값 저장
}
datas[index+1] = key; //키값을 저장
printDatas(datas, dataType); //배열 전체 출력 함수()
}
}
/**
* 차순별로 키값과 현재값을 비교하여 종료조건에 해당하는지 아닌지를 진위형 값으로 반환하는 함수
* parameters:int 차순, int 키값, int 현재값
* return: boolean
*/
public static boolean sortByOrder(int order, int key, int curVal) { //함수 진위형 차순별정렬(정수 차순, 정수 키값, 정수 배열의 현재위치, 배열) {
if (order == 1 && key >= curVal) { //만약 (오름차순이면서 키값이 더 크다면)
return true; //반환 참
}
else if (order == 2 && key <= curVal) { //만약 (내림차순이면서 키값이 더 작다면)
return true; // 반환 참
}
return false; // 반환 거짓
}
public static void main(String[] args) {
hello(); // 시작 안내문 함수();
String dataType = inputDataType(); // 자료형 선택 변수 선언 및 자료형 선택 함수() 초기화
final int SIZE = 10; // 배열 크기 상수 선언
int[] datas = new int[SIZE]; // 배열 선언
createList(datas, dataType); //랜덤 배열 생성 함수(배열 변수);
int order = inputOrder(); // 함수에서 차순 입력 받아 변수에 저장
System.out.println("정렬 전 배열:");
printDatas(datas, dataType); // 배열 전체 출력 함수();
insertionSort(order, datas, dataType); // 삽입정렬
System.out.println("정렬 완료 후 배열:");
printDatas(datas, dataType); // 배열 전체 출력 함수();
bye(); // 종료인사 함수();
}
}

[피드백]
1. 함수화 : 기능이 다르다고 생각하면 함수화 하기
-> 문자로 배열 채우는 경우, 정수로 채우는 경우를 하나의 함수로 함께 작성했는데 따로 두는 게 더 좋았을 것 같다는 생각이 든다.
2. 효율성 고려 : 데이터의 크기가 커질 경우 해당 조건문을 커진 크기만큼 더 돌기 때문이다. (연산 횟수 최소화 필요)
-> for문을 밖에 뒀는데 if문을 밖에 두고 조건에 맞는 경우에만 반복하도록 수정하면 연산 횟수를 줄일 수 있다!!
3. 코드 다시 확인하기 : 쓸모없는 파라미터 놔두지 말고 지우기
-> 코드를 . 정확히. 보자. .... 제발
+ ) 삽입정렬.. 그림으로만 봤을 땐 키값과 앞에 있는 요소들을 비교해서 키값이 더 작을 경우 해당 요소들을 뒤로 밀어내고 키값을 삽입한다고 이해했는데, 코드를 작성할 때는 요소를 밀어낸다는 말의 의미가 그게 아니라는 점을 알았다.
그림으로 보면 밀어낸다고 하지만.. 애초에 배열에는 빈 공간이라는 게 존재하지 않아 요소를 밀어낸다고 해서 밀어낸 요소의 공간이 비어있게 되는 것이 아니라는 거다.
비어있는 공간이 아니고, 그 이전 요소를 복사해서 덮어씌우는 것이란 걸 알았다.
알고리즘 어렵다..