ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TIL #11 - 선택정렬, 클래스
    프로그래밍/TIL(국비과정) 2020. 4. 9. 19:50

    #SelectionSort (선택정렬 알고리즘)

    배열을 오름차순 또는 내림차순으로 정렬해주는 SelectionSort이다. 

    오름차순은 1, 2, 3... 

    내림차순은 3, 2, 1 이렇게 나열디는 것이다. 

     

    먼저 for문으로 배열을 한 번 오름차순 정렬해본다.

    public class SelectionSort {
    
    	public static void main(String[] args) {
    		int[] arr = new int[] {35, 24, 12, 48, 30};
    		int temp; // 임시 저장소 
    		
    		for(int i = 0; i < arr.length; i++) {
    			for(int k = 1+1; k < arr.length; i++) {
    				if(arr[i] > arr[k]) {
    					temp = arr[i]; 
    					arr[i] = arr[k];
    					arr[k] = temp;
    				}
    			}
    		}
    		
    		for(int data : arr) {
    			System.out.println(data + " ");
    		}
    
    	}
    
    }
    

     먼저 배열 arr을 만들어 5개의 요소를 넣었다. 


    저렇게 요소값이 지정된 배열을 만들 때 주의할 점은 아래와 같은 형태는 오류가 난다는 것이다. 

    		int[] arr = new int[5];
    		arr = {35, 24, 12, 48, 30};
    		
    
    		int[] arr = new int[5]{35, 24, 12, 48, 30};

    요소값을 넣을 때 배열의 크기를 지정해 놓고 요소값을 넣는 것은 안된다. 


    바깥쪽 for문은 배열의 길이-1만큼 실행된다.

    왜냐하면 i의 배열은 i+1의 배열과 비교하기 때문에 마지막 arr.length에 있는 배열은 비교할 필요가 없기 때문이다. 

    안쪽 for문의 경우엔 i+1부터 시작하는데 이는 첫번째 값을 비교할 기준점으로 정해놓고 그 다음 값부터 비교를 하기 때문에 굳이 0부터 시작할 필요가 없기 때문이다. 

    그래서 1부터 시작해서 차례차례 모든 요소들이 바로 뒤의 index값과 비교를 하기 때문에 i+1부터 시작해서 배열의 길이만큼 진행한다. 

    차례차례 요소들을 비교해가면서 i의 값이 i+1값인 k 보다 크다면 오름차순 정렬이기 때문에 i를 k위치로 바꿔준다. 

    배열을 바꿔줄 경우에는 임시저장소 temp를 만들어야 한다. 

     

    배열 그 자체는 공간의 개념이기 때문에 안의 내용물이 섞이지 않도록 바꿔주려면 

    하나를 임시저장소에 옮겨 놓고, 공간을 비워준 후 그 공간을 바꾸고자하는 요소로 채우고 

    그 빈 공간을 임시저장소에 있던 요소로 채워야한다. 

     

    코드를 보면, 임시저장소 temp에 arr[i] 값을 먼저 넣고 

    arr[i] 값에 arr[k] 값을 넣어준 후 

    arr[k]에 temp를 넣는다. 

    이렇게 내용물이 섞이지 않고 자리를 잘 바꿔준다.

     

    #위의 과정을 수행하주는 Sort()

    위에서는 일일이 for문을 만들고 temp를 만들어 배열을 오름차순 정렬해주었지만,  

    사실 자바 자체에서 위의 코드를 수행해주는 sort 메소드가 있다. 

    sort 메소드는 Arrays 클래스로부터 왔기 때문에 사용시엔 Arrays.sort() 라고 적어준다. 

    package date0409;
    
    import java.util.Arrays;
    
    public class SelectionSort {
    
    	public static void main(String[] args) {
    		int[] arr = new int[]{36, 24, 12, 48, 30};
    		
    		Arrays.sort(arr);
    
    	
    		
    		for(int data : arr) {
    			System.out.println(data + " ");
    		}
    
    	}
    
    }
    

     허무하지만 편리한 메소드이다. 

     

     

    # Class

    우리가 어떤 클래스를 만들 때 아래와 같이 클래스가 여러개일 수 있다. 

    class PersonTest{
    }
    class PersonMain{
    }

    그런데 우리는 클래스의 이름에 따라 파일명을 정해주어야한다. 

    이런 경우엔 어떻게 할까? 

    사실 위와 같은 상황은 없고, 

    보통 main 메소드가 붙어 있는 class 명을 따라 간다. 

    main 메소드가 붙어 있는 class가 파일 주인이라고 생각하면 된다. 

    만약 main 메소드가 없는 상황이라면 앞에 public을 붙여주면 그 class가 파일의 주인이 된다. (파일 이름이 된다)

     

     

    클래스 안에 필드를 만들면 아래와 같은 형태가 된다. 

    class PersonTest {
    	private String name;
        	private int age;
        ...
    }

    물론 private 외에 다른 접근제한자를 쓸 수도 있지만 일단 필드 생성시 private을 많이 쓰므로 private의 예를 보자. 

    위와 같이 필드 선언이 된 것들은 초기화가 이미 끝난 것들이다. 

    = null 이나 = 0을 붙여주지 않아도 null과 0을 이미 가지고 있다. 

    위의 속성들은 메모리에 잡힌 것이 아니고 본 클래스가 아래와 같은 속성을 가지고 있다라는 것을 명시해줄 뿐이다. 

     

    또, 위의 필드들은 같은 클래스 내, 즉 PersonTest에서만 사용할 수 있다. 

    그렇기 때문에 사용하기 위해선 set/get 메소드를 이용해서 다른 클래스와도 주고받을 수 있게 만들어줘야한다. 

    name이라는 속성을 사용하고 싶으면 먼저 setName (set필드명) 메소드를 만들어 입력받은 name 값을 받는다 

    그런 후 getName() (get필드명) 으로 name에 들어있는 값을 반환해준다. 

    이후 main 메소드에서 필드가 들어있는 클래스의 객체를 만들어 준다. 

    이 객체가 속성 name의 주소값을 가지고 있어서 name이 어디있는지 알려주는 것이다. 

    객체 이름.setName 으로 name값을 입력해 주고 

    객체 이름.getName으로 name값을 출력해준다. 

     

    아래와 같은 흐름이다. 

    class PersonTest{
    	private String name;
        ...
        
        public void setName(String n){
            name = n; // 아래에서 받은 이름을 받는다. 
        }
        ....
        
        public String getName(){
        	return name; // name에 들어 있는 값을 반환한다. 
        }
    }
    
    public class PersonMain{
    	public static void main(String[] args){
        	PersonTest pt = new PersonTest(); // 객체 생성
            
            pt.setName("양아무개");
            
            System.out.println(pt.getName()); // 양아무개 출력
            
        }
    }
    
    

     

    PersonTest는 한 사람에 대한 정보값이기 때문에 한사람의 정보값만 입출력 할 수 있다. 

    만약 여러명을 하고 싶다면 그 여러명 분의 객체를 또 다른 이름으로 만들어 주어야한다. 

    예를 들어 객체 pt로 한 사람의 name을 입출력 했고, 또 다른 사람의 name을 입출력하고 싶다면 

    PersonTest pt2 = new PersonTest();

    와 같이 다른 이름의 객체를 만들어 위의 set/get 과정을 다시 반복해야한다. 

    set/get의 메소드를 다시 만들어줄 필요는 없이 오직 객체만 다시 생성해주면 된다. 

     

    그런데 set의 경우에는 한 번에 여러값을 받게 묶어줄 수도 있다. 

    만약 name, age 이 두개의 값을 받고 싶다면 

    class PersonTest{
    	private String name;
        private int age; 
        
        public void setData(String n, int a){
        	name = n; 
            age = a;
            ....
        }
    }

    위와 같이 할 수도 있다. 

     

    # 오버로드 

    오버로는 한 클래스 내에서만 성립한다.

    즉 다른 클래스에선 성립하지 않는다. 

    아래와 같은 경우가 성립하지 않는 경우이다. 

    class A {
    	public void sub(int a){
        }
    }
    class B {
    	public void sub(double b){
        }
    }

    위의 두 메소드는 메소드 명이 같다고 하더라도 각각 다른 A와 B 클래스에 있기 때문에 오버로드가 성립되지 않는다. 

     

     

    # class 더...

    위와 같이 한 클래스에 모든 것을 다 넣어 줄 수도 있지만 

    보통은 다 분리해서 각자 다른 클래스에 넣어둔다. 

    필드와 set/get 메소드 따로 

    그리고 직접적인 실행이 일어나는 main 메소드 따로인 것이다. 

     

    아래의 예시를 보자. 

    학생의 성적을 받아 총점과 평균을 출력하는 프로그램이다. 

    먼저 필드와 set/get 메소드만 들어 있는 클래스이다. 

    SungJuk.java

    class SungJuk {
    	private String name; // 이름
    	private int kor, eng, math;  // 국영수 
    	private int tot; // 총점 
    	private double avg; // 평균
    	private char grade; // 성적 (A~F)
    

     속성은 위와 같다,

    위의 속성에 따른 set 메소드를 받아주는데 

    직접적인 계산이 필요한 총점 tot , 평균 avg, 성적 grade를 제외하고 

    입력을 받아야하는 이름 name, 국영수 각각은 하나로 묶어 set 메소드를 만든다. 

    // set
    	public void setData(String n, int k, int e, int m){
    		name = n;
    		kor = k;
    		eng = e;
    		math = m;
    	}

     

    총점 tot, 평균 avg, 성적 grade를 계산하는 메소드를 만든다. 

    // calc
    	public void calcTot(){
    		tot = kor + eng + math; 
    	// 이미 위의 set에서 값을 받았기 때문에 
    	// 여기서는 값을 받지 않아도 된다. 
    	}
    
    	public void calcAvg(){
    		avg = (double)tot/3.0;
    	}
    
    	public void calcGrade(){
    		
    		if(avg >= 90){
    			grade = 'A';
    		}else if(avg >= 80){
    			grade ='B';
    			
    		}else if(avg >= 70){
    			grade ='C';
    
    		}else if(avg >= 60){
    			grade ='D';
    	
    		}else {
    			grade ='F';
    		}
    
    
    	}

    위의 메소드들은 모두 이미 set에서 필요한 값들을 다 받았기 때문에 따로 값을 받을 필요 없이 

    속성값을 그대로 써서 메소드를 만들어주면 된다. 

    다음은 get 메소드이다. 

    
    	// get
    	public String getName(){
    		return name;
    	}
    	public int getKor(){
    		return kor;
    	}
    	
    	public int getEng(){
    		return eng;
    	}
    
    	public int getMath(){
    		return math;
    	}
    	
    	public int getTot(){
    		return tot;
    	}
    	
    	public double getAvg(){
    		return avg;
    	}
    	
    	public char getGrade(){
    		return grade;
    	}
    
    	
    }

     

    위의 속성들을 이용해서 학생의 성적을 입출력할 main 메소드이다.

    SungJukMain.java

    역시 먼저 속성값이 들어있는 class의 객체를 만들어 준다. 

    class SungJukMain{
    	public static void main(String[] args){
    		SungJuk sj = new SungJuk();

    그런 후 SungJuk 클래스의 set 메소드를 호출해 데이터를 입력한다. 

    sj.setData("양아무개",40,20,90);

    데이터 입력이 끝나면 

    각 데이터를 가지고 총점, 평균, 성적을 계산할 메소드를 호출한다 

    sj.calcTot();
    sj.calcAvg();
    sj.calcGrade();
    

     

    만약!! 

    학생을 또 추가하고 싶다면 객체를 다른 이름으로 또 만들어 주어야한다!

    	SungJuk sj2 = new SungJuk();
    		sj2.setData("김아무개",50,80,90);
    
    		sj2.calcTot();
    		sj2.calcAvg();
    		sj2.calcGrade();

     

    출력할 땐 get 메소드를 불러온다 

    System.out.println("이름\t\t국어\t영어\t수학\t총점\t평균\t학점");
    		System.out.print(sj.getName()+"\t"+sj.getKor()+"\t"+sj.getEng()+"\t"+sj.getMath()+"\t"+sj.getTot()+"\t"+
    			String.format("%.2f",sj.getAvg())+"\t"+sj.getGrade()+"\n");
    

      출력 시에도 객체에 따라 따로따로 해주어야한다. 

     

    '프로그래밍 > TIL(국비과정)' 카테고리의 다른 글

    TIL #13 - 생성자 응용 프로그램  (0) 2020.04.13
    TIL #12 - 클래스, 생성자  (0) 2020.04.10
    TIL #10 - 각 종 응용들  (0) 2020.04.08
    TIL #9 - 필드, 메소드  (0) 2020.04.07
    TIL #8 - 게시판 프로그램  (0) 2020.04.06

    댓글

Designed by Tistory.