def swap(arr, i, j):
	temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
    
    
def bubble_sort(list) :
	for i in range(list(len)):
    	for j in range(len(list)-i-1):
        	if list[j] > list[j+1]: 
            	swap(list,j,j+1) #뒤에 오는 원소가 더 크도록 위치 교환
                
# 개선된 선택정렬
def select_sort(list) :
	for i in range(len(list)):
    	min_idx = i
        for j in range(i+1,len(list)):
        	if list[j] < list[min_idx]:
            	min_idx = j
        swap(list,i,min_idx) # 버블정렬에서 사용된 swap 사용
                
def insert_sort(list):
	for i in range(1,len(list)):
    	target = list[i] # 삽입할 원소
    	for j in range(i-1,-1,-1):
        	if list[j] > target :
            	list[j+1]=list[j]
            else :
            	list[j+1] = target
def heapify(heap, index, heap_size):
	largest = index
    left_child_index = index*2
    right_child_index = index*2+1
    
    if (left_child_index < heap_size) and (heap[largest] > heap[left_child_index]) : #왼쪽 자식 노드가 존재하고, 부모 노드보다 작은 경우
    	largest = left_child_index
     if (right_child_index < heap_size) and (heap[largest] > heap[right_child_index]) : #오른쪽 자식 노드가 존재하고, 부모 노드보다 작은 경우
    	largest = right_child_index
      
      if index != largest : 
      	heap[largest],heap[index] = heap[index],heap[largest] # 자식노드와 부모 노드를 교환한다.
      	heapify(heap, largest, heap_size) # 자식노드를 루트노드로 하는 힙에 대해서 heapify를 수행한다.
    
def heap_sort(list):
	n = len(list)
	# 1. 최소힙 구성
	# 자식 노드를 갖는 마지막 노드부터 상향으로 heapify 진행한다.
    # 마지막 노드부터 수행하지 않아도 된다.
	for i in range(n//2-1,-1.-1):
    	heapify(list, i, n) 
    
    
    for i in range(n-1,0,-1):	
        list[i], list[1] = list[1], list[i] # 2. 루트 노드와 마지막 노드의 값을 교환한다.
        heapify(list, 0, i) # 3. 나머지 배열에 대해 heapify 수행
    
def merge_two_array(list, left, mid, right):
	temp_list=[]
    
    current_index = left
    left_index = left
    right_index = mid +1
    
    while (left_index <= mid) and (right_index <= right) :
    	if list[left_index] < list[right_index] :
	        temp_list[current_index] = list[left_index]
            left_index += 1
    	else :
        
        """
        not stable인 이유 :
        두 배열의 비교 대상이 동일한 원소인 경우,
        뒤쪽 배열에 위치한 원소를 먼저 옮기기 때문이다.
        """
	        temp_list[current_index] = list[right_index]
            right_index += 1
        current_index += 1
            
    #왼쪽 원소 완전히 옮기기
    while (left_index <= mid) : 
    	temp_list[current_index] = list[left_index]
        left += 1
        current_index += 1
        
    #오른쪽 원소 완전히 옮기기    
    while (mid+1 <= righ) : 
    	temp_list[current_index] = list[right]
        right += 1
        current_index += 1
	#결과 배열로 원소 옮기기
    for i in range(len(list)):
    	list[i] = temp_list[i]
        
def merge_sort(list, left, right):
	if left < right :
    	# 정렬 대상 분할하기
    	mid = (left+right)//2
        merge_sort(list,left,mid)
        merge_sort(list,mid+1,right)
        
        # 정렬 대상 합치면서 정렬하기
        merge_two_array(list,left,mid,right)
""" 
 윤성우의 열혈 자료구조 ver 
- 분할하는 부분과 정렬하는 부분을 두 함수로 구분
"""
def partition(list,left,right):
	low  = left+1
    high = right
    
    while low <= high :
    	while (low <= right) and (list[low] <= list[left]) :
        	low += 1
        while (left <= high) and (list[high] >= list[left]) :
        	high -= 1
        if low < high :
        	swap(list,low,high)
            
    swap(list, left, high)
    return high
    
def quick_sort(list, left, right):
	if left < right :
    	pivot = partition(list, left, right)
        quick_sort(list,left, pivot-1)
        quick_sort(list,pivot+1,right)
        
"""
일반적으로 많이 쓰이는 ver
- 하나의 함수 안에서 분할, 정렬을 모두 수행
- 피벗을 기준으로 세 배열로 나눈 후 이를 합치는 방법으로 정렬을 수행
"""
def quick_sort(list) :
	if len(list) <= 1:
    	return list
    pivot = list[0] # 배열의 중간값을 사용해도 됨
    
    # 각각 피벗보다 크기가 작은, 같은, 큰, 원소를 저장하는 리스트를 의미함
    less_list =[]
    equal_list=[]
    greater_list = [] 
    
    for i in list : 
    	if i > pivot :
        	greater_list.append(i)
        elif i == pivot :
        	equal_list.append(i)
        else:
        	less_list.append(i)
            
    return quick_sort(less_list) + equal_list + quick_sort(greater_list) 
    	
    	
(모든 정렬은 오름차순 기준으로 설명함.)