<h1>Quick Sort</h1>

<div id='buttonContainer'>
  <button id="randomize">Randomize</button>
  <button id="sort">Sort</button>
</div>

<div>
  <label for="slider">Delay in seconds</label>
  <input type="range" id="slider" value="1" min="0" max="3" step="0.5">
  <span id="seconds">1</span>
</div>

<div id="spanContainer">
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>

<code>Best -- Time: O(n log(n)) Space: O(log (n))</code>
<code>Ave -- Time: O(n log(n)) Space: O(log (n))</code>
<code>Worst -- Time: O(n<sup>2</sup>) Space: O(log (n))</code>
* {
  font-family: Arial;
  font-size: 3.5vw;
  outline: none;
}

body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin: 0;
  height: 100vh;
}

h1 {
  margin: 0 0 12.5vh;
  font-size: 6vw;
  font-weight: 400;
}

#buttonContainer {
  display: flex;
  justify-content: center;
}

button {
  width: 25vw;
  padding: 1vw;
  margin: 0.5vw 0.5vw 1.5vw;
  border: 1px solid black;
  border-radius: 25vw;
  background-color: white;
  cursor: pointer;
  transition: all 0.2s ease;
}

button:hover {
  background-color: black;
  color: white;
  box-shadow: 0 0 3.5vw gray;
}

#slider {
  margin-right: 10px;
}

#seconds {
  position: absolute;
}

#spanContainer {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 12.5vh 0 3vh;
}

#spanContainer span {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 3.5vw;
  height: 3.5vw;
  margin: 0 0.5vw;
  padding: 1.5vw;
  border: 1px solid black;
  border-radius: 3.5vw;
}

/* ----------------------------------------------
 * Generated by Animista on 2020-5-30 8:25:12
 * Licensed under FreeBSD License.
 * Edited by Kent Warren
 * See http://animista.net/license for more info. 
 * w: http://animista.net, t: @cssanimista
 * ---------------------------------------------- */

/**
 * ----------------------------------------
 * animation pulsate-fwd
 * ----------------------------------------
 */

.pulsate-fwd {
	-webkit-animation: pulsate-fwd 0.75s ease-in-out 3 both;
	        animation: pulsate-fwd 0.75s ease-in-out 3 both;
}

@-webkit-keyframes pulsate-fwd {
  0% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
  50% {
    -webkit-transform: scale(1.1);
            transform: scale(1.1);
           box-shadow: 0 0 1vw gray;
  }
  100% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
}

@keyframes pulsate-fwd {
  0% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
  50% {
    -webkit-transform: scale(1.1);
            transform: scale(1.1);
           box-shadow: 0 0 1vw gray;
  }
  100% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
}

code {
  font-family: monospace;
  margin: 3vh 0 0;
}

code:first-of-type {
  margin: 12.5vh 0 0;
}

sup {
  font-family: monospace;
}
console.clear()

// randomize button
const randomize = document.getElementById('randomize');
// sort button
const sort = document.getElementById('sort');
// delay input
const delay = document.getElementById('slider');
// delay value
let delayValue = delay.value * 1000;
// delay span
const delaySpan = document.getElementById('seconds');
// for when sort is in process
let sortInProcess = false;
// spanContainer
const spanContainer = document.getElementById('spanContainer');
// div of spans with random numbers
const randomSpans = [...spanContainer.children];



// randomize
randomize.addEventListener('click', () => {
  // if in progress, return
  if (sortInProcess) return;
  
  randomSpans.forEach(span => {
    span.style.cssText = 'color: black; box-shadow: initial;';
    span.className = '';
    span.innerText = Math.floor( Math.random() * 100 );
  });
});



// sort
sort.addEventListener('click', async () => {
  // if in progress or no random numbers yet or all green, return
  if (sortInProcess || randomSpans[0].innerText === '' || randomSpans[0].style.color === 'green') return;
  sortInProcess = true;
  
  // start quick sort
  await quickSort(randomSpans);

  randomSpans.forEach(span => {
    span.style.cssText = 'color: green; box-shadow: 0 0 1vw gray;';
    span.className = 'pulsate-fwd';
  });
  
  // revert state
  sortInProcess = false;
});



// delay
delay.addEventListener('input', (e) => {
  delaySpan.innerText = e.target.value;
  delayValue = e.target.value * 1000;
});



async function quickSort(arr, start = 0, end = arr.length) {
  if (start < end) {
    arr.forEach((span, i) => {
      if (i >= start && i < end) {
        span.style.cssText = 'background-color: pink';
      }
    });
    let newPivotIndex = await pivot(arr, start, end);
    arr.forEach((span, i) => {
      if (i >= start && i < end) {
        span.style.cssText = 'background-color: initial';
      }
    });
    await quickSort(arr, start, newPivotIndex);
    await quickSort(arr, newPivotIndex + 1, end);
  }
  
  return arr;
}



const swap = (arr, i, j) => {
  return new Promise(resolve => {
    setTimeout(() => {
      [arr[j], arr[i]] = [arr[i], arr[j]];
      updateDOM(arr);
      resolve();
    }, delayValue);
  });
};

const wait = () => {
  return new Promise(resolve => {
    setTimeout(() => resolve(), delayValue);
  });
};

const updateDOM = arr => {
  spanContainer.innerHTML = '';
  arr.forEach(span => spanContainer.append(span));
};



async function pivot(arr, start, end) {
  let lesser = start;
  
  for (let i = start; i < end; i++) {
    if (Number(arr[i].innerText) < Number(arr[start].innerText)) {
      lesser++;
      if (i !== lesser) {
        randomSpans[i].style.cssText = 'color: red; box-shadow: 0 0 1vw gray; background-color: pink';
        randomSpans[lesser].style.cssText = 'color: red; box-shadow: 0 0 1vw gray; background-color: pink';
        await swap(arr, i, lesser);
        randomSpans[i].style.cssText = 'color: green; box-shadow: 0 0 1vw gray; background-color: pink';
        randomSpans[lesser].style.cssText = 'color: green; box-shadow: 0 0 1vw gray; background-color: pink';
        await wait();
        randomSpans[i].style.cssText = 'background-color: pink';
        randomSpans[lesser].style.cssText = 'background-color: pink';
      }
    }
  }
  
  if (start !== lesser) {
    randomSpans[start].style.cssText = 'color: red; box-shadow: 0 0 1vw gray; background-color: pink';
    randomSpans[lesser].style.cssText = 'color: red; box-shadow: 0 0 1vw gray; background-color: pink';
    await swap(arr, start, lesser);
    randomSpans[start].style.cssText = 'color: green; box-shadow: 0 0 1vw gray; background-color: pink';
    randomSpans[lesser].style.cssText = 'color: green; box-shadow: 0 0 1vw gray; background-color: pink';
    await wait();
    randomSpans[start].style.cssText = 'background-color: pink';
    randomSpans[lesser].style.cssText = 'background-color: pink';
  }
  
  return lesser;
}





/*

Unadulterated quick sort


function quickSort(arr, start = 0, end = arr.length) {
  if (start < end) {
    let newPivotIndex = pivot(arr, start, end);
    quickSort(arr, start, newPivotIndex);
    quickSort(arr, newPivotIndex + 1, end);
  }
  
  return arr;
}

const swap = (arr, i, j) => [arr[j], arr[i]] = [arr[i], arr[j]];

function pivot(arr, start, end) {
  let lesser = start;
  
  for (let i = start; i < end; i++) {
    if (arr[i] < arr[start]) {
      lesser++;
      if (i !== lesser) swap(arr, i, lesser);
    }
  }
  
  swap(arr, start, lesser);
  return lesser;
}

*/

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.