Data Structures & Algorithms with Javascript : Sorting Algorithms (basic)
2024.07.26 - [๐ชฒ debug] - Data Structures & Algorithms with Javascript : Graphs and Graph Algorithms Data Structures & Algorithms with Javascript : Graphs and Graph Algorithms2024.07.25 - [๐ค data structures & algorithms] - Data Structures & Algorithm
pyotato-dev.tistory.com
๐ฉ๐ป๐ป ์ด์ ํฌ์คํ ์์๋ ๊ธฐ๋ณธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ธ ๋ฒ๋ธ ์ ๋ ฌ, ์ ํ ์ ๋ ฌ, ๊ทธ๋ฆฌ๊ณ ์ฝ์ ์ ๋ ฌ์ ๋ํด ์์๋ดค๋ค.
๐ ์ด๋ฒ์๋ ๋ง์ ๋ฐ์ดํฐ๊ฐ ์์ ๋ ํจ์จ์ ์ผ๋ก ์ ๋ ฌํ ์ ์๋ ์ข ๋ ์ฌํ๋ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ๋ค์ ๋ํด ์์๋ณด์.
โ๏ธ ์ค๋ ์ดํด๋ณผ ์๊ณ ๋ฆฌ์ฆ : Shellsort, Mergesort, Quicksort
The Shellsort Algorithm
Shellsort๋ ๊ฐ๋ฐํ Donald Shell์์ ๋ฐ์จ ์ด๋ฆ์ด๋ค. ์ด์ ์ดํด๋ณธ ์ฝ์ ์ ๋ ฌ์ ๊ฐ์ ํ ๋ฒ์ ์ด๋ค.
Shellsort๋ ์ธ์ ํ ์๋ฆฌ๋จผํธ๋ฅผ ๋จผ์ ์ดํด๋ณด๋ ๋์ ๊ฐ์ฅ ๋จผ ์๋ฆฌ๋จผํธ๋ค์ ๋น๊ตํ๋ค.
๊ฐ์ฅ ๋จผ ์๋ฆฌ๋จผํธ๋ค์ gap์ ์ ์ ์ค์ฌ๊ฐ๋๋ฐ, ์ด gap ์ํ์ค๋ Marcin Ciura์ ๋ ผ๋ฌธ(“Best Increments for the Average Case of Shell Sort”, 2001)์์ Shellsort์ ํ๊ท gap ์ํ์ค์ธ 701, 301, 132, 57, 23, 10, 4, 1์ผ๋ก ์ ์ํ ๊ฒ์ ํ์ฉํ ๊ฒ์ด๋ค.
๋ค์์ gap ์ํ์ค๋ฅผ ๊ฐ๊ฐ 3,2,1๋ก ์ค์ ํ์ ๊ฒฝ์ฐ๋ฅผ ๋ณด์ฌ์ค๋ค.
gap ์ํ์ค = 3์ธ ๊ฒฝ์ฐ shellSort ์์๋ฅผ ์ดํด๋ณด์.
61 85 19 88 68 8 70 29 (์์)
61 85 19 88 68 8 70 29
61 8 19 88 68 85 70 29
61 8 19 88 68 85 70 29
61 8 19 29 68 85 70 88 (gap = 1 ๋ก ์ค์ด๊ธฐ)
8 19 61 29 68 85 70 88
8 19 29 61 68 85 70 88
8 19 29 61 68 70 85 88 (์๋ฃ)
๊ตฌํ
์์ ์์์์ ์ดํด๋ดค๋ฏ์ด ์ ํด์ง gap(๊ฐ๊ฒฉ)๋งํผ ๋ฐฐ์ด ์ ์ฒด๋ฅผ ์ํํ๋ฉด์ gap ๋ด๋ถ์ ๊ฐ๋ค์ ๋น๊ตํด์ ์ ๋ ฌํ๋ค.
์ ์ gap์ ์ค์ด๋ฉด์ ์์ ๊ฐ์ด ์ค๋ฅธ์ชฝ์ ์ค๋๋ก ์๋ฆฌ๋ฅผ ๋ฐ๊ฟ์ฃผ๋ค ๋ณด๋ฉด ์ ๋ ฌ์ด ๋๋ค.
gap์ด 1์ผ ๊ฒฝ์ฐ ์ฝ์ ์ ๋ ฌ๊ณผ ๋์ผํ ๋งค์ปค๋์ฆ์ผ๋ก ์ ๋ ฌ์ ํด์ฃผ๊ณ ์๋ค.
shellSort ๋งค์๋๋ฅผ ๊ตฌํํด ๋ณด์.
์ธ๋ถ for ๋ฃจํ๋ฅผ ๋๋ฉด์ gap์ ์ํํ๋ค. ์์ ์์์์๋ gap ๋ฐฐ์ด์ด [3,1]๋ก ์ด๋ฃจ์ด์ง ๊ฒฝ์ฐ๋ค.
๋ด๋ถ for ๋ฃจํ์์๋ ์ ๋ ฌํ๊ณ ์ํ๋ ๋ฐฐ์ด์ ์ฒซ ์์์ gap ๋งํผ์ ๋จ์ด์ง ์ธ๋ฑ์ค์ ์์นํ ์์์ ๋์๋ฅผ ๋น๊ตํ์ฌ ๊ฐ์ด ์์ ๊ฑฐ๋ฅผ ๋ฐฐ์ด ์์ ์ค๋๋ก ์๋ฆฌ๋ฅผ ๋ฐ๊ฟ์ค๋ค.
์๋ฅผ ๋ค์ด, ํ์ฌ gap์ด 3์ผ ๋ ๋ชจ๋ ๋ฐฐ์ด ์์ 0๊ณผ 3, 1๊ณผ 4, 2์ 5... ๋์ ๋น๊ต๋ฅผ ํด์ ์๋ฆฌ๋ฅผ ๋ฐ๊ฟ์ค๋ค. ๋ชจ๋ ์๋ฆฌ๋ฐ๊ฟ์ด ๋๋ ๋ค, gap์ด 1์ผ ๋, ๋ชจ๋ ๋ฐฐ์ด ์์ 0๊ณผ 1, 1๊ณผ 2, 2์ 3... ๋์ ๋น๊ต๋ฅผ ํด์ ์๋ฆฌ๋ฅผ ๋ฐ๊ฟ์ฃผ๋ฉด ์ ๋ ฌ์ ์๋ฃํ๋ค.
shellSort(){
for (let g = 0; g < this.gaps.length; ++g) {
for (let i = this.gaps[g]; i < this.dataStore.length; ++i) {
let temp = this.dataStore[i];
for (let j = i; j >= this.gaps[g] && this.dataStore[j-this.gaps[g]] > temp; j -= this.gaps[g]) {
this.dataStore[j] = this.dataStore[j - this.gaps[g]];
}
this.dataStore[g] = temp;
}
}
}
๋จ์ ์ฝ์ ์ ๋ ฌ๋ณด๋ค gap์ ์ค์ฌ๊ฐ๋ฉด์ ๋น๊ต๋ฅผ ํ๊ธฐ ๋๋ฌธ์ ๋ ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ์ด๋ค.
๋ค์ ๋งํด, ์ฝ์ ์ ๋ ฌ์ ์ ๋ ฌ์ด ์๋ฃ๋ ๋๊น์ง ๋ชจ๋ ์์๋ค์ ๋น๊ตํด์ผ ํ๋ฏ๋ก ๋ฐฐ์ด์ ๋๊น์ง ์ํ๋ฅผ ๋ฐ๋ณตํด์ผํ๋ค.
ํ์ง๋ง gap=5์ธ ๊ฒฝ์ฐ ๋ชจ๋ ๋ฐฐ์ด์์๋ค์ ์ํํ๋ ๊ฒ์ด ์๋๋ผ ๋ฐฐ์ด ๊ธธ์ด -5 ๋งํผ ์ํํ๊ณ , ๊ทธ๋ค์์๋ gap =3 ์ธ ๊ฒฝ์ฐ์๋ q๋ฐฐ์ด ๊ธธ์ด -3, ๊ทธ ๋ค์ gap=1์ธ ๊ฒฝ์ฐ์๋ ์ด๋ฏธ ์ ๋ ฌ์ด ๋ง์ด ๋ ๋ฐฐ์ด ๊ธธ์ด๋ฅผ ๋๊ธฐ ๋๋ฌธ์ ํจ์จ์ ์ด๋ค.
๐ ์ ์ฒด ์ฝ๋
class CustomArray{
constructor(numElements){
this.dataStore = [];
this.pos = 0;
this.numElements = numElements;
for (let i = 0; i < numElements; ++i) {
this.dataStore[i] = i;
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
this.gaps = [5,3,1];
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
}
// ์ฝ์
insert(element){
this.dataStore[this.pos++] = element;
}
// ์ถ๋ ฅ ํฌ๋ฉงํด์ฃผ๊ธฐ ์ํ ํฌํผํจ์
toString(){
let retstr = "";
for (let i = 0; i < this.dataStore.length; ++i) {
retstr += this.dataStore[i] + " ";
if (i > 0 && i % 10 == 0) {
retstr += "\n";
}
}
return retstr;
}
// ์ ๊ฑฐ
clear(){
for (let i = 0; i < this.dataStore.length; ++i) {
this.dataStore[i] = 0;
}
}
// ๋๋ค ๋ฐ์ดํฐ ์์ฑ
setData(){
for (let i = 0; i < this.numElements; ++i) {
this.dataStore[i] = Math.floor(Math.random() * (this.numElements+1));
}
}
// index1 ๊ณผ index2์ ์๋ฆฌ ๋ณ๊ฒฝ
swap(arr, index1, index2){
let temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
bubbleSort(){
let numElements = this.dataStore.length;
let temp;
for(let outer = numElements; outer >=2; --outer){
for(let inner = 0; inner <= outer-1; ++inner){
if(this.dataStore[inner] > this.dataStore[inner+1]){
this.swap(this.dataStore, inner, inner+1);
}
}
}
}
selectionSort(){
let min,temp;
for(let outer = 0; outer <= this.dataStore.length-2; ++outer){
min = outer;
for(let inner = outer+1; inner <= this.dataStore.length-1; ++inner){
if(this.dataStore[inner] < this.dataStore[min]){
min = inner;
}
this.swap(this.dataStore, outer, min);
}
}
}
insertionSort(){
let temp, inner;
for(let outer = 1; outer <= this.dataStore.length-1; ++outer){
temp = this.dataStore[outer];
inner = outer;
while(inner > 0 && (this.dataStore[inner-1] >= temp)){
this.dataStore[inner] = this.dataStore[inner-1];
--inner;
}
this.dataStore[inner] = temp;
}
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
setGaps(arr){
this.gaps = arr;
}
shellSort() {
for (let g = 0; g < this.gaps.length; ++g) {
for (let i = this.gaps[g]; i < this.dataStore.length; ++i) {
let temp = this.dataStore[i];
let j;
for (j = i; j >= this.gaps[g] && this.dataStore[j - this.gaps[g]] > temp; j -= this.gaps[g]) {
this.dataStore[j] = this.dataStore[j - this.gaps[g]];
}
this.dataStore[j] = temp;
}
}
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
}
const print = item => console.log(item);
let numElements = 10;
let myNums = new CustomArray(numElements);
myNums.setData();
print(myNums.toString());
myNums.shellSort();
print('์ ๋ ฌ ํ:');
print(myNums.toString());
/**
9 6 9 10 7 5 9 7 3 7
์ ๋ ฌ ํ:
3 5 6 7 7 7 9 9 9 10
*/
๋ ผ๋ฌธ์์ ์ ํ gap ์ํ์ค๊ฐ ์ ๋ง ์ ์ผ ํจ์จ์ ์ผ๊น?
์ด๋ฒ์๋ gap ์ํ์ค๋ฅผ ๋์ ์ผ๋ก ๊ณ์ฐํ๋ ๊ฒฝ์ฐ๋ฅผ ํ๋ฒ ์ดํด๋ณด์.
๋ค์์ Robert Sedgewick์ด ๊ตฌ์ํ gap ์ํ์ค๋ฅผ ๋์ ์ผ๋ก ๊ณ์ฐํ ์ ์๋ ์ฝ๋๋ค.
let N = this.dataStore.length;
let h = 1;
while (h < N/3) {
h = 3 * h + 1;
}
gap ๊ฐ์ด ๊ฒฐ์ ๋๋ฉด ์ด์ ๋ฐฉ์๋๋ก shellsort์ด ๋์ํ๋ค. ๋ค๋ง ์ฐจ์ด์ ์ ์ธ๋ถ for ๋ฃจํ๋ก ๋์๊ฐ๊ธฐ ์ ์ ์๋ก์ด gap ๊ฐ์ ๊ณ์ฐํ๋ค.
dynamicGapShellSort(){
let N = this.dataStore.length;
let h = 1;
while (h < N/3) {
h = 3 * h + 1;
}
while(h >= 1){
for(let i = h; i < N; i++){
for(let j =i; j>=h && this.dataStore[j] < this.dataStore[j-h]; j -= h){
this.swap(this.dataStore,j,j-h);
}
}
h = (h-1)/3;
}
}
๐ ์ ์ฒด ์ฝ๋
class CustomArray{
constructor(numElements){
this.dataStore = [];
this.pos = 0;
this.numElements = numElements;
for (let i = 0; i < numElements; ++i) {
this.dataStore[i] = i;
}
this.gaps = [5,3,1];
}
// ์ฝ์
insert(element){
this.dataStore[this.pos++] = element;
}
// ์ถ๋ ฅ ํฌ๋ฉงํด์ฃผ๊ธฐ ์ํ ํฌํผํจ์
toString(){
let retstr = "";
for (let i = 0; i < this.dataStore.length; ++i) {
retstr += this.dataStore[i] + " ";
if (i > 0 && i % 10 == 0) {
retstr += "\n";
}
}
return retstr;
}
// ์ ๊ฑฐ
clear(){
for (let i = 0; i < this.dataStore.length; ++i) {
this.dataStore[i] = 0;
}
}
// ๋๋ค ๋ฐ์ดํฐ ์์ฑ
setData(){
for (let i = 0; i < this.numElements; ++i) {
this.dataStore[i] = Math.floor(Math.random() * (this.numElements+1));
}
}
// index1 ๊ณผ index2์ ์๋ฆฌ ๋ณ๊ฒฝ
swap(arr, index1, index2){
let temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
bubbleSort(){
let numElements = this.dataStore.length;
let temp;
for(let outer = numElements; outer >=2; --outer){
for(let inner = 0; inner <= outer-1; ++inner){
if(this.dataStore[inner] > this.dataStore[inner+1]){
this.swap(this.dataStore, inner, inner+1);
}
}
}
}
selectionSort(){
let min,temp;
for(let outer = 0; outer <= this.dataStore.length-2; ++outer){
min = outer;
for(let inner = outer+1; inner <= this.dataStore.length-1; ++inner){
if(this.dataStore[inner] < this.dataStore[min]){
min = inner;
}
this.swap(this.dataStore, outer, min);
}
}
}
insertionSort(){
let temp, inner;
for(let outer = 1; outer <= this.dataStore.length-1; ++outer){
temp = this.dataStore[outer];
inner = outer;
while(inner > 0 && (this.dataStore[inner-1] >= temp)){
this.dataStore[inner] = this.dataStore[inner-1];
--inner;
}
this.dataStore[inner] = temp;
}
}
setGaps(arr){
this.gaps = arr;
}
shellSort() {
for (let g = 0; g < this.gaps.length; ++g) {
for (let i = this.gaps[g]; i < this.dataStore.length; ++i) {
let temp = this.dataStore[i];
let j;
for (j = i; j >= this.gaps[g] && this.dataStore[j - this.gaps[g]] > temp; j -= this.gaps[g]) {
this.dataStore[j] = this.dataStore[j - this.gaps[g]];
}
this.dataStore[j] = temp;
}
}
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
dynamicGapShellSort(){
let N = this.dataStore.length;
let h = 1;
while (h < N/3) {
h = 3 * h + 1;
}
while(h >= 1){
for(let i = h; i < N; i++){
for(let j =i; j>=h && this.dataStore[j] < this.dataStore[j-h]; j -= h){
this.swap(this.dataStore,j,j-h);
}
}
h = (h-1)/3;
}
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
}
const print = item => console.log(item);
let numElements = 10;
let myNums = new CustomArray(numElements);
myNums.setData();
print(myNums.toString());
myNums.dynamicGapShellSort();
print('์ ๋ ฌ ํ:');
print(myNums.toString());
/**
0 3 6 4 4 1 7 3 7 5
์ ๋ ฌ ํ:
0 1 3 3 4 4 5 6 7 7
*/
๋ค์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ๋ค์ ์ดํด๋ณด๊ธฐ ์ ์ ๋ gap ์ํ์ค์ ๋ฌ๋ ํ์์ ๋น๊ตํด ๋ณด์!
๋ ๋ฐฉ๋ฒ ๋ชจ๋ ํจ์จ์ฑ์ ๊ฐ๋ค๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
let nums = new CustomArray(10000);
nums.setData();
let start = new Date().getTime();
nums.shellSort();
let stop = new Date().getTime();
let elapsed = stop - start;
print("Shellsort with hard-coded gap sequence: " + elapsed + " ms.");
nums.clear();
nums.setData();
start = new Date().getTime();
nums.dynamicGapShellSort();
stop = new Date().getTime();
print("Shellsort with dynamic gap sequence: " + elapsed + " ms.");
/**
Shellsort with hard-coded gap sequence: 16 ms.
Shellsort with dynamic gap sequence: 16 ms.
Shellsort with hard-coded gap sequence: 27 ms.
Shellsort with dynamic gap sequence: 27 ms.
Shellsort with hard-coded gap sequence: 29 ms.
Shellsort with dynamic gap sequence: 29 ms.
*/
The Mergesort Algorithm
Mergesort์ ์ ๋ ฌ๋ sublist๋ค์ merge(ํฉ๋ณ)ํด์ ์์ ํ๊ฒ ์ ๋ ฌ๋ ๋ฆฌ์คํธ๋ฅผ ๋ง๋ ๋ค๋ ์ ์์ ์ด๋ฆ์ ์ง์๋ค.
์ด๋ก ์ ์ผ๋ก mergesort ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํํ๊ธฐ ์ด๋ ต์ง ์๋ค.
๋ ๊ฐ์ ์ ๋ ฌ๋ ๋ถ๋ถ ๋ฐฐ์ด๋ค๊ณผ ์ด ๋ ๋ฐฐ์ด๋ค์ ๋์ ๊ด๊ณ๋ฅผ ๋น๊ตํ์ฌ ํฉ์น ์ธ ๋ฒ์งธ ๋ฐฐ์ด๋ง ์์ผ๋ฉด ๋๋ค.
ํ์ง๋ง ์ค์ ๋ก ๊ตฌํํ๊ณ ์ ํ ๋๋ ์์ฒญ ๋ง์ ๋ฐ์ดํฐ๋ค์ ๋ค๋ค์ผ ํ๋ค๋ฉด ๋ ๋ฐฐ์ด๋ค์ ํฉ์น ๊ณต๊ฐ์ ๋ง๋ จํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ์ธก๋ฉด์์๋ ํจ์จ์ฑ์ด ๋จ์ด์ง ์ ์๋ค.
Top-down vs. Bottom-up Mergesort
ํ์ ์์๋ ์๋์ง๋ง mergesort๋ฅผ ์ฌ๊ท ์๊ณ ๋ฆฌ์ฆ์ ํ์ฉํด ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ ์ ์๋ค.
ํ์ง๋ง CustomArray์ ๋ฉ์๋๋ก ์ถ๊ฐํ๋ ค๊ณ ํ๋ฉด ์ฌ๊ท ๊น์ด๊ฐ ๋๋ฌด ๊น์ด์ ธ์ ํ์ฉํ ์ ์๋ค.
// Function to merge two halves into a sorted array
function merge(left, right) {
let result = [];
let leftIndex = 0;
let rightIndex = 0;
// Concatenate values into the result array in sorted order
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
// Concatenate remaining elements of left and right arrays
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}
// Function to perform top-down merge sort
function mergeSort(array) {
// Base case: single element or empty array
if (array.length <= 1) {
return array;
}
// Find the middle index to split the array into two halves
const middleIndex = Math.floor(array.length / 2);
// Recursively sort the left and right halves
const left = mergeSort(array.slice(0, middleIndex));
const right = mergeSort(array.slice(middleIndex));
// Merge the sorted halves
return merge(left, right);
}
// Example usage
const array = [38, 27, 43, 3, 9, 82, 10];
console.log('Unsorted array:', array);
const sortedArray = mergeSort(array);
console.log('Sorted array:', sortedArray);
/**
Unsorted array: (7) [38, 27, 43, 3, 9, 82, 10]
Sorted array: (7) [3, 9, 10, 27, 38, 43, 82]
*/
ํ์ง๋ง ์๋ฐ์คํฌ๋ฆฝํธ๋ก๋ ์ฌ๊ท ๊น์ด๊ฐ ๋๋ฌด ๊น์ด์ ๋ถ๊ฐ๋ฅํ๋ค.
๋์ ๋น์ฌ๊ท์ ์ธ bottom-up Mergesort๋ฅผ ์ดํด๋ณด์.
๋จผ์ ์ ๋ ฌํ๊ณ ์ ํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ํ๋์ ๋ฐฐ์ด๋ก ์ชผ๊ฐ์ค๋ค.
๊ทธ ๋ค ๊ฐ ๋ฐฐ์ด ์์๋ค๋ณด๋ค ๋ฌด์กฐ๊ฑด ํฐ ๊ฐ์ธ infinity๋ฅผ ์ค๋ฅธ์ชฝ์ ๋ฐฐ์นํ์ฌ ์ง์ ์ง์ด์ฃผ๊ณ ๊ฐ ์ง์ ์ผ์ชฝ๊ณผ ์ค๋ฅธ์ชฝ ๋ถ๋ถ ๋ฐฐ์ด๋ก ์ง์ ํ๋ค. ์ด๋ infinity(๋ฌดํ)์ sentinel(๊ฐ์์) ๊ฐ์ผ๋ก ์ฐ์ธ๋ค๊ณ ํ๋๋ฐ, ์ผ์ชฝ์ด๋ ์ค๋ฅธ์ชฝ ๋ถ๋ถ ๋ฐฐ์ด์ ๋์ ๋ํ๋ด๊ธฐ ์ํด ์ฐ์ธ๋ค. ์ผ์ชฝ๊ณผ ์ค๋ฅธ์ชฝ ๋ถ๋ถ ๋ฐฐ์ด๋ค์ ๊ฐ์ ธ์ ์ ๋ ฌํด ์ค ์๋ก์ด ๋ฐฐ์ด๋ก ํฉ์ณ์ฃผ๊ณ , ๋ง์ง๋ง์ ๋ถ๋ถ ๋ฐฐ์ด๋ค์ด ๋ ์ด์ ์์ ๋๊น์ง ๋ฐ๋ณตํด ์ฃผ๋ฉด ์ ๋ ฌ์ด ์์ฑ๋๋ค.
๊ตฌํ
mergeSort(){
if(this.dataStore.length <2){
return;
}
let step = 1;
let left,right;
while(step < this.dataStore.length){
left = 0;
right = step;
while(right+step <= this.dataStore.length){
this.mergeArrays(this.dataStore, left, left+step, right, right+step);
left = right + step;
right = left + step;
}
if(right < this.dataStore.length){
this.mergeArrays(this.dataStore, left, left+step, right, this.dataStore.length);
}
step *= 2;
}
}
mergeArrays(arr,startLeft, stopLeft, startRight, stopRight){
let rightArr = new Array(stopRight - startRight + 1);
let leftArr = new Array(stopLeft - startLeft + 1);
let k = startRight;
for(let i = 0; i< (rightArr.length-1); ++i){
rightArr[i] = arr[k];
++k;
}
k = startLeft;
for(let i=0; i< (leftArr.length-1);++i){
leftArr[i] = arr[k];
++k;
}
rightArr[rightArr.length-1] = Infinity;
leftArr[leftArr.length-1] = Infinity;
let m = 0;
let n = 0;
for (let k = startLeft; k < stopRight; ++k) {
if (leftArr[m] <= rightArr[n]) {
arr[k] = leftArr[m];
m++;
} else {
arr[k] = rightArr[n]; n++;
}
}
this.print("left array - ", leftArr);
this.print("right array - ", rightArr);
}
๐ ์ ์ฒด ์ฝ๋
class CustomArray{
constructor(numElements){
this.dataStore = [];
this.pos = 0;
this.numElements = numElements;
for (let i = 0; i < numElements; ++i) {
this.dataStore[i] = i;
}
this.gaps = [5,3,1];
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
// ์ถ๋ ฅ ํฌํผ
print(label,arr,...others){
console.log(`${label} [${arr}] ${others}`);
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
// ์ฝ์
insert(element){
this.dataStore[this.pos++] = element;
}
// ์ถ๋ ฅ ํฌ๋ฉงํด์ฃผ๊ธฐ ์ํ ํฌํผํจ์
toString(){
let retstr = "";
for (let i = 0; i < this.dataStore.length; ++i) {
retstr += this.dataStore[i] + " ";
if (i > 0 && i % 10 == 0) {
retstr += "\n";
}
}
return retstr;
}
// ์ ๊ฑฐ
clear(){
for (let i = 0; i < this.dataStore.length; ++i) {
this.dataStore[i] = 0;
}
}
// ๋๋ค ๋ฐ์ดํฐ ์์ฑ
setData(){
for (let i = 0; i < this.numElements; ++i) {
this.dataStore[i] = Math.floor(Math.random() * (this.numElements+1));
}
}
// index1 ๊ณผ index2์ ์๋ฆฌ ๋ณ๊ฒฝ
swap(arr, index1, index2){
let temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
bubbleSort(){
let numElements = this.dataStore.length;
let temp;
for(let outer = numElements; outer >=2; --outer){
for(let inner = 0; inner <= outer-1; ++inner){
if(this.dataStore[inner] > this.dataStore[inner+1]){
this.swap(this.dataStore, inner, inner+1);
}
}
}
}
selectionSort(){
let min,temp;
for(let outer = 0; outer <= this.dataStore.length-2; ++outer){
min = outer;
for(let inner = outer+1; inner <= this.dataStore.length-1; ++inner){
if(this.dataStore[inner] < this.dataStore[min]){
min = inner;
}
this.swap(this.dataStore, outer, min);
}
}
}
insertionSort(){
let temp, inner;
for(let outer = 1; outer <= this.dataStore.length-1; ++outer){
temp = this.dataStore[outer];
inner = outer;
while(inner > 0 && (this.dataStore[inner-1] >= temp)){
this.dataStore[inner] = this.dataStore[inner-1];
--inner;
}
this.dataStore[inner] = temp;
}
}
setGaps(arr){
this.gaps = arr;
}
shellSort() {
for (let g = 0; g < this.gaps.length; ++g) {
for (let i = this.gaps[g]; i < this.dataStore.length; ++i) {
let temp = this.dataStore[i];
let j;
for (j = i; j >= this.gaps[g] && this.dataStore[j - this.gaps[g]] > temp; j -= this.gaps[g]) {
this.dataStore[j] = this.dataStore[j - this.gaps[g]];
}
this.dataStore[j] = temp;
}
}
}
dynamicGapShellSort(){
let N = this.dataStore.length;
let h = 1;
while (h < N/3) {
h = 3 * h + 1;
}
while(h >= 1){
for(let i = h; i < N; i++){
for(let j =i; j>=h && this.dataStore[j] < this.dataStore[j-h]; j -= h){
this.swap(this.dataStore,j,j-h);
}
}
h = (h-1)/3;
}
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
mergeSort(){
if(this.dataStore.length <2){
return;
}
let step = 1;
let left,right;
while(step < this.dataStore.length){
left = 0;
right = step;
while(right+step <= this.dataStore.length){
this.mergeArrays(this.dataStore, left, left+step, right, right+step);
left = right + step;
right = left + step;
}
if(right < this.dataStore.length){
this.mergeArrays(this.dataStore, left, left+step, right, this.dataStore.length);
}
step *= 2;
}
}
mergeArrays(arr,startLeft, stopLeft, startRight, stopRight){
let rightArr = new Array(stopRight - startRight + 1);
let leftArr = new Array(stopLeft - startLeft + 1);
let k = startRight;
for(let i = 0; i< (rightArr.length-1); ++i){
rightArr[i] = arr[k];
++k;
}
k = startLeft;
for(let i=0; i< (leftArr.length-1);++i){
leftArr[i] = arr[k];
++k;
}
rightArr[rightArr.length-1] = Infinity;
leftArr[leftArr.length-1] = Infinity;
let m = 0;
let n = 0;
for (let k = startLeft; k < stopRight; ++k) {
if (leftArr[m] <= rightArr[n]) {
arr[k] = leftArr[m];
m++;
} else {
arr[k] = rightArr[n]; n++;
}
}
this.print("left array - ", leftArr);
this.print("right array - ", rightArr);
}
/////////////////////////// ๐ ์ถ๊ฐ ///////////////////////////
}
const print = item => console.log(item);
let numElements = 10;
let myNums = new CustomArray(numElements);
myNums.setData();
print(myNums.toString());
myNums.mergeSort();
print('์ ๋ ฌ ํ:');
print(myNums.toString());
/**
2 8 9 1 3 7 3 9 9 0
left array - [2,Infinity]
right array - [8,Infinity]
left array - [9,Infinity]
right array - [1,Infinity]
left array - [3,Infinity]
right array - [7,Infinity]
left array - [3,Infinity]
right array - [9,Infinity]
left array - [9,Infinity]
right array - [0,Infinity]
left array - [2,8,Infinity]
right array - [1,9,Infinity]
left array - [3,7,Infinity]
right array - [3,9,Infinity]
left array - [1,2,8,9,Infinity]
right array - [3,3,7,9,Infinity]
left array - [1,2,3,3,7,8,9,9,Infinity]
right array - [0,9,Infinity]
์ ๋ ฌ ํ:
0 1 2 3 3 7 8 9 9 9
*/
The Quicksort Algorithm
Quicksort์ ๋ง์ ๋ฐ์ดํฐ์์ ์ ๋ ฌํ๊ธฐ ์ํ ์๊ณ ๋ฆฌ์ฆ ์ค ๊ฐ์ฅ ๋น ๋ฅธ ์ถ์ ์ํ๋ค.
๋ถํ ์ ๋ณต(divide and conquer)์ ์ํด ์ฌ๊ท์ ์ผ๋ก ๋ฆฌ์คํธ๋ฅผ ๋ ์์ ๋ถ๋ถ ๋ฆฌ์คํธ๋ก ์ชผ๊ฐ์ค๋ค.
๋ฆฌ์คํธ๋ฅผ pivot์ ๊ธฐ์ค์ผ๋ก ๋ถ๋ถ ๋ฆฌ์คํธ๋ก ์ชผ๊ฐ์ฃผ๋๋ฐ, pivot๋ณด๋ค ์์ ๊ฐ๋ค์ ๋ฆฌ์คํธ์ ์ผ์ชฝ(์๋)์, ํฐ ๊ฐ๋ค์ ์ค๋ฅธ์ชฝ(์)์ ๋ฐฐ์นํ๋ค.
๋ค์ ์์๋ฅผ ์ดํด๋ณด์. pivot์ ๊ฐ ๋ฆฌ์คํธ์ ๋ง์ง๋ง ์์๋ก ์ง์ ํ์.
์ ๋ ฌ ์ : [10, 7, 8, 9, 1, 5]
Partitioning: pivot=5, array= [1, 5, 8, 9, 10, 7]
Partitioning: pivot=7, array= [1, 5, 7, 9, 10, 8]
Partitioning: pivot=8, array= [1, 5, 7, 8, 10, 9]
Partitioning: pivot=9, array= [1, 5, 7, 8, 9, 10]
์ ๋ ฌ ํ: [1, 5, 7, 8, 9, 10]
์๊ณ ๋ฆฌ์ฆ ํ๋ฆ์ ์ดํด๋ณด๋ฉด,
- ๋ฐฐ์ด์ ๋ ๋ถ๋ถ์ผ๋ก ๋๋ pivot ์์๋ฅผ ๊ณ ๋ฅธ๋ค.
- pivot๋ณด๋ค ์์ ๊ฐ๋ค์ ์ ์, ํฐ ๊ฐ๋ค์ ๋ค์ ์ค๋๋ก ์ ๋ ฌํ๋ค.
- ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌ๋ ๋๊น์ง 1๊ณผ 2๋ฅผ ๋ฐ๋ณตํ๋ค.
๊ตฌํ
์ฌ๊ท์ ์ผ๋ก quickSort๋ฅผ ํธ์ถํ๊ธฐ ๋๋ฌธ์ ์ด์ ํด๋์ค๊ฐ ์๋ ์ง์ ๋๋ค ์ซ์๋ก ๋ฐฐ์ด์ ๋ง๋ค์ด ์ฐ์.
function quickSort(arr){
if(arr.length===0){
return [];
}
let left = [];
let right = [];
let pivot = arr[0]; // ๊ตฌํ์ ๋ฐฐ์ด์ ์ฒซ ์์๋ฅผ pivot์ผ๋ก ์ง์
for(let i = 1; i< arr.length; i++){
if(arr[i] < pivot){
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort(left).concat(pivot, quickSort(right));
}
const print = item => console.log(item);
let arr = Array.from({length:10},()=>Math.floor((Math.random()*100)+1));
print(arr); // [72, 50, 36, 55, 25, 75, 90, 45, 39, 46]
print();
print(quickSort(arr)); // [25, 36, 39, 45, 46, 50, 55, 72, 75, 90]
quickSort๋ ๋ฐ์ดํฐ ์๊ฐ ๋ง์ ๋ ์ฐ๋ฉด ์ข๋ค. ๋ฐ์ดํฐ ์๊ฐ ์ ์์๋ก ์ฑ๋ฅ์ด ๋จ์ด์ง๋ค.
์ด๋ฒ์๋ pivot ์ ํ์ ๋ฐ๋ผ ์ด๋ป๊ฒ ๋ฐ์ดํฐ๊ฐ pivot ์ค์ฌ์ผ๋ก ์ ๋ ฌ๋๋์ง ์ดํด๋ณด์.
const print = item => console.log(item);
function quickSort(arr){
if(arr.length===0){
return [];
}
let left = [];
let right = [];
let pivot = arr[0];
for(let i = 1; i< arr.length; i++){
print(`pivot: ${pivot}, current element: ${arr[i]}`); // ๐ ๋ก๊ทธ ์ถ๊ฐ
if(arr[i] < pivot){
print(`moving ${arr[i]} to the left`); // ๐ ๋ก๊ทธ ์ถ๊ฐ
left.push(arr[i]);
} else {
print(`moving ${arr[i]} to the right`); // ๐ ๋ก๊ทธ ์ถ๊ฐ
right.push(arr[i]);
}
}
return quickSort(left).concat(pivot, quickSort(right));
}
let arr = Array.from({length:10},()=>Math.floor((Math.random()*100)+1));
print(arr);
print();
print(quickSort(arr));
/**
[65, 70, 12, 6, 35, 40, 15, 21, 83, 44]
pivot: 65, current element: 70
moving 70 to the right
pivot: 65, current element: 12
moving 12 to the left
pivot: 65, current element: 6
moving 6 to the left
pivot: 65, current element: 35
moving 35 to the left
pivot: 65, current element: 40
moving 40 to the left
pivot: 65, current element: 15
moving 15 to the left
pivot: 65, current element: 21
moving 21 to the left
pivot: 65, current element: 83
moving 83 to the right
pivot: 65, current element: 44
moving 44 to the left
pivot: 12, current element: 6
moving 6 to the left
pivot: 12, current element: 35
moving 35 to the right
pivot: 12, current element: 40
moving 40 to the right
pivot: 12, current element: 15
moving 15 to the right
pivot: 12, current element: 21
moving 21 to the right
pivot: 12, current element: 44
moving 44 to the right
pivot: 35, current element: 40
moving 40 to the right
pivot: 35, current element: 15
moving 15 to the left
pivot: 35, current element: 21
moving 21 to the left
pivot: 35, current element: 44
moving 44 to the right
pivot: 15, current element: 21
moving 21 to the right
pivot: 40, current element: 44
moving 44 to the right
pivot: 70, current element: 83
moving 83 to the right
[6, 12, 15, 21, 35, 40, 44, 65, 70, 83]
*/
๐ ๋ง์น๋ฉด์
?? 170์ชฝ์์ Heapsort์ ๋ํด์๋ ์์๋ณธ๋ค๊ณ ํ๋๋ฐ ํด๋น ๋ด์ฉ์ด ๋๋ฝ๋์ด ์์ด์ ๋นํฉ..
๐ค ๊ฐ์ธ์ ์ผ๋ก heapsort ๊ณต๋ถ ํ ๋ด์ฉ ์ ๋ฆฌํ์ฌ ์ถ๊ฐํด ๋ด์ผ๊ฒ ๋ค.
๐ Reference
- Data Structures and Algorithms Using Javaโ Script by Michael McMillian (O’Reilly). Copyright 2014 Michael McMillan, 978-1-449-36493-9