수업 중 설명드렸던 퀵정렬 코드와 함께 설명을 추가한 버전
둘 중 편한 버전으로 보셔요 같은 내용입니다.
package test;
public class Loop {
public static void main(String[] args) {
int[] list = new int[10];//
for(int i = 0 ; i < 10 ; i++ ) {
list[i] = (int) (Math.random()*100)+1;//임의의수 10개를 고름
System.out.print(list[i]+" ");
}
sort(null, 0, list.length-1);
System.out.println("\n===========================");
for(int i = 0 ; i < 10 ; i++ ) {
System.out.print(list[i]+" ");
}
}
private static void sort(int[] num,int l, int r) {
int pivot = num[(r+l) / 2]; // 배열의 중간 인덱스의 "값"(value)가 비교값(pivot)으로 할거에요.
while(l<=r) { // 투 포인터로 l(left), r(right)를 사용할거에요.
// left는 right를 넘어가면 의미가 없어져요. 그렇다면 제외할거에요.
// left는 right와 교환하는 것이 역할이에요. right도 그렇구요. 그러니까 둘은 위치가 바뀌면 의미가 없어져요.
// while문의 조건은 true일때 내부의 반복문이 수행돼요. l은 시작부터 시작하니 0으로 시작하고, 조건에 맞는 값까지 내부에서 증가시킬거에요.
// while은 false가 나면 loop가 종료되지만, loop의 시작시점에 판단하고 이후에 값이 바뀐다고 중간에 종료되지 않아요.
while(pivot>=num[l] && num.length-1>=l) { // 특정한 값으로 설정한 pivot과 비교해, l(left)포인터가 가리키는 값이 pivot보다 크면 r(right)포인터가 가리키는 값과 바꿀 준비를 해요.
// pivot은 값을 루프전에 세팅하고, 그 값과 비교해 더 작은값과(left) 더 큰 값(right)을 바꾸면
// 결과적으로 전체 배열은 어느 시점을 기준으로 pivot을 기준으로 더 작은 값과 더 큰값으로구분되게 돼요.
// ex) pivot이 임의의 기준으로 5일때, 3 2 1 5 9 처럼 순서는 보장되지 않아도 기준값으로 구분돼요 ( 물론, 몇 개 뽑아 평균을 내면 요소(elemnet)중에 일치하는 값이 없을수도 있어요
// l(left)이 특수한 상황에 따라 배열의 끝값까지 갈 수 있어야 하기 때문에 ( 0 0 0 0 0 )
// 배열의 끝 ( num.length-1 ) 까지 갈 수 있어야해요
// 그리고 r(right)와 바꿔야하는 순간이 올때는 지금의 바깥루프 ( while(l<=r) ) 의 한 루프안에서는 바깥으로 나가야하기 때문에
// pivot(기준값)보다 크면 r과 바꿔야 하기때문에 l(left)가 가리키는 값을 pivot(기준값)보다 작거나 같아야 해요
/*
3 2 3 으로 배열이 있어요. 이때 pivot을 3으로 한다면
L R 일때,
L을 다루는 while에서는 pivot과 같을경우 처음의 3을 통과하고, 다음 2는 left에 있어야하니 통과하고, 마지막칸인 3에 멈출거에요.
R을 다루는 while에서도 pivot과 같은 경우인 3을 통과하고, 2는 left로 가야하기때문에 멈출거에요.
3 2 3
R L
이렇게 될거에요. 그렇다면 이때는 두 값을 바꾸면 안돼요. 2는 pivot인 3보다 작으니까 왼쪽으로 가야하는데 L은 3이고, 2보다 크기때문에 결국 요건이 안맞아요
이땐 가장 바깥의 while(l<=r)처럼 l이 더 커지면 교환을 하면 안돼요.
그렇다고 R, L에서 값을 따로 비교해서 이걸 다음 분할의 분기로 삼기 명확하지 않아요.
그러면 R을 다루는 while에서 pivot과 같은 경우 통과하지 않는다면 처음의 3에 멈출거니
3 2 3
L
R
이렇게 되고, 이때의 L과 R의 index를 다음 분기의 분기점 (pivot)으로 하면 이 3을 기준으로 왼쪽은 같거나 작은 값들이 존재하게 되고, 여기서 정렬하게 되면 이후에 2 3 3이 성립하게 될거에요.
반대로,
3 4 3 으로 배열이 있어요, 이때도 pivot을 3으로 한다면
L R 일때,
L을 다루는 while에서는 pivot과 같을경우 통과하니 처음 3을 통과하고, 4에서 멈출거에요.
R을 다루는 while에서는 pivot과 같을경우 통과하면 처음의 3을 통과하고, R은 pivot보다 작은값에 멈출테니 배열의 끝인 왼쪽의 3에서 멈추게 될거에요
3 4 3
R L
이렇게 되고, 이땐 값을 바꾸면 더 큰값인 4가 왼쪽으로 가고 그렇다고 멈추기에는 다음 분기의 pivot을 정하기도 불확실해져요.
대신, R을 다루는 while에서 pivot과 같은경우 멈추게 설정하면
3 4 3
L
R
이 되고, 둘의 요건이 맞으므로 ( L은 pivot보다 더 큰값, R은 pivot
*/
//피벗을 기준으로 피벗보다 오른쪽을 포인터 하지 못하도록 조건을 걸어줌
l++;
}
while(pivot<=num[r] && r>=0) {//피벗의 왼쪽에는 피벗보다 작은 값이 정렬되도록 하기위해서, 피벗보다 큰 값이 나올때까지 반복(같으면 넘어감)
r--;
}
swap(num, l, r);
}
}
public static void swap(int[] num,int l, int r) {
//피벗을 기준으로 오른쪽 값고 왼쪽값을 바꾸는 함수
int temp = num[l];
num[l] = num[r];
num[r]= temp;
}
public static void partition() {
}
}
'알고리즘' 카테고리의 다른 글
3차원 배열, 1차원 배열 같은 데이터라면 속도차이 (0) | 2023.11.06 |
---|---|
페이징에 대한 이해 (0) | 2023.04.24 |
분수의 덧셈 ( 프로그래머스 문제, 코드 없음 ) (1) | 2023.04.24 |
BOJ3052 - 서로 다른 나머지의 개수 (0) | 2022.01.13 |
StringBuilder, StringBuffer (0) | 2022.01.11 |