From chaos to order: achieving understanding of algorithms through visualisation
Tags: flutter, algorithms, interview
Published: 2023-04-06 17:26:25

## TL;DR
As a developer preparing for interviews with FAANG companies, I found myself struggling with simple algorithms like string traversal and palindrome checks. However, I persevered and, after nine months of hard work, was able to master even more specific algorithms like KMP. During this time, I relied on a notebook and pen to visualise how sorting algorithms work and how numbers are compared.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yc6gir65dz5m4ld9som.png)

## Where it started from
When I began preparing for interviews with FAANG companies, I struggled with simple algorithms such as String traversal and palindrome checks. There were times when I almost gave up, but I have always been one to finish what I start. The same approach was applied here, and after nine months of hard work, I went from struggling with simple algorithms to understanding more specific ones like KMP (which I like a lot).

On my journey to master these algorithms, I used a notebook and pen to visualise how sorting works, how numbers are compared, and where it all goes. This helped me to better understand the algorithms and improved my ability to work with them.

## We are all developers
So why not create a project that visualises sorting algorithms in a more user-friendly way? Additionally, writing algorithmic solutions in a different language provides an extra opportunity to better understand and learn them.

I took advantage of this opportunity to improve my knowledge and develop a stronger understanding of the sorting pathway. By creating a mobile application using Flutter, I was able to utilise my experience with cross-platform development to build an effective tool for visualising complex algorithms, particularly sorting. This allowed me to further improve my knowledge and understanding of these algorithms while also creating a user-friendly platform for others to do the same.

## Flutter is a handy tool
With solid experience in developing cross-platform applications using the Flutter framework, I chose to utilise it to create a mobile application for both Android and iOS operating systems. Currently, the same code can run on web and desktop platforms if I add support.

During the process I achieved:
- I was able to write the same algorithms with Dart on top of Java implementations that I had done previously on Leetcode and AlgoExpert (both great resources for interview preparation).
- I learned about the Provider (recommended to use Riverpod) state management pattern, which was not previously in my development stack. Provider allows for a great separation of logic and UI and reactively updates UI with consumed data, making updates process very smooth.
- I also pushed my imagination beyond the norm and transformed a simple set of numbers into visually-pleasing widgets. To simplify the understanding of the algorithms, users can turn the numbers on and off.

## My implementation
Each sorting algorithm is a descendant of BaseSort, which, in turn, is a ChangeNotifier. The details of each algorithm’s implementation are covered under its specific implementation: BubbleSort, HeapSort, InsertionSort, MergeSort, and SelectionSort. BaseSort only covers the basic parts of each algorithm, such as the references of left and right pointers, as well as the index of the sorted part. This class is responsible for generating random data and notifying each subscriber of a new dataset.

```
class BaseSort with ChangeNotifier {
  BaseSort() {
    generateData();
  }

  List<int> array = List.empty(growable: true);

  int left = -1;
  int right = -1;
  int sorted = -1;

  bool isSorting = false;

  @mustCallSuper
  void generateData() {
    array.clear();
    isSorting = false;
    int counter = 0;
    final rand = Random();
    left = -1;
    right = -1;
    sorted = -1;

    while (counter < 50) {
      // to show anything in case of 0 -> shifting it to 1
      array.add(rand.nextInt(99) + 1);
      counter++;
      notifyListeners();
    }
  }

  Future startSorting() async {}

  Future sleep() async {
    await Future.delayed(const Duration(milliseconds: 150), () {});
  }
}
```
BaseSortWidget is an abstract class that represents a collection of common widget parts, with several abstract methods to be implemented in each specific algorithm widget.

```
abstract class BaseSortWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Card(
        margin: const EdgeInsets.all(8.0),
        elevation: 2.0,
        shape: const RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(12.0)),
        ),
        child: Padding(
          padding: const EdgeInsets.all(12.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                algorithmName(),
                style: const TextStyle(fontWeight: FontWeight.bold),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 10),
              consumerWidget(),
              const SizedBox(height: 10),
              Text(
                algorithmComplexity(),
                style: const TextStyle(fontWeight: FontWeight.bold),
                textAlign: TextAlign.center,
              ),
            ],
          ),
        ),
      );
}
```
Each algorithm widget implementation, with the exception of SelectionSort, is simplified to a state of:

```
class HeapSortWidget extends BaseSortWidget {
  @override
  String algorithmName() => HEAP_SORT;

  @override
  String algorithmComplexity() => 'Time: O(n*log(n))  Space: O(1)';

  @override
  Widget consumerWidget() => Consumer<HeapSort>(
        builder: (context, state, _) => Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: buildItemsArray(
            state.array,
            state.left,
            state.right,
            state.sorted,
            Colors.cyan,
          ),
        ),
      );
}
```
All the other parts are merely for aesthetic purposes, to create a cleaner and more elegant code. The main screen is a list of sorting widgets.

```
Consumer<SortHolder>(
  builder: (context, types, _) {
    final List<Widget> widgets = types.generateWidgets(context);
    return widgets.isEmpty
        ? Center(
            child: Text(
              '$DRAWER_TITLE\n\n$EMPTY_MESSAGE',
              textAlign: TextAlign.center,
              style: Theme.of(context)
                  .textTheme
                  .bodyLarge
                  .copyWith(fontSize: 18.0),
            ),
          )
        : ListView(
            padding: const EdgeInsets.all(8),
            children: widgets,
          );
  },
)
```
Whenever we add or remove widgets, the screen updates with more or fewer items. To hold data about widgets and to shuffle data/start sorting, we used SortHolder.

## The view
The resulting view of my work looks very neat and is easily understandable.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w500i1eboioge3xkqck2.png)

## Sorting process
Observing the sorting process is a true pleasure. Additionally, it is an easier way to understand the sorting algorithm by seeing which data is being compared. The left pointer is represented by yellow, while the right pointer is represented by red. Enjoy!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c2rdxbsai0dfvylkfr0i.gif)

## Summary
While preparing to algorithmic and data-structure interviews it might be tricky to master these complex topics. People are using different approaches to make is simpler, and easier to understand. Having no whiteboard, which could help me to visualise data, I have found simple notebook and pen quite useful, but for automatisation of the process and to repeat algorithms again, I have used coding, one instrument I am good at. Now we can observe how these algorithms are working. But I would love to extend this knowledge base with other more complex algorithms, which might be even harder to visualise. But still possible.

I am calling everyone, who want to participate in this project, to contribute to my gitHub via pull requests. I am happy to dedicate time for short catch-ups and collaboration.

{% embed https://github.com/VadymPinchuk/visualizer %}