Siddhesh
Siddhesh

Reputation: 179

How to make Sorting Visualizer?

I am trying to make sorting visualizer using react, I also made algorithms ready for different sort mechanism like merge sort, bubble sort, insertion sort and Quick sort but not able to implement it visually.

I made visualizer for bubble sort but for that too I asked question in stack overflow and one of the guys gave the entire logic of it using react, now I am trying to make it possible for merge sort, spend 4 days to implement it but still I got stuck, it feels like I will not able survive without taking any help.

Can anyone please suggest me what to do?

my App.js file

import "./styles.css";
import { useState, useEffect } from "react";

export default function App() {
  const [arrayForSort, setArrayForSort] = useState([
    70,
    20,
    40,
    90,
    26,
    10,
    80,
    50
  ]);

  const [isSort, setIsSort] = useState(false);

  const fetchArray = arrayForSort.map((element) => {
    return (
      <span className="array-element" key={element}>
        {element}
      </span>
    );
  });

  const beginSort = () => {
    setIsSort(true);
  };

  const mergeSort = (myArray) => {
    let newArray = [...myArray];

    // if array contains nothing or only one element then return the array
    if (myArray.length <= 1) return myArray;

    // find the middle of the array
    const middle = Math.floor(myArray.length / 2);

    // Split the array into two
    const leftArray = myArray.slice(0, middle);
    const rightArray = myArray.slice(middle);

    // recursive function to combine left and right array
    return merge(mergeSort(leftArray), mergeSort(rightArray), newArray);
  };

  const merge = (leftArr, rightArr, originalArray) => {
    let resultArray = [],
      leftIndex = 0,
      rightIndex = 0;

    while (leftIndex < leftArr.length && rightIndex < rightArr.length) {
      if (leftArr[leftIndex] < rightArr[rightIndex]) {
        let newLeftIndex = originalArray.indexOf(leftArr[leftIndex]);
        let newRightIndex = originalArray.indexOf(rightArr[rightIndex]);
        [originalArray[newLeftIndex], originalArray[newRightIndex]] = [
          originalArray[newRightIndex],
          originalArray[newLeftIndex]
        ];
        resultArray.push(leftArr[leftIndex]);
        leftIndex++;
      } else {
        let newLeftIndex = originalArray.indexOf(leftArr[leftIndex]);
        let newRightIndex = originalArray.indexOf(rightArr[rightIndex]);
        [originalArray[newRightIndex], originalArray[newLeftIndex]] = [
          originalArray[newLeftIndex],
          originalArray[newRightIndex]
        ];
        resultArray.push(rightArr[rightIndex]);
        rightIndex++;
      }
    }

    setArrayForSort(originalArray);

    resultArray = resultArray
      .concat(leftArr.slice(leftIndex))
      .concat(rightArr.slice(rightIndex));

    return resultArray;
  };

  useEffect(() => {
    if (isSort) {
      const arr = [...arrayForSort];
      const sortedArray = mergeSort(arr);
      console.log(sortedArray);
      // setArrayForSort(sortedArray);
      setIsSort(false);
    }
  }, [arrayForSort, setArrayForSort, isSort, mergeSort]);

  return (
    <div className="App">
      <h1>Merge Sort</h1>
      <div className="array">{fetchArray}</div>
      <button onClick={beginSort}>SORT</button>
    </div>
  );
}

Upvotes: 1

Views: 302

Answers (1)

Michael Hoobler
Michael Hoobler

Reputation: 622

This is actually trickier than I originally thought it was going to be. I wanted each individual "swap" the merge sort detected to be displayed, but I'm having problems going "back up the splits" correctly with my original idea.

I'll probably revisit this, but in case I don't, here's a version that just slightly tweaks your original code. You'll notice the bigger splits just sort of "snap" into being in the correct order, which probably isn't what you want, but hopefully it helps with understanding Timeouts and Promises:

https://codesandbox.io/s/merge-sort-forked-coh7r?file=/src/App.js

Just to be clear, everything is still basically happening in "one shot", meaning the call stack is still pretty much identical, meaning all the functions are still being called right on top of each other. The difference is that the Promise/setTimeout is adding a "pause here then run this" and the async/await is adding a "wait for that before continuing". I think if you really wanted to show off "each swap" you would have to really break up the control flow and add in some conditional steps.

Upvotes: 1

Related Questions