skip to Main Content

I’m trying to draw visual representation of sorting algorithms. Bubble Sort is working fine, but Selection Sort don’t care about how much time I put in the setInterval timer, he runs on the same speed no matter what (until I manually put sleep, but that’s not the solution)

Can you guys help me understand what’s wrong here? It’s strange, because bubble sort works very good.

Bubble Sort

function bubbleSort(X, Y, LastX, LastY, no_loops, no_steps, time) {
  var i, j;
  var len = LastY.length;
  var isSwapped = false;

  for (i = 0; i < len; i++) {
    var intervalId = setInterval(function() {
      ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
      isSwapped = false;
      for (j = 0; j < len; j++) {
        if (LastY[j] > LastY[j + 1]) {
          var temp = LastY[j]
          LastY[j] = LastY[j + 1];
          no_steps = no_steps + 1;
          LastY[j + 1] = temp;
          no_steps = no_steps + 1;
          isSwapped = true;
        }
      }

      drawArray(X, Y, LastX, LastY);
      no_loops = no_loops + 1;
      no_steps = no_steps + 1;
      document.getElementById("p1").innerHTML = no_loops;
      document.getElementById("p2").innerHTML = no_steps;
      if (isArraySorted(LastY) == true) {
        clearInterval(intervalId);
      }
    }, time);
    if (!isSwapped) {
      break;
    }
  }
}

Selection Sort

function selectionSort(X, Y, LastX, LastY, no_loops, no_steps, time) {
  let n = LastY.length;

  for (let i = 0; i < n; i++) {
    var intervalId = setInterval(function() {
          ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);

          let min = i;
          for (let j = i + 1; j < n; j++) {
            if (LastY[j] < LastY[min]) {
              min = j;
            }
            no_steps = no_steps + 1;
          }
          if (min != i)
            let tmp = LastY[i];
          LastY[i] = LastY[min];
          LastY[min] = tmp;
          no_steps = no_steps + 1;
        }
        drawArray(X, Y, LastX, LastY);
        //sleep(time);
        console.log(time) no_loops = no_loops + 1; no_steps = no_steps + 1;
        if (isArraySorted(LastY) == true) {
          return;
        }
        console.log(i); document.getElementById("p1").innerHTML = no_loops; document.getElementById("p2").innerHTML = no_steps;

        if (isArraySorted(LastY) == true) {
          clearInterval(intervalId);
        }
      },
      time);
}

}

I was trying parsing code block in interval to external function, changing placement of setInterval, but i can’t get it to draw properly.

2

Answers


  1. Chosen as BEST ANSWER

    Sorry guys, i did not gave you enough info. @RAllen, you are a genious, thank you. It's working like a charm now. I need just google what "*" means before function.

    @Mr. Polywhirl @Barmar

    Full code below

    <?php
    if (isset($_POST['time'])) {
        $time = $_POST['time'];
    } else {
        $time = 50;
    }
    if (isset($_POST['elements'])) {
        $elements = $_POST['elements'];
    } else {
        $elements = 1000;
    }
    if (isset($_POST['checkbox1'])) {
        $worstcase = 1;
        $checked = 'checked=""';
    } else {
        $worstcase = 0;
        $checked = '';
    }
    if (isset($_POST['SortButton'])) {
        $alg_type = $_POST['SortButton'];
    } else {
        $alg_type = 'bubble';
    }
    ?>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Sorting algorithms</title>
        <link rel="stylesheet" href="./css/canvas.css">
        <link rel="stylesheet" href="./css/slider.css">
        <link rel="stylesheet" href="./css/button.css">
        <link rel="stylesheet" href="./css/checkbox.css">
    </head>
    <body>
        <table style="width:100%">
            <th style="width:10%"></th>
            <th style="width:80%"><center><canvas id="canvasElement" class="inline-block-centered" width="1300" height="800"></canvas></center></th>
            <th style="width:10%" valign="top" align="left">Number of loops through array:<p id="p1">0</p>Number of all steps:<p id="p2">0</p></th>
        </table>
        <div class="slidecontainer"><br>
            <form action="index.php" method="post">
                <label for="elements">
                    <input type="range" id="elements" name="elements" value="<?php echo $elements;?>" min="5" max="10000" class="slider" oninput="elementsOutput.value = elements.value"><br>
                    Number of elements to sort (range: 5-10000):<output id="elementsOutput"><?php echo $elements;?></output><br><br>
                </label>
                <label for="time">
                    <input type="range" id="time" name="time" value="<?php echo $time;?>" min="1" max="1000" class="slider" oninput="timeOutput.value = time.value"><br>
                    Time in miliseconds between each sort (range: 1-1000):<output id="timeOutput"><?php echo $time;?></output><br>
                </label>
                <label for="checkbox1" class="checkbox">
                <br><br>
                    <span class="label">REVERSE ARRAY</span>
                    <input type="checkbox" id="checkbox1" name="checkbox1" value="checkbox1" <?php echo $checked;?>>
                    <span class="checkmark"></span>
                </label><br>
            <button type="submit" id="SortButton" name="SortButton" value="bubble" class="button-36">Bubble<br>SORT!</button>
            <button type="submit" id="SortButton" name="SortButton" value="selection" class="button-36">Selection<br>SORT!</button>
            </form>
        </div>
    
    <script>
    //Declare Variables
    var c = document.getElementById('canvasElement');
    const canvas = document.getElementById('canvasElement');
    canvas.width  = window.innerWidth * 0.8;
    canvas.height = window.innerHeight * 0.7;
    function windowResize() {
      canvas.width  = window.innerWidth * 0.8;
      canvas.height = window.innerHeight * 0.7;
    };
    
    window.addEventListener('resize', windowResize);
    
    var ctx = c.getContext('2d');
    var X = [];
    var LastX = [];
    var Y = [];
    var LastY = [];
    
    ctx.font = "15px Arial";
    ctx.textAlign = "start";
    ctx.fillText("textAlign=start", canvas.width, canvas.height);
    
    var number = <?php echo $elements;?>;
    var time = <?php echo $time;?>;
    var worstcase = <?php echo $worstcase;?>;
    console.log(number);
    var pos_x = canvas.width - (canvas.width/number/2);
    var pos_y = canvas.height;
    var delay = canvas.width/number;
    var delay_y = canvas.height/number
    </script>
    
    <script type="module">
    import { drawArray } from './js/drawArray.js';
    import { createArray } from './js/createArray.js';
    import { shuffle } from './js/shuffleArray.js';
    import * as sorting from './js/sortingAlgorithms.js';
    
    createArray(X, Y, LastX, LastY, number, window.innerHeight);
    if (worstcase == 0){
        LastY = shuffle(LastY);
    }
    drawArray(X, Y, LastX, LastY);
    
    var no_loops = 1;
    var no_steps = 1;
    
    const iterator = sorting.<?php echo $alg_type;?>Sort(X, Y, LastX, LastY, no_loops, no_steps, time);
    const timer = setInterval(() => {
      const state = iterator.next().value;
      if (!state) {
        clearInterval(timer);
        return;
      }
      ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
      drawArray(X, Y, LastX, LastY);
    }, time);
    </script>
    
    
    </body>
    </html>
    
            
    
    
        import { drawArray } from './drawArray.js';
    import { isArraySorted } from './isArraySorted.js';
    
    export function *bubbleSort(X, Y, LastX, LastY, no_loops, no_steps) {
      var i, j;
      var len = LastY.length;
      var isSwapped = false;
    
      for (i = 0; i < len; i++) {
        isSwapped = false;
        for (j = 0; j < len; j++) {
          if (LastY[j] > LastY[j + 1]) {
            var temp = LastY[j]
            LastY[j] = LastY[j + 1];
            no_steps = no_steps + 1;
            LastY[j + 1] = temp;
            no_steps = no_steps + 1;
            isSwapped = true;
          }
        }
        no_loops = no_loops + 1;
        no_steps = no_steps + 1;
    
        yield {
          X,
          Y,
          LastX,
          LastY,
          no_loops,
          no_steps
        };
    
        if (isArraySorted(LastY) == true) {
          return;
        }
    
        if (!isSwapped) {
          break;
        }
      }
    }
    
    export function *selectionSort(X, Y, LastX, LastY, no_loops, no_steps) {
      let n = LastY.length;
    
      for (let i = 0; i < n; i++) {
        let min = i;
        for (let j = i + 1; j < n; j++) {
          if (LastY[j] < LastY[min]) {
            min = j;
          }
          no_steps = no_steps + 1;
        }
        if (min != i) {
          let tmp = LastY[i];
          LastY[i] = LastY[min];
          LastY[min] = tmp;
        }
        no_steps = no_steps + 1;
        
        yield {
          X,
          Y,
          LastX,
          LastY,
          no_loops,
          no_steps
        };
    
        if (isArraySorted(LastY)) {
          return;
        }
      }  
    }
    
        
    export function createArray(X, Y, LastX, LastY, number, height) {
        for (var i = 0; i < number; i++) {
            X.push(pos_x);
            LastX.push(pos_x);
            Y.push(height);
            LastY.push(pos_y);
            pos_x = pos_x - delay;
            pos_y = pos_y - delay_y;
            
        }
    }
    
        export function shuffle(array) {
      let currentIndex = array.length,  randomIndex;
      while (currentIndex != 0) {
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;
        [array[currentIndex], array[randomIndex]] = [
          array[randomIndex], array[currentIndex]];
      }
      return array;
    }
    
        export function isArraySorted(arr) {
        for (let i=0;i<arr.length;i++) {
            if (arr[i+1] && (arr[i+1] > arr[i])) {
                continue;
            } else if(arr[i+1] && (arr[i+1] < arr[i])) {
                return false;
            }
        }
    
        return true;
    }
    
        export function drawArray(X, Y, LastX, LastY) {
        for (var i = 0; i < X.length; ++i) {
            ctx.beginPath();
            ctx.moveTo(LastX[i],LastY[i]);
            ctx.lineTo(X[i],Y[i]);
            ctx.stroke();
        }
    }
    

  2. With your approach, you will have an increasing number of issues with the more complex sorting algorithms.

    Why not just use yield to return control to your main function to draw the current state on every step of sorting?

    const isArraySorted = arr => arr.every((v,i,a) => !i || a[i-1] <= v);
    
    function *bubbleSort(X, Y, LastX, LastY, no_loops, no_steps) {
      var i, j;
      var len = LastY.length;
      var isSwapped = false;
    
      for (i = 0; i < len; i++) {
        isSwapped = false;
        for (j = 0; j < len; j++) {
          if (LastY[j] > LastY[j + 1]) {
            var temp = LastY[j]
            LastY[j] = LastY[j + 1];
            no_steps = no_steps + 1;
            LastY[j + 1] = temp;
            no_steps = no_steps + 1;
            isSwapped = true;
          }
        }
        no_loops = no_loops + 1;
        no_steps = no_steps + 1;
    
        yield {
          X,
          Y,
          LastX,
          LastY,
          no_loops,
          no_steps
        };
    
        if (isArraySorted(LastY) == true) {
          return;
        }
    
        if (!isSwapped) {
          break;
        }
      }
    }
    
    const LastX = [4, 3, 2, 1];
    const LastY = [4, 3, 2, 1];
    
    const iterator = bubbleSort(0, 0, LastX, LastY, 0, 0);
    const timer = setInterval(() => {
      const state = iterator.next().value;
      if (!state) {
        clearInterval(timer);
        return;
      }
      // draw the current state provided by yield
      console.log(state.LastY);
    }, 1000);

    And with the Selection sort

    const isArraySorted = arr => arr.every((v, i, a) => !i || a[i - 1] <= v);
    
    function *selectionSort(X, Y, LastX, LastY, no_loops, no_steps) {
      let n = LastY.length;
    
      for (let i = 0; i < n; i++) {
        let min = i;
        for (let j = i + 1; j < n; j++) {
          if (LastY[j] < LastY[min]) {
            min = j;
          }
          no_steps = no_steps + 1;
        }
        if (min != i) {
          let tmp = LastY[i];
          LastY[i] = LastY[min];
          LastY[min] = tmp;
        }
        no_steps = no_steps + 1;
        
        yield {
          X,
          Y,
          LastX,
          LastY,
          no_loops,
          no_steps
        };
    
        if (isArraySorted(LastY)) {
          return;
        }
      }  
    }
    
    const LastX = [4, 3, 2, 1];
    const LastY = [4, 3, 2, 1];
    
    const iterator = selectionSort(0, 0, LastX, LastY, 0, 0);
    const timer = setInterval(() => {
      const state = iterator.next().value;
      if (!state) {
        clearInterval(timer);
        return;
      }
      // draw the current state provided by yield
      console.log(state.LastY);
    }, 1000);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search