From 6a03f7b7825c46a442c08303891639c9e0d52124 Mon Sep 17 00:00:00 2001 From: Liang Wang Date: Wed, 22 Nov 2023 23:56:46 +0200 Subject: [PATCH] coding ... --- docs/blog/404.html | 20 + docs/blog/CNAME | 1 + docs/blog/about/index.html | 104 +++ .../algorithm/2021/01/01/red-black-tree.html | 139 ++++ .../algorithm/2023/11/10/bubble-sort.html | 129 +++ .../algorithm/2023/11/10/bucket-sort.html | 154 ++++ .../algorithm/2023/11/10/counting-sort.html | 140 ++++ .../algorithm/2023/11/10/selection-sort.html | 140 ++++ .../blog/algorithm/2023/11/10/shell-sort.html | 148 ++++ docs/blog/algorithm/2023/11/20/heapsort.html | 157 ++++ .../algorithm/2023/11/20/insertion-sort.html | 128 +++ docs/blog/algorithm/2023/11/20/mergesort.html | 152 ++++ docs/blog/algorithm/2023/11/20/quicksort.html | 175 ++++ .../blog/algorithm/2023/11/20/radix-sort.html | 149 ++++ docs/blog/assets/css/style.css | 747 ++++++++++++++++++ docs/blog/assets/css/style.css.map | 1 + docs/blog/assets/minima-social-icons.svg | 5 + docs/blog/feed.xml | 493 ++++++++++++ docs/blog/index.html | 156 ++++ 19 files changed, 3138 insertions(+) create mode 100644 docs/blog/404.html create mode 100644 docs/blog/CNAME create mode 100644 docs/blog/about/index.html create mode 100644 docs/blog/algorithm/2021/01/01/red-black-tree.html create mode 100644 docs/blog/algorithm/2023/11/10/bubble-sort.html create mode 100644 docs/blog/algorithm/2023/11/10/bucket-sort.html create mode 100644 docs/blog/algorithm/2023/11/10/counting-sort.html create mode 100644 docs/blog/algorithm/2023/11/10/selection-sort.html create mode 100644 docs/blog/algorithm/2023/11/10/shell-sort.html create mode 100644 docs/blog/algorithm/2023/11/20/heapsort.html create mode 100644 docs/blog/algorithm/2023/11/20/insertion-sort.html create mode 100644 docs/blog/algorithm/2023/11/20/mergesort.html create mode 100644 docs/blog/algorithm/2023/11/20/quicksort.html create mode 100644 docs/blog/algorithm/2023/11/20/radix-sort.html create mode 100644 docs/blog/assets/css/style.css create mode 100644 docs/blog/assets/css/style.css.map create mode 100644 docs/blog/assets/minima-social-icons.svg create mode 100644 docs/blog/feed.xml create mode 100644 docs/blog/index.html diff --git a/docs/blog/404.html b/docs/blog/404.html new file mode 100644 index 0000000..d98598d --- /dev/null +++ b/docs/blog/404.html @@ -0,0 +1,20 @@ + + +
+

404

+ +

Page not found :(

+

The requested page could not be found.

+
diff --git a/docs/blog/CNAME b/docs/blog/CNAME new file mode 100644 index 0000000..43a97ff --- /dev/null +++ b/docs/blog/CNAME @@ -0,0 +1 @@ +blog.ocaml.xyz \ No newline at end of file diff --git a/docs/blog/about/index.html b/docs/blog/about/index.html new file mode 100644 index 0000000..4a72748 --- /dev/null +++ b/docs/blog/about/index.html @@ -0,0 +1,104 @@ + + + + + +About | Algorithm Blog + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

About

+
+ +
+

This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at jekyllrb.com

+ +

You can find the source code for Minima at GitHub: +jekyll / +minima

+ +

You can find the source code for Jekyll at GitHub: +jekyll / +jekyll

+ + +
+ +
+ +
+
+ + + diff --git a/docs/blog/algorithm/2021/01/01/red-black-tree.html b/docs/blog/algorithm/2021/01/01/red-black-tree.html new file mode 100644 index 0000000..9bf134f --- /dev/null +++ b/docs/blog/algorithm/2021/01/01/red-black-tree.html @@ -0,0 +1,139 @@ + + + + + +Red Black Tree | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Red Black Tree

+ +
+ +
+

Introduction

+

Red-black tree is a self-balancing binary search tree. It was invented in 1972 by Rudolf Bayer who called them “symmetric binary B-trees,” but acquired its modern name in a paper in 1978 by Leo J. Guibas and Robert Sedgewick. Red-black trees are often used in C++ STL (Standard Template Library) implementation of map and set.

+ +

Implementation

+

Here is an implementation of the red-black tree in OCaml:

+ +
type color = Red | Black  
+   
+type 'a tree =  
+  | Leaf  
+  | Node of color * 'a tree * 'a * 'a tree  
+   
+let balance = function  
+  | Black, Node (Red, Node (Red, a, x, b), y, c), z, d  
+  | Black, Node (Red, a, x, Node (Red, b, y, c)), z, d  
+  | Black, a, x, Node (Red, Node (Red, b, y, c), z, d)  
+  | Black, a, x, Node (Red, b, y, Node (Red, c, z, d)) ->  
+      Node (Red, Node (Black, a, x, b), y, Node (Black, c, z, d))  
+  | color, left, value, right -> Node (color, left, value, right)  
+   
+let rec insert x = function  
+  | Leaf -> Node (Red, Leaf, x, Leaf)  
+  | Node (color, left, value, right) as node ->  
+      if x < value then balance (color, insert x left, value, right)  
+      else if x > value then balance (color, left, value, insert x right)  
+      else node  
+
+ +

Here, we define the type of color as either Red or Black. We also define the type of a tree as either a Leaf or a Node with a color, left subtree, value, and right subtree. The balance function takes a tuple and returns a balanced node. The insert function takes a value and a tree and returns a new tree with the value inserted in the correct position.

+ +

Step-by-step Explanation

+
    +
  1. A new node is always inserted as a red node.
  2. +
  3. If the node is the root node, it is colored black.
  4. +
  5. If the parent of a red node is also red, the tree is rebalanced.
  6. +
  7. If a node is red, its children must be black.
  8. +
  9. The black height of a subtree must be equal on both sides.
  10. +
  11. When rebalancing, the red node is rotated and recolored to maintain the above properties.
  12. +
+ +

Complexity Analysis

+

The worst-case time complexity for insertion, deletion, and search operations in a red-black tree is O(log n), where n is the number of nodes in the tree. This is because the height of a red-black tree is always log n. The space complexity is also O(n), where n is the number of nodes in the tree, as each node requires a constant amount of memory.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/10/bubble-sort.html b/docs/blog/algorithm/2023/11/10/bubble-sort.html new file mode 100644 index 0000000..f5cd6ef --- /dev/null +++ b/docs/blog/algorithm/2023/11/10/bubble-sort.html @@ -0,0 +1,129 @@ + + + + + +Bubble Sort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Bubble Sort

+ +
+ +
+

Introduction

+

Bubble Sort is a simple sorting algorithm that repeatedly swaps adjacent elements if they are in the wrong order. It is named as bubble sort because the smaller elements bubble up to the top of the list as the algorithm iterates through the list. Bubble Sort is not an efficient algorithm for large lists and is generally used for educational purposes.

+ +

Implementation

+

Here is an implementation of Bubble Sort in OCaml:

+ +
let bubble_sort arr =  
+  let n = Array.length arr in  
+  for i = 0 to n - 2 do  
+    for j = 0 to n - i - 2 do  
+      if arr.(j) > arr.(j+1) then  
+        let temp = arr.(j) in  
+        arr.(j) <- arr.(j+1);  
+        arr.(j+1) <- temp  
+    done  
+  done;;  
+
+ +

Here, arr is the array to be sorted. The function bubble_sort uses two nested loops to iterate through the array and compare adjacent elements. If the elements are in the wrong order, they are swapped. The outer loop iterates from 0 to n-2, while the inner loop iterates from 0 to n-i-2. This is because the largest element in the list will already be in its correct position after each iteration of the outer loop.

+ +

Step-by-step Explanation

+
    +
  1. Start with an unsorted array of n elements.
  2. +
  3. Compare the first two elements. If the first element is greater than the second element, swap them.
  4. +
  5. Move to the next pair of adjacent elements and repeat step 2 until the end of the array is reached.
  6. +
  7. Repeat steps 2 and 3 for each pair of adjacent elements until the end of the array is reached.
  8. +
  9. After each iteration, the largest element will be in its correct position at the end of the array.
  10. +
  11. Repeat steps 2-5 n-1 times to sort the entire array.
  12. +
+ +

Complexity Analysis

+

The time complexity of Bubble Sort is O(n^2), where n is the number of elements in the array. This is because the algorithm uses two nested loops to iterate through the array and compare adjacent elements. In the worst case scenario, where the array is in reverse order, the algorithm will need to make n*(n-1)/2 comparisons and swaps. The space complexity of Bubble Sort is O(1), as the algorithm only requires a constant amount of additional memory to store temporary variables for swapping elements.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/10/bucket-sort.html b/docs/blog/algorithm/2023/11/10/bucket-sort.html new file mode 100644 index 0000000..e9dfe77 --- /dev/null +++ b/docs/blog/algorithm/2023/11/10/bucket-sort.html @@ -0,0 +1,154 @@ + + + + + +Bucket Sort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Bucket Sort

+ +
+ +
+

Introduction

+

Bucket sort is a sorting algorithm that works by distributing the elements of an array into a number of buckets. Each bucket is then sorted individually, either using a different sorting algorithm or by recursively applying the bucket sorting algorithm. Bucket sort is useful when the input is uniformly distributed over a range. It is commonly used in computer graphics, computational biology, and data mining.

+ +

Implementation

+

Here is an implementation of bucket sort in OCaml:

+ +
let bucket_sort arr =  
+  let n = Array.length arr in  
+  let buckets = Array.make n [] in  
+  for i = 0 to n - 1 do  
+    let bucket_index = int_of_float (arr.(i) *. (float_of_int n)) in  
+    buckets.(bucket_index) <- arr.(i) :: buckets.(bucket_index)  
+  done;  
+  let sorted = ref [] in  
+  for i = 0 to n - 1 do  
+    buckets.(i) <- List.sort compare buckets.(i);  
+    sorted := !sorted @ buckets.(i)  
+  done;  
+  Array.of_list !sorted  
+
+ +

This implementation takes an array of floating-point numbers as input and returns a sorted array.

+ +

Step-by-step Explanation

+
    +
  1. The input array is first traversed to determine the number of buckets required. This is done by taking the length of the array and creating an empty bucket for each index. +
    let n = Array.length arr in  
    +let buckets = Array.make n [] in  
    +
    +
  2. +
  3. The elements of the array are then distributed into the buckets. This is done by iterating over the array and calculating the index of the bucket for each element. The index is calculated by multiplying the element by the number of buckets and taking the integer part of the result. +
    for i = 0 to n - 1 do  
    +  let bucket_index = int_of_float (arr.(i) *. (float_of_int n)) in  
    +  buckets.(bucket_index) <- arr.(i) :: buckets.(bucket_index)  
    +done;  
    +
    +
  4. +
  5. Each bucket is then sorted individually. This is done using the OCaml List.sort function, which sorts a list in ascending order using the compare function. +
    for i = 0 to n - 1 do  
    +  buckets.(i) <- List.sort compare buckets.(i);  
    +done;  
    +
    +
  6. +
  7. Finally, the sorted elements are concatenated to form the final sorted array. +
    let sorted = ref [] in  
    +for i = 0 to n - 1 do  
    +  sorted := !sorted @ buckets.(i)  
    +done;  
    +Array.of_list !sorted  
    +
    +
  8. +
+ +

Complexity Analysis

+

The time complexity of bucket sort depends on the sorting algorithm used to sort the individual buckets. In the worst case, if each bucket contains all the elements of the input array, the time complexity of bucket sort is O(n^2), where n is the number of elements in the input array. However, if the input is uniformly distributed over a range, the time complexity can be improved to O(n) by using a linear-time sorting algorithm like counting sort or radix sort to sort the individual buckets.

+ +

The space complexity of bucket sort is O(n), where n is the number of elements in the input array. This is because we need to create a bucket for each element in the input array. However, if the input is uniformly distributed over a range, the space complexity can be improved to O(k), where k is the number of buckets required, which is much smaller than n.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/10/counting-sort.html b/docs/blog/algorithm/2023/11/10/counting-sort.html new file mode 100644 index 0000000..ce30db0 --- /dev/null +++ b/docs/blog/algorithm/2023/11/10/counting-sort.html @@ -0,0 +1,140 @@ + + + + + +Counting Sort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Counting Sort

+ +
+ +
+

Introduction

+

Counting sort is an efficient sorting algorithm that can be used to sort elements in a range of integers. It is a non-comparison based sorting algorithm that works by counting the number of occurrences of each element in the array and then using this information to determine the position of each element in the sorted output array.

+ +

Implementation

+

Here is an implementation of counting sort in OCaml:

+ +
let counting_sort arr =  
+  let max_val = Array.fold_left max arr 0 in  
+  let count_arr = Array.make (max_val + 1) 0 in  
+  Array.iter (fun x -> count_arr.(x) <- count_arr.(x) + 1) arr;  
+  let index_arr = Array.make (max_val + 1) 0 in  
+  let rec fill_index_arr i j =  
+    if i <= max_val then  
+      begin  
+        index_arr.(i) <- j;  
+        fill_index_arr (i + 1) (j + count_arr.(i))  
+      end  
+  in  
+  fill_index_arr 0 0;  
+  let sorted_arr = Array.make (Array.length arr) 0 in  
+  Array.iter (fun x -> sorted_arr.(index_arr.(x)) <- x; index_arr.(x) <- index_arr.(x) + 1) arr;  
+  sorted_arr  
+
+ +

Here, arr is the input array to be sorted. The function counting_sort first finds the maximum value in the input array and creates a new array count_arr to count the number of occurrences of each element in the input array. It then creates another array index_arr to store the index of each element in the sorted output array. The function fill_index_arr is a helper function that fills in the index_arr array based on the counts in count_arr. Finally, the function creates a new array sorted_arr and fills it in by iterating over the input array and using the index_arr array to determine the position of each element in the sorted output array.

+ +

Step-by-step Explanation

+
    +
  1. Find the maximum value in the input array.
  2. +
  3. Create a new array count_arr of length max_val + 1 and initialize all elements to 0.
  4. +
  5. Iterate over the input array and increment the count of each element in count_arr.
  6. +
  7. Create a new array index_arr of length max_val + 1 and initialize all elements to 0.
  8. +
  9. Define a helper function fill_index_arr that fills in the index_arr array based on the counts in count_arr. The function takes two arguments: i and j, where i is the current index in count_arr and j is the current index in index_arr.
  10. +
  11. Call the fill_index_arr function with initial arguments 0 and 0.
  12. +
  13. Create a new array sorted_arr of length n, where n is the length of the input array.
  14. +
  15. Iterate over the input array and use the index_arr array to determine the position of each element in the sorted output array. Store each element in the corresponding position in sorted_arr.
  16. +
  17. Return sorted_arr.
  18. +
+ +

Complexity Analysis

+

The time complexity of counting sort is O(n + k), where n is the length of the input array and k is the range of the input integers. The space complexity is also O(n + k).

+ +

The algorithm iterates over the input array twice: once to count the occurrences of each element and once to fill in the sorted output array. The time complexity of these two iterations is O(n). The algorithm also creates two additional arrays: count_arr and index_arr, each of length k. Therefore, the space complexity of the algorithm is O(n + k).

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/10/selection-sort.html b/docs/blog/algorithm/2023/11/10/selection-sort.html new file mode 100644 index 0000000..d95199e --- /dev/null +++ b/docs/blog/algorithm/2023/11/10/selection-sort.html @@ -0,0 +1,140 @@ + + + + + +Selection Sort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Selection Sort

+ +
+ +
+

Introduction

+

Selection sort is a simple sorting algorithm that works by repeatedly finding the minimum element from an unsorted list and putting it at the beginning. The algorithm is not very efficient for large lists, but it has the advantage of being simple to understand and implement.

+ +

Implementation

+

Here is an implementation of selection sort in OCaml:

+ +
let rec find_min i arr =  
+  if i = Array.length arr then -1  
+  else  
+    let min_idx = find_min (i+1) arr in  
+    if min_idx = -1 || arr.(i) < arr.(min_idx) then i else min_idx  
+   
+let selection_sort arr =  
+  for i = 0 to Array.length arr - 1 do  
+    let min_idx = find_min i arr in  
+    let tmp = arr.(i) in  
+    arr.(i) <- arr.(min_idx);  
+    arr.(min_idx) <- tmp  
+  done  
+
+ +

Here, find_min is a helper function that finds the index of the minimum element in the array arr starting from index i. It returns -1 if i is already at the end of the array. selection_sort uses find_min to find the minimum element in the unsorted portion of the array and swaps it with the first element in the unsorted portion. This process is repeated until the entire array is sorted.

+ +

Here is an example of using selection_sort:

+ +
let arr = [|5; 2; 9; 3; 6|]  
+selection_sort arr  
+(* arr is now [|2; 3; 5; 6; 9|] *)  
+
+ +

Step-by-step Explanation

+
    +
  1. We start with an unsorted array arr.
  2. +
  3. We iterate over the array from index 0 to n-1, where n is the length of the array.
  4. +
  5. For each iteration, we call find_min to find the index of the minimum element in the unsorted portion of the array starting from index i.
  6. +
  7. We swap the element at index i with the minimum element found in step 3.
  8. +
  9. We repeat steps 3-4 until the entire array is sorted.
  10. +
+ +

Complexity Analysis

+

The time complexity of selection sort is O(n^2), where n is the length of the array. This is because we have to iterate over the entire array n times, and for each iteration, we have to find the minimum element in the unsorted portion of the array, which takes O(n) time. The space complexity of selection sort is O(1), because we only need to store a few variables to keep track of the indices and the temporary value during the swapping process.

+ +

Selection sort is not very efficient for large arrays, but it has the advantage of being simple to implement and understand. It can also be useful in situations where memory is limited, since it only requires a constant amount of extra memory.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/10/shell-sort.html b/docs/blog/algorithm/2023/11/10/shell-sort.html new file mode 100644 index 0000000..99425b6 --- /dev/null +++ b/docs/blog/algorithm/2023/11/10/shell-sort.html @@ -0,0 +1,148 @@ + + + + + +Selection Sort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Selection Sort

+ +
+ +
+

Introduction

+

Shell sort is an efficient sorting algorithm that is a variation of insertion sort. It was invented by Donald Shell in 1959. The algorithm works by sorting elements that are far apart from each other and then gradually reducing the gap between them. This makes the algorithm faster than insertion sort for larger lists.

+ +

Implementation

+

Here is an implementation of Shell sort in OCaml:

+ +
let shell_sort arr =  
+  let n = Array.length arr in  
+  let gap = ref (n / 2) in  
+  while !gap > 0 do  
+    for i = !gap to n - 1 do  
+      let temp = arr.(i) in  
+      let j = ref i in  
+      while !j >= !gap && arr.(!j - !gap) > temp do  
+        arr.(!j) <- arr.(!j - !gap);  
+        j := !j - !gap  
+      done;  
+      arr.(!j) <- temp  
+    done;  
+    gap := !gap / 2  
+  done;  
+  arr  
+
+ +

To use this function, simply pass in an array of elements to sort:

+ +
let arr = [| 5; 3; 8; 4; 2 |]  
+let sorted_arr = shell_sort arr  
+
+ +

The sorted_arr variable will contain the sorted array.

+ +

Step-by-step Explanation

+
    +
  1. Start by dividing the list into sublists of equal intervals. The interval is called the gap.
  2. +
  3. Sort each sublist using insertion sort.
  4. +
  5. Reduce the gap by half and repeat step 2 until the gap is 1.
  6. +
+ +

For example, let’s say we have the following list of integers: [5, 3, 8, 4, 2]. We’ll use a gap of 2 for the first pass.

+ +
    +
  1. Divide the list into sublists with a gap of 2: [5, 8, 2] and [3, 4].
  2. +
  3. Sort each sublist using insertion sort. The first sublist becomes [2, 5, 8] and the second sublist stays the same: [3, 4].
  4. +
  5. Reduce the gap to 1 and sort the entire list using insertion sort. The sorted list is [2, 3, 4, 5, 8].
  6. +
+ +

Complexity Analysis

+

The time complexity of Shell sort depends on the gap sequence used. The worst-case time complexity is O(n^2), which occurs when the gap sequence is 1, making the algorithm equivalent to insertion sort. However, the average-case time complexity is O(n log n), which is faster than insertion sort for larger lists.

+ +

The space complexity of Shell sort is O(1) because it sorts the list in place.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/20/heapsort.html b/docs/blog/algorithm/2023/11/20/heapsort.html new file mode 100644 index 0000000..8d5106b --- /dev/null +++ b/docs/blog/algorithm/2023/11/20/heapsort.html @@ -0,0 +1,157 @@ + + + + + +Heapsort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Heapsort

+ +
+ +
+

Introduction

+

Heapsort is a comparison-based sorting algorithm that uses a binary heap data structure. It was first proposed by J. W. J. Williams in 1964. Heapsort is an in-place algorithm, meaning that it sorts the array in place, without needing any additional memory. It has a time complexity of O(n log n), which makes it efficient for large data sets.

+ +

Implementation

+

Here is an implementation of heapsort in OCaml:

+ +
let swap arr i j =  
+  let temp = arr.(i) in  
+  arr.(i) <- arr.(j);  
+  arr.(j) <- temp  
+   
+let rec heapify arr n i =  
+  let largest = ref i in  
+  let left = 2 * i + 1 in  
+  let right = 2 * i + 2 in  
+  if left < n && arr.(left) > arr.(!largest) then  
+    largest := left;  
+  if right < n && arr.(right) > arr.(!largest) then  
+    largest := right;  
+  if !largest <> i then (  
+    swap arr i !largest;  
+    heapify arr n !largest  
+  )  
+   
+let heapsort arr =  
+  let n = Array.length arr in  
+  for i = n / 2 - 1 downto 0 do  
+    heapify arr n i  
+  done;  
+  for i = n - 1 downto 1 do  
+    swap arr 0 i;  
+    heapify arr i 0  
+  done  
+
+ +

Here is an example of how to use the heapsort function:

+ +
let arr = [|4; 2; 7; 1; 3|] in  
+heapsort arr;  
+Array.iter (Printf.printf "%d ") arr  
+
+ +

Output:

+
1 2 3 4 7  
+
+ +

Step-by-step Explanation

+
    +
  1. Build a max heap from the input data. A binary heap is a complete binary tree where each node is greater than or equal to its children. The largest element is stored at the root of the heap.
  2. +
  3. Swap the root node with the last element in the array. Decrease the heap size by 1.
  4. +
  5. Call heapify on the root node to restore the heap property.
  6. +
  7. Repeat steps 2-3 until the heap size is 1.
  8. +
+ +

The heapify function takes three arguments: the array to be sorted, the size of the heap, and the index of the current node. It compares the current node with its left and right children and swaps it with the largest child if necessary. It then recursively calls heapify on the largest child to ensure that the subtree rooted at the current node is also a heap.

+ +

Complexity Analysis

+

The time complexity of heapsort is O(n log n) in the worst case. Building the heap takes O(n) time, and each call to heapify takes O(log n) time. We call heapify n-1 times in the second loop, so the total time complexity is O(n log n).

+ +

Heapsort is an in-place sorting algorithm, so it requires no additional memory beyond the array to be sorted. However, it is not a stable sorting algorithm, meaning that it does not preserve the relative order of equal elements in the input array.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/20/insertion-sort.html b/docs/blog/algorithm/2023/11/20/insertion-sort.html new file mode 100644 index 0000000..79de2e1 --- /dev/null +++ b/docs/blog/algorithm/2023/11/20/insertion-sort.html @@ -0,0 +1,128 @@ + + + + + +Insertion Sort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Insertion Sort

+ +
+ +
+

Introduction

+

Insertion sort is a simple sorting algorithm that is widely used in computer science. It works by taking one element from the unsorted list and inserting it into the correct position in the sorted list. The algorithm is efficient for small data sets but becomes inefficient for larger ones. Insertion sort can be used in situations where the data is already partially sorted or where the cost of swapping elements is high.

+ +

Implementation

+

Here is an implementation of insertion sort in OCaml:

+ +
let rec insertion_sort = function  
+  | [] -> []  
+  | x :: xs -> insert x (insertion_sort xs)  
+and insert x = function  
+  | [] -> [x]  
+  | y :: ys -> if x < y then x :: y :: ys else y :: insert x ys  
+
+ +

This implementation uses a recursive function to sort the list. The insertion_sort function takes a list as input and returns a sorted list. The insert function takes an element x and a sorted list as input and returns a new sorted list with x inserted in the correct position.

+ +

Step-by-step Explanation

+
    +
  1. The insertion_sort function is called with a list as input.
  2. +
  3. If the list is empty, an empty list is returned.
  4. +
  5. Otherwise, the first element x is removed from the list and the insert function is called with x and the sorted list returned by a recursive call to insertion_sort.
  6. +
  7. The insert function takes x and a sorted list as input.
  8. +
  9. If the list is empty, a list with x as the only element is returned.
  10. +
  11. Otherwise, the first element y is removed from the list and the insert function is called recursively with x and the remaining list ys.
  12. +
  13. If x is less than y, a new list with x and y followed by ys is returned.
  14. +
  15. Otherwise, a new list with y followed by the result of calling insert with x and ys is returned.
  16. +
  17. The sorted list returned by insert is returned by insertion_sort.
  18. +
+ +

Complexity Analysis

+

The time complexity of insertion sort is O(n^2) in the worst case, where n is the number of elements in the list. This is because each element must be compared to every other element in the list, resulting in n^2 comparisons. However, in the best case (when the list is already sorted), the time complexity is O(n) because each element only needs to be compared to the previous element. The space complexity of insertion sort is O(1) because the algorithm sorts the list in place without using any additional memory.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/20/mergesort.html b/docs/blog/algorithm/2023/11/20/mergesort.html new file mode 100644 index 0000000..6a28060 --- /dev/null +++ b/docs/blog/algorithm/2023/11/20/mergesort.html @@ -0,0 +1,152 @@ + + + + + +Merge Sort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Merge Sort

+ +
+ +
+

Introduction

+ +

Merge sort is a divide-and-conquer algorithm that sorts an array or list of elements by recursively dividing it into two halves, sorting each half, and then merging the sorted halves back together. It is a highly efficient sorting algorithm with a time complexity of O(n log n), making it suitable for large datasets. Merge sort is widely used in various applications, including sorting large databases, numerical analysis, and parallel computing.

+ +

Implementation

+ +

Here is an implementation of merge sort in OCaml:

+ +
let rec merge_sort = function  
+  | [] -> []  
+  | [x] -> [x]  
+  | xs ->  
+      let rec split left right = function  
+        | [] -> (left, right)  
+        | x :: xs -> split right (x :: left) xs  
+      in  
+      let rec merge left right = match left, right with  
+        | [], _ -> right  
+        | _, [] -> left  
+        | x :: xs, y :: ys ->  
+            if x < y then x :: merge xs right  
+            else y :: merge left ys  
+      in  
+      let left, right = split [] [] xs in  
+      merge (merge_sort left) (merge_sort right)  
+
+ +

Here is an example of using this implementation to sort a list of integers:

+ +
let sorted_list = merge_sort [4; 2; 7; 1; 3; 6; 5];;  
+
+ +

The resulting sorted_list will be [1; 2; 3; 4; 5; 6; 7].

+ +

Step-by-step Explanation

+ +
    +
  1. The merge_sort function takes a list of elements as input.
  2. +
  3. If the list is empty or contains only one element, it is already sorted, so the function returns the list as is.
  4. +
  5. Otherwise, the function recursively divides the list into two halves using the split function.
  6. +
  7. The split function takes two empty lists (left and right) and the original list as input.
  8. +
  9. If the original list is empty, the function returns the two half lists.
  10. +
  11. Otherwise, the function takes the first element of the original list and adds it to the right list, while the rest of the list is recursively split with the right list becoming the new left list.
  12. +
  13. The merge function takes two sorted lists (left and right) as input and returns a single sorted list.
  14. +
  15. If one of the input lists is empty, the function returns the other list as is.
  16. +
  17. Otherwise, the function compares the first elements of the two lists and adds the smaller one to the output list.
  18. +
  19. The function then recursively calls itself with the remaining elements of the input lists until both input lists are empty.
  20. +
  21. Finally, the merge_sort function merges the two sorted halves of the original list using the merge function.
  22. +
+ +

Complexity Analysis

+ +

The time complexity of merge sort is O(n log n), where n is the number of elements in the input list. This is because the algorithm recursively divides the input list into halves until each half contains only one element, which takes O(log n) time. Then, the algorithm merges the sorted halves back together, which takes O(n) time. Therefore, the total time complexity is O(n log n).

+ +

The space complexity of merge sort is O(n), where n is the number of elements in the input list. This is because the algorithm creates temporary lists to store the halves of the input list during the merge process. However, these temporary lists are deallocated after each recursive call, so the overall space complexity is O(n).

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/20/quicksort.html b/docs/blog/algorithm/2023/11/20/quicksort.html new file mode 100644 index 0000000..54f40e9 --- /dev/null +++ b/docs/blog/algorithm/2023/11/20/quicksort.html @@ -0,0 +1,175 @@ + + + + + +Quicksort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Quicksort

+ +
+ +
+

Introduction

+ +

Quicksort was developed by British computer scientist Tony Hoare in 1959. It is one of the most widely used sorting algorithms and is commonly used in computer science and engineering applications.

+ +

Quicksort is particularly useful when sorting large datasets because it has an average time complexity of O(n log n), which is faster than many other sorting algorithms. It is also an in-place sorting algorithm, meaning that it does not require any additional memory beyond the input array.

+ +

Quicksort is used in a variety of applications, including sorting large databases, sorting elements in computer graphics and image processing, and in network routing algorithms. It is also used in many programming languages as a built-in sorting function, such as Python’s sorted() function and C++’s std::sort() function.

+ +

Implementation

+ +
let rec quicksort = function  
+  | [] -> []  
+  | pivot::tail ->  
+    let lesser, greater = List.partition (fun x -> x < pivot) tail in  
+    quicksort lesser @ [pivot] @ quicksort greater  
+
+ +

This implementation uses a functional programming style and takes advantage of pattern matching to handle the two cases of the input list: the empty list, which is already sorted, and a non-empty list, which is partitioned into two sub-lists based on a pivot element (in this case, the first element of the list).

+ +

The List.partition function is used to split the tail of the input list into two sub-lists: lesser, which contains all elements that are strictly less than the pivot, and greater, which contains all elements that are greater than or equal to the pivot. The @ operator is used to concatenate the sorted lesser sub-list, the pivot element, and the sorted greater sub-list into a single sorted list.

+ +

Here’s an example usage of the quicksort function:

+ +
let unsorted = [5; 1; 3; 9; 2]  
+let sorted = quicksort unsorted  
+
+ +

After running this code, the sorted variable should contain the list [1; 2; 3; 5; 9], which is the sorted version of the unsorted list.

+ +

Step-by-step Explanation

+ +

Here’s a step-by-step explanation of how the quicksort algorithm works:

+ +
    +
  1. +

    Choose a pivot element from the list. This can be any element, but a common choice is the first or last element in the list.

    +
  2. +
  3. +

    Partition the list into two sub-lists, with one sub-list containing elements less than the pivot and the other sub-list containing elements greater than or equal to the pivot. This can be done by iterating through the list and swapping elements as necessary to ensure that all elements less than the pivot are on one side of the pivot and all elements greater than or equal to the pivot are on the other side.

    +
  4. +
  5. +

    Recursively apply steps 1 and 2 to the sub-lists until the entire list is sorted. This can be done by calling the quicksort function on each sub-list.

    +
  6. +
+ +

Here’s an example of how this algorithm would sort the list [5; 1; 3; 9; 2]:

+ +
    +
  1. +

    Choose the first element, 5, as the pivot.

    +
  2. +
  3. +

    Partition the list into two sub-lists: [1; 3; 2] and [9]. All elements less than 5 are on the left and all elements greater than or equal to 5 are on the right.

    +
  4. +
  5. +

    Recursively apply steps 1 and 2 to each sub-list. For the left sub-list, choose 1 as the pivot and partition it into [ ], [1], and [3; 2]. For the right sub-list, it is already sorted.

    +
  6. +
  7. +

    Recursively apply steps 1 and 2 to the sub-lists [1] and [3; 2]. Both sub-lists are already sorted, so no further partitioning is necessary.

    +
  8. +
  9. +

    Concatenate the sorted sub-lists in the order [1], [2; 3], [5], and [9] to obtain the sorted list [1; 2; 3; 5; 9].

    +
  10. +
+ +

This example shows how the quicksort algorithm works by recursively dividing the input list into smaller sub-lists, sorting them, and then combining them to obtain the final sorted list.

+ +

Complexity

+ +

The time complexity of quicksort is O(n log n) on average, where n is the number of elements in the input list.

+ +

The average case occurs when the pivot element is chosen randomly and is close to the median value of the list. In this case, the list is divided roughly in half with each partition, and the algorithm will make log n recursive calls to sort the entire list. The partitioning step takes linear time, so the total time complexity is O(n log n).

+ +

However, in the worst case, quicksort can have a time complexity of O(n^2) if the pivot element is consistently chosen poorly. For example, if the pivot is always chosen as the smallest or largest element in the list, then each partition will only remove one element from the list, and the algorithm will make n recursive calls to sort the entire list. This worst-case scenario is rare in practice, but it can occur in certain edge cases.

+ +

In terms of space complexity, quicksort is an in-place sorting algorithm, meaning that it does not require any additional memory beyond the input list. However, the recursive nature of the algorithm means that it has a space complexity of O(log n) due to the call stack used for the recursive calls.

+ +

Overall, quicksort is a highly efficient sorting algorithm with a time complexity of O(n log n) on average, making it a popular choice for sorting large datasets.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/algorithm/2023/11/20/radix-sort.html b/docs/blog/algorithm/2023/11/20/radix-sort.html new file mode 100644 index 0000000..d33d002 --- /dev/null +++ b/docs/blog/algorithm/2023/11/20/radix-sort.html @@ -0,0 +1,149 @@ + + + + + +Radix Sort | Algorithm Blog + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+

Radix Sort

+ +
+ +
+

Introduction

+

Radix sort is a sorting algorithm that sorts elements by grouping them based on their digits or bits. It is a non-comparative integer sorting algorithm that sorts data with integer keys by grouping the keys by individual digits that share the same significant position and value. Radix sort is often used for sorting large numbers of records, such as in big data applications.

+ +

Implementation

+

Here is an implementation of radix sort in OCaml:

+ +
let radix_sort arr =  
+  let rec loop arr exp =  
+    if exp < 0 then arr else  
+      let zeroes, ones = List.partition (fun x -> x land (1 lsl exp) = 0) arr in  
+      loop zeroes (exp - 1) @ loop ones (exp - 1)  
+  in  
+  loop arr (List.fold_left (fun m x -> max m (int_of_float (log10 (float_of_int x)))) 0 arr)  
+
+ +

Here, radix_sort takes in an array of integers arr and returns a sorted array. The loop function recursively sorts the array by partitioning it into two subarrays based on the value of the exp-th bit (starting from the most significant bit). The exp parameter is initially set to the maximum number of digits in any element of the array. The function log10 is used to calculate the number of digits in each element.

+ +

Step-by-step Explanation

+
    +
  1. Find the maximum number of digits in any element of the array.
  2. +
  3. For each bit position starting from the most significant bit, partition the array into two subarrays based on the value of that bit.
  4. +
  5. Recursively sort each subarray by repeating step 2 with the next bit position.
  6. +
  7. Concatenate the sorted subarrays to get the final sorted array.
  8. +
+ +

For example, let’s say we have the following array:

+ +
[170, 45, 75, 90, 802, 24, 2, 66]  
+
+ +

The maximum number of digits is 3, so we start by partitioning the array based on the third bit:

+ +
[170, 90, 802, 2, 24, 45, 75, 66]  
+
+ +

We then recursively sort each subarray by partitioning based on the second bit:

+ +
[802, 2, 24, 45, 66, 170, 75, 90]  
+
+ +
[2, 24, 45, 66, 75, 90, 170, 802]  
+
+ +

Finally, we concatenate the sorted subarrays to get the final sorted array:

+ +
[2, 24, 45, 66, 75, 90, 170, 802]  
+
+ +

Complexity Analysis

+

The time complexity of radix sort is O(d * (n + k)), where d is the maximum number of digits in any element of the array, n is the number of elements in the array, and k is the range of values (i.e., the maximum value minus the minimum value). The space complexity is O(n + k).

+ +

In the worst case, when d is very large, radix sort can be slower than comparison-based sorting algorithms like quicksort or mergesort. However, radix sort has the advantage of being able to sort large integers and other non-comparable data types that cannot be easily sorted using comparison-based algorithms.

+ +
+
+ +
+
+ + + diff --git a/docs/blog/assets/css/style.css b/docs/blog/assets/css/style.css new file mode 100644 index 0000000..d90a056 --- /dev/null +++ b/docs/blog/assets/css/style.css @@ -0,0 +1,747 @@ +.highlight .c { + color: #998; + font-style: italic; +} +.highlight .err { + color: #a61717; + background-color: #e3d2d2; +} +.highlight .k { + font-weight: bold; +} +.highlight .o { + font-weight: bold; +} +.highlight .cm { + color: #998; + font-style: italic; +} +.highlight .cp { + color: #999; + font-weight: bold; +} +.highlight .c1 { + color: #998; + font-style: italic; +} +.highlight .cs { + color: #999; + font-weight: bold; + font-style: italic; +} +.highlight .gd { + color: #000; + background-color: #fdd; +} +.highlight .gd .x { + color: #000; + background-color: #faa; +} +.highlight .ge { + font-style: italic; +} +.highlight .gr { + color: #a00; +} +.highlight .gh { + color: #999; +} +.highlight .gi { + color: #000; + background-color: #dfd; +} +.highlight .gi .x { + color: #000; + background-color: #afa; +} +.highlight .go { + color: #888; +} +.highlight .gp { + color: #555; +} +.highlight .gs { + font-weight: bold; +} +.highlight .gu { + color: #aaa; +} +.highlight .gt { + color: #a00; +} +.highlight .kc { + font-weight: bold; +} +.highlight .kd { + font-weight: bold; +} +.highlight .kp { + font-weight: bold; +} +.highlight .kr { + font-weight: bold; +} +.highlight .kt { + color: #458; + font-weight: bold; +} +.highlight .m { + color: #099; +} +.highlight .s { + color: #d14; +} +.highlight .na { + color: #008080; +} +.highlight .nb { + color: #0086B3; +} +.highlight .nc { + color: #458; + font-weight: bold; +} +.highlight .no { + color: #008080; +} +.highlight .ni { + color: #800080; +} +.highlight .ne { + color: #900; + font-weight: bold; +} +.highlight .nf { + color: #900; + font-weight: bold; +} +.highlight .nn { + color: #555; +} +.highlight .nt { + color: #000080; +} +.highlight .nv { + color: #008080; +} +.highlight .ow { + font-weight: bold; +} +.highlight .w { + color: #bbb; +} +.highlight .mf { + color: #099; +} +.highlight .mh { + color: #099; +} +.highlight .mi { + color: #099; +} +.highlight .mo { + color: #099; +} +.highlight .sb { + color: #d14; +} +.highlight .sc { + color: #d14; +} +.highlight .sd { + color: #d14; +} +.highlight .s2 { + color: #d14; +} +.highlight .se { + color: #d14; +} +.highlight .sh { + color: #d14; +} +.highlight .si { + color: #d14; +} +.highlight .sx { + color: #d14; +} +.highlight .sr { + color: #009926; +} +.highlight .s1 { + color: #d14; +} +.highlight .ss { + color: #990073; +} +.highlight .bp { + color: #999; +} +.highlight .vc { + color: #008080; +} +.highlight .vg { + color: #008080; +} +.highlight .vi { + color: #008080; +} +.highlight .il { + color: #099; +} + +html { + font-size: 16px; +} + +/** + * Reset some basic elements + */ +body, h1, h2, h3, h4, h5, h6, +p, blockquote, pre, hr, +dl, dd, ol, ul, figure { + margin: 0; + padding: 0; +} + +/** + * Basic styling + */ +body { + font: 400 16px/1.5 -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Segoe UI Emoji", "Segoe UI Symbol", "Apple Color Emoji", Roboto, Helvetica, Arial, sans-serif; + color: #111111; + background-color: #fdfdfd; + -webkit-text-size-adjust: 100%; + -webkit-font-feature-settings: "kern" 1; + -moz-font-feature-settings: "kern" 1; + -o-font-feature-settings: "kern" 1; + font-feature-settings: "kern" 1; + font-kerning: normal; + display: flex; + min-height: 100vh; + flex-direction: column; + overflow-wrap: break-word; +} + +/** + * Set `margin-bottom` to maintain vertical rhythm + */ +h1, h2, h3, h4, h5, h6, +p, blockquote, pre, +ul, ol, dl, figure, +.highlight { + margin-bottom: 15px; +} + +hr { + margin-top: 30px; + margin-bottom: 30px; +} + +/** + * `main` element + */ +main { + display: block; /* Default value of `display` of `main` element is 'inline' in IE 11. */ +} + +/** + * Images + */ +img { + max-width: 100%; + vertical-align: middle; +} + +/** + * Figures + */ +figure > img { + display: block; +} + +figcaption { + font-size: 14px; +} + +/** + * Lists + */ +ul, ol { + margin-left: 30px; +} + +li > ul, +li > ol { + margin-bottom: 0; +} + +/** + * Headings + */ +h1, h2, h3, h4, h5, h6 { + font-weight: 400; +} + +/** + * Links + */ +a { + color: #2a7ae2; + text-decoration: none; +} +a:visited { + color: #1756a9; +} +a:hover { + color: #111111; + text-decoration: underline; +} +.social-media-list a:hover, .pagination a:hover { + text-decoration: none; +} +.social-media-list a:hover .username, .pagination a:hover .username { + text-decoration: underline; +} + +/** + * Blockquotes + */ +blockquote { + color: #828282; + border-left: 4px solid #e8e8e8; + padding-left: 15px; + font-size: 1.125rem; + font-style: italic; +} +blockquote > :last-child { + margin-bottom: 0; +} +blockquote i, blockquote em { + font-style: normal; +} + +/** + * Code formatting + */ +pre, +code { + font-family: "Menlo", "Inconsolata", "Consolas", "Roboto Mono", "Ubuntu Mono", "Liberation Mono", "Courier New", monospace; + font-size: 0.9375em; + border: 1px solid #e8e8e8; + border-radius: 3px; + background-color: #eeeeff; +} + +code { + padding: 1px 5px; +} + +pre { + padding: 8px 12px; + overflow-x: auto; +} +pre > code { + border: 0; + padding-right: 0; + padding-left: 0; +} + +.highlight { + border-radius: 3px; + background: #eeeeff; +} +.highlighter-rouge .highlight { + background: #eeeeff; +} + +/** + * Wrapper + */ +.wrapper { + max-width: calc(800px - (30px)); + margin-right: auto; + margin-left: auto; + padding-right: 15px; + padding-left: 15px; +} +@media screen and (min-width: 800px) { + .wrapper { + max-width: calc(800px - 30px * 2); + padding-right: 30px; + padding-left: 30px; + } +} + +/** + * Clearfix + */ +.wrapper:after { + content: ""; + display: table; + clear: both; +} + +/** + * Icons + */ +.orange { + color: #f66a0a; +} + +.grey { + color: #828282; +} + +.svg-icon { + width: 1.25em; + height: 1.25em; + display: inline-block; + fill: currentColor; + vertical-align: text-bottom; +} + +/** + * Tables + */ +table { + margin-bottom: 30px; + width: 100%; + text-align: left; + color: #3f3f3f; + border-collapse: collapse; + border: 1px solid #e8e8e8; +} +table tr:nth-child(even) { + background-color: #f7f7f7; +} +table th, table td { + padding: 10px 15px; +} +table th { + background-color: #f0f0f0; + border: 1px solid #e0e0e0; +} +table td { + border: 1px solid #e8e8e8; +} +@media screen and (max-width: 800px) { + table { + display: block; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; + } +} + +/** + * Site header + */ +.site-header { + border-top: 5px solid #424242; + border-bottom: 1px solid #e8e8e8; + min-height: 55.95px; + line-height: 54px; + position: relative; +} + +.site-title { + font-size: 1.625rem; + font-weight: 300; + letter-spacing: -1px; + margin-bottom: 0; + float: left; +} +@media screen and (max-width: 600px) { + .site-title { + padding-right: 45px; + } +} +.site-title, .site-title:visited { + color: #424242; +} + +.site-nav { + position: absolute; + top: 9px; + right: 15px; + background-color: #fdfdfd; + border: 1px solid #e8e8e8; + border-radius: 5px; + text-align: right; +} +.site-nav .nav-trigger { + display: none; +} +.site-nav .menu-icon { + float: right; + width: 36px; + height: 26px; + line-height: 0; + padding-top: 10px; + text-align: center; +} +.site-nav .menu-icon > svg path { + fill: #424242; +} +.site-nav label[for=nav-trigger] { + display: block; + float: right; + width: 36px; + height: 36px; + z-index: 2; + cursor: pointer; +} +.site-nav input ~ .trigger { + clear: both; + display: none; +} +.site-nav input:checked ~ .trigger { + display: block; + padding-bottom: 5px; +} +.site-nav .page-link { + color: #111111; + line-height: 1.5; + display: block; + padding: 5px 10px; + margin-left: 20px; +} +.site-nav .page-link:not(:last-child) { + margin-right: 0; +} +@media screen and (min-width: 600px) { + .site-nav { + position: static; + float: right; + border: none; + background-color: inherit; + } + .site-nav label[for=nav-trigger] { + display: none; + } + .site-nav .menu-icon { + display: none; + } + .site-nav input ~ .trigger { + display: block; + } + .site-nav .page-link { + display: inline; + padding: 0; + margin-left: auto; + } + .site-nav .page-link:not(:last-child) { + margin-right: 20px; + } +} + +/** + * Site footer + */ +.site-footer { + border-top: 1px solid #e8e8e8; + padding: 30px 0; +} + +.footer-heading { + font-size: 1.125rem; + margin-bottom: 15px; +} + +.feed-subscribe .svg-icon { + padding: 5px 5px 2px 0; +} + +.contact-list, +.social-media-list, +.pagination { + list-style: none; + margin-left: 0; +} + +.footer-col-wrapper, +.social-links { + font-size: 0.9375rem; + color: #828282; +} + +.footer-col { + margin-bottom: 15px; +} + +.footer-col-1, +.footer-col-2 { + width: calc(50% - 30px / 2); +} + +.footer-col-3 { + width: calc(100% - 30px / 2); +} + +@media screen and (min-width: 800px) { + .footer-col-1 { + width: calc(35% - 30px / 2); + } + .footer-col-2 { + width: calc(20% - 30px / 2); + } + .footer-col-3 { + width: calc(45% - 30px / 2); + } +} +@media screen and (min-width: 600px) { + .footer-col-wrapper { + display: flex; + } + .footer-col { + width: calc(100% - 30px / 2); + padding: 0 15px; + } + .footer-col:first-child { + padding-right: 15px; + padding-left: 0; + } + .footer-col:last-child { + padding-right: 0; + padding-left: 15px; + } +} +/** + * Page content + */ +.page-content { + padding: 30px 0; + flex: 1 0 auto; +} + +.page-heading { + font-size: 2rem; +} + +.post-list-heading { + font-size: 1.75rem; +} + +.post-list { + margin-left: 0; + list-style: none; +} +.post-list > li { + margin-bottom: 30px; +} + +.post-meta { + font-size: 14px; + color: #828282; +} + +.post-link { + display: block; + font-size: 1.5rem; +} + +/** + * Posts + */ +.post-header { + margin-bottom: 30px; +} + +.post-title, +.post-content h1 { + font-size: 2.625rem; + letter-spacing: -1px; + line-height: 1.15; +} +@media screen and (min-width: 800px) { + .post-title, + .post-content h1 { + font-size: 2.625rem; + } +} + +.post-content { + margin-bottom: 30px; +} +.post-content h1, .post-content h2, .post-content h3, .post-content h4, .post-content h5, .post-content h6 { + margin-top: 30px; +} +.post-content h2 { + font-size: 1.75rem; +} +@media screen and (min-width: 800px) { + .post-content h2 { + font-size: 2rem; + } +} +.post-content h3 { + font-size: 1.375rem; +} +@media screen and (min-width: 800px) { + .post-content h3 { + font-size: 1.625rem; + } +} +.post-content h4 { + font-size: 1.25rem; +} +.post-content h5 { + font-size: 1.125rem; +} +.post-content h6 { + font-size: 1.0625rem; +} + +.social-media-list, .pagination { + display: table; + margin: 0 auto; +} +.social-media-list li, .pagination li { + float: left; + margin: 5px 10px 5px 0; +} +.social-media-list li:last-of-type, .pagination li:last-of-type { + margin-right: 0; +} +.social-media-list li a, .pagination li a { + display: block; + padding: 10px 12px; + border: 1px solid #e8e8e8; +} +.social-media-list li a:hover, .pagination li a:hover { + border-color: #dbdbdb; +} + +/** + * Pagination navbar + */ +.pagination { + margin-bottom: 30px; +} +.pagination li a, .pagination li div { + min-width: 41px; + text-align: center; + box-sizing: border-box; +} +.pagination li div { + display: block; + padding: 7.5px; + border: 1px solid transparent; +} +.pagination li div.pager-edge { + color: #e8e8e8; + border: 1px dashed; +} + +/** + * Grid helpers + */ +@media screen and (min-width: 800px) { + .one-half { + width: calc(50% - 30px / 2); + } +} + +/*# sourceMappingURL=style.css.map */ \ No newline at end of file diff --git a/docs/blog/assets/css/style.css.map b/docs/blog/assets/css/style.css.map new file mode 100644 index 0000000..b7b9474 --- /dev/null +++ b/docs/blog/assets/css/style.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../../../../.rvm/gems/ruby-3.2.2/bundler/gems/minima-101245159535/_sass/minima/skins/auto.scss","../../../../../.rvm/gems/ruby-3.2.2/bundler/gems/minima-101245159535/_sass/minima/_base.scss","../../../../../.rvm/gems/ruby-3.2.2/bundler/gems/minima-101245159535/_sass/minima/initialize.scss","../../../../../.rvm/gems/ruby-3.2.2/bundler/gems/minima-101245159535/_sass/minima/_layout.scss"],"names":[],"mappings":"AA0CI;EAAS;EAAa;;AACtB;EAAS;EAAgB;;AACzB;EAAS;;AACT;EAAS;;AACT;EAAS;EAAa;;AACtB;EAAS;EAAa;;AACtB;EAAS;EAAa;;AACtB;EAAS;EAAa;EAAmB;;AACzC;EAAS;EAAa;;AACtB;EAAS;EAAa;;AACtB;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;EAAa;;AACtB;EAAS;EAAa;;AACtB;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;EAAa;;AACtB;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;EAAa;;AACtB;EAAS;;AACT;EAAS;;AACT;EAAS;EAAa;;AACtB;EAAS;EAAa;;AACtB;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;AACT;EAAS;;;ACpGb;EACE,WCKiB;;;ADFnB;AAAA;AAAA;AAGA;AAAA;AAAA;EAGE;EACA;;;AAMF;AAAA;AAAA;AAGA;EACE;EACA,ODJyB;ECKzB,kBDJyB;ECKzB;EACA;EACG;EACE;EACG;EACR;EACA;EACA;EACA;EACA;;;AAKF;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;EAIE;;;AAGF;EACE,YCtCiB;EDuCjB,eCvCiB;;;AD0CnB;AAAA;AAAA;AAGA;EACE;;;AAKF;AAAA;AAAA;AAGA;EACE;EACA;;;AAKF;AAAA;AAAA;AAGA;EACE;;;AAGF;EACE,WCxEiB;;;AD6EnB;AAAA;AAAA;AAGA;EACE,aC9EiB;;;ADkFjB;AAAA;EAEE;;;AAMJ;AAAA;AAAA;AAGA;EACE,aClGiB;;;ADuGnB;AAAA;AAAA;AAGA;EACE,OD5FyB;EC6FzB;;AAEA;EACE,OD/FuB;;ACkGzB;EACE,ODxGuB;ECyGvB;;AAGF;EACE;;AAEA;EACE;;;AAMN;AAAA;AAAA;AAGA;EACE,ODhIyB;ECiIzB;EACA;ECtGA;EDwGA;;AAEA;EACE;;AAGF;EACE;;;AAMJ;AAAA;AAAA;AAGA;AAAA;EAEE,aC7JiB;ED8JjB;EACA;EACA;EACA,kBDlJyB;;;ACqJ3B;EACE;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;;AAIJ;EACE;EACA,YDtKyB;;ACyKzB;EACE,YD1KuB;;;ACgL3B;AAAA;AAAA;AAGA;EACE;EACA;EACA;EACA;EACA;;AAGA;EARF;IASI;IACA,eCtMe;IDuMf,cCvMe;;;;AD6MnB;AAAA;AAAA;AAGA;EACE;EACA;EACA;;;AAKF;AAAA;AAAA;AAIA;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAIF;AAAA;AAAA;AAGA;EACE,eCjPiB;EDkPjB;EACA,YCjPiB;EDkPjB,ODjOyB;ECkOzB;EACA;;AAEE;EACE,kBDrOqB;;ACwOzB;EACE;;AAEF;EACE,kBD3OuB;EC4OvB;;AAEF;EACE;;AC7OF;EDyNF;IAwBI;IACA;IACA;IACQ;;;;AEtRZ;AAAA;AAAA;AAGA;EACE;EACA;EACA;EACA;EAGA;;;AAGF;ED2BE;ECzBA;EACA;EACA;EACA;;ADgBA;ECrBF;IAQI;;;AAGF;EAEE,OHZuB;;;AGgB3B;EACE;EACA;EACA;EACA,kBHfyB;EGgBzB;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE,MHtCqB;;AG0CzB;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE,OH1DuB;EG2DvB,aDpEe;ECqEf;EACA;EAMA;;AAHA;EACE;;AAKJ;EA1DF;IA2DI;IACA;IACA;IACA;;EAEA;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;IACA;IAKA;;EAHA;IACE;;;;AASR;AAAA;AAAA;AAGA;EACE;EACA;;;AAGF;EDxFE;EC0FA;;;AAGF;EACE;;;AAGF;AAAA;AAAA;EAEE;EACA;;;AAGF;AAAA;EDvGE;EC0GA,OHtIyB;;;AGyI3B;EACE;;;AAGF;AAAA;EAEE;;;AAGF;EACE;;;AAGF;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;;AAIJ;EACE;IACE;;EAGF;IACE;IACA;;EAEA;IACE;IACA;;EAGF;IACE;IACA;;;AAON;AAAA;AAAA;AAGA;EACE;EACA;;;AAGF;EDvKE;;;AC2KF;ED3KE;;;AC+KF;EACE;EACA;;AAEA;EACE,eDjNe;;;ACqNnB;EACE,WDzNiB;EC0NjB,OHtNyB;;;AGyN3B;EACE;ED9LA;;;ACoMF;AAAA;AAAA;AAGA;EACE,eDrOiB;;;ACwOnB;AAAA;ED3ME;EC8MA;EACA;;AAEA;EANF;AAAA;ID3ME;;;;ACsNF;EACE,eDpPiB;;ACsPjB;EAAyB,YDtPR;;ACwPjB;ED3NA;;AC8NE;EAHF;ID3NA;;;ACmOA;EDnOA;;ACsOE;EAHF;IDnOA;;;AC2OA;ED3OA;;AC+OA;ED/OA;;ACkPA;EDlPA;;;ACwPF;EACE;EACA;;AACA;EACE;EACA;;AACA;EAAiB;;AACjB;EACE;EACA;EACA;;AACA;EAAU,cHhRW;;;AGuR3B;AAAA;AAAA;AAGA;EACE,eD3SiB;;AC8Sf;EACE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAEA;EACE,OHvTmB;EGwTnB;;;AAQR;AAAA;AAAA;AAGA;EACE;IACE","sourcesContent":["@charset \"utf-8\";\n\n// Default color scheme settings\n// These are overridden in classic.css and dark.scss\n\n$color-scheme-auto: true !default;\n$color-scheme-dark: false !default;\n\n\n// Light mode\n// ----------\n\n$lm-brand-color: #828282 !default;\n$lm-brand-color-light: lighten($lm-brand-color, 40%) !default;\n$lm-brand-color-dark: darken($lm-brand-color, 25%) !default;\n\n$lm-site-title-color: $lm-brand-color-dark !default;\n\n$lm-text-color: #111111 !default;\n$lm-background-color: #fdfdfd !default;\n$lm-code-background-color: #eeeeff !default;\n\n$lm-link-base-color: #2a7ae2 !default;\n$lm-link-visited-color: darken($lm-link-base-color, 15%) !default;\n$lm-link-hover-color: $lm-text-color !default;\n\n$lm-border-color-01: $lm-brand-color-light !default;\n$lm-border-color-02: lighten($lm-brand-color, 35%) !default;\n$lm-border-color-03: $lm-brand-color-dark !default;\n\n$lm-table-text-color: lighten($lm-text-color, 18%) !default;\n$lm-table-zebra-color: lighten($lm-brand-color, 46%) !default;\n$lm-table-header-bg-color: lighten($lm-brand-color, 43%) !default;\n$lm-table-header-border: lighten($lm-brand-color, 37%) !default;\n$lm-table-border-color: $lm-border-color-01 !default;\n\n\n// Syntax highlighting styles should be adjusted appropriately for every \"skin\"\n// ----------------------------------------------------------------------------\n\n@mixin lm-highlight {\n .highlight {\n .c { color: #998; font-style: italic } // Comment\n .err { color: #a61717; background-color: #e3d2d2 } // Error\n .k { font-weight: bold } // Keyword\n .o { font-weight: bold } // Operator\n .cm { color: #998; font-style: italic } // Comment.Multiline\n .cp { color: #999; font-weight: bold } // Comment.Preproc\n .c1 { color: #998; font-style: italic } // Comment.Single\n .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special\n .gd { color: #000; background-color: #fdd } // Generic.Deleted\n .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific\n .ge { font-style: italic } // Generic.Emph\n .gr { color: #a00 } // Generic.Error\n .gh { color: #999 } // Generic.Heading\n .gi { color: #000; background-color: #dfd } // Generic.Inserted\n .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific\n .go { color: #888 } // Generic.Output\n .gp { color: #555 } // Generic.Prompt\n .gs { font-weight: bold } // Generic.Strong\n .gu { color: #aaa } // Generic.Subheading\n .gt { color: #a00 } // Generic.Traceback\n .kc { font-weight: bold } // Keyword.Constant\n .kd { font-weight: bold } // Keyword.Declaration\n .kp { font-weight: bold } // Keyword.Pseudo\n .kr { font-weight: bold } // Keyword.Reserved\n .kt { color: #458; font-weight: bold } // Keyword.Type\n .m { color: #099 } // Literal.Number\n .s { color: #d14 } // Literal.String\n .na { color: #008080 } // Name.Attribute\n .nb { color: #0086B3 } // Name.Builtin\n .nc { color: #458; font-weight: bold } // Name.Class\n .no { color: #008080 } // Name.Constant\n .ni { color: #800080 } // Name.Entity\n .ne { color: #900; font-weight: bold } // Name.Exception\n .nf { color: #900; font-weight: bold } // Name.Function\n .nn { color: #555 } // Name.Namespace\n .nt { color: #000080 } // Name.Tag\n .nv { color: #008080 } // Name.Variable\n .ow { font-weight: bold } // Operator.Word\n .w { color: #bbb } // Text.Whitespace\n .mf { color: #099 } // Literal.Number.Float\n .mh { color: #099 } // Literal.Number.Hex\n .mi { color: #099 } // Literal.Number.Integer\n .mo { color: #099 } // Literal.Number.Oct\n .sb { color: #d14 } // Literal.String.Backtick\n .sc { color: #d14 } // Literal.String.Char\n .sd { color: #d14 } // Literal.String.Doc\n .s2 { color: #d14 } // Literal.String.Double\n .se { color: #d14 } // Literal.String.Escape\n .sh { color: #d14 } // Literal.String.Heredoc\n .si { color: #d14 } // Literal.String.Interpol\n .sx { color: #d14 } // Literal.String.Other\n .sr { color: #009926 } // Literal.String.Regex\n .s1 { color: #d14 } // Literal.String.Single\n .ss { color: #990073 } // Literal.String.Symbol\n .bp { color: #999 } // Name.Builtin.Pseudo\n .vc { color: #008080 } // Name.Variable.Class\n .vg { color: #008080 } // Name.Variable.Global\n .vi { color: #008080 } // Name.Variable.Instance\n .il { color: #099 } // Literal.Number.Integer.Long\n }\n}\n\n\n// Dark mode\n// ---------\n\n$dm-brand-color: #999999 !default;\n$dm-brand-color-light: lighten($dm-brand-color, 5%) !default;\n$dm-brand-color-dark: darken($dm-brand-color, 35%) !default;\n\n$dm-site-title-color: $dm-brand-color-light !default;\n\n$dm-text-color: #bbbbbb !default;\n$dm-background-color: #181818 !default;\n$dm-code-background-color: #212121 !default;\n\n$dm-link-base-color: #79b8ff !default;\n$dm-link-visited-color: $dm-link-base-color !default;\n$dm-link-hover-color: $dm-text-color !default;\n\n$dm-border-color-01: $dm-brand-color-dark !default;\n$dm-border-color-02: $dm-brand-color-light !default;\n$dm-border-color-03: $dm-brand-color !default;\n\n$dm-table-text-color: $dm-text-color !default;\n$dm-table-zebra-color: lighten($dm-background-color, 4%) !default;\n$dm-table-header-bg-color: lighten($dm-background-color, 10%) !default;\n$dm-table-header-border: lighten($dm-background-color, 21%) !default;\n$dm-table-border-color: $dm-border-color-01 !default;\n\n\n// Syntax highlighting styles should be adjusted appropriately for every \"skin\"\n// List of tokens: https://github.com/rouge-ruby/rouge/wiki/List-of-tokens\n// Some colors come from Material Theme Darker:\n// https://github.com/material-theme/vsc-material-theme/blob/master/scripts/generator/settings/specific/darker-hc.ts\n// https://github.com/material-theme/vsc-material-theme/blob/master/scripts/generator/color-set.ts\n// ----------------------------------------------------------------------------\n\n@mixin dm-highlight {\n .highlight {\n .c { color: #545454; font-style: italic } // Comment\n .err { color: #f07178; background-color: #e3d2d2 } // Error\n .k { color: #89DDFF; font-weight: bold } // Keyword\n .o { font-weight: bold } // Operator\n .cm { color: #545454; font-style: italic } // Comment.Multiline\n .cp { color: #545454; font-weight: bold } // Comment.Preproc\n .c1 { color: #545454; font-style: italic } // Comment.Single\n .cs { color: #545454; font-weight: bold; font-style: italic } // Comment.Special\n .gd { color: #000; background-color: #fdd } // Generic.Deleted\n .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific\n .ge { font-style: italic } // Generic.Emph\n .gr { color: #f07178 } // Generic.Error\n .gh { color: #999 } // Generic.Heading\n .gi { color: #000; background-color: #dfd } // Generic.Inserted\n .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific\n .go { color: #888 } // Generic.Output\n .gp { color: #555 } // Generic.Prompt\n .gs { font-weight: bold } // Generic.Strong\n .gu { color: #aaa } // Generic.Subheading\n .gt { color: #f07178 } // Generic.Traceback\n .kc { font-weight: bold } // Keyword.Constant\n .kd { font-weight: bold } // Keyword.Declaration\n .kp { font-weight: bold } // Keyword.Pseudo\n .kr { font-weight: bold } // Keyword.Reserved\n .kt { color: #FFCB6B; font-weight: bold } // Keyword.Type\n .m { color: #F78C6C } // Literal.Number\n .s { color: #C3E88D } // Literal.String\n .na { color: #008080 } // Name.Attribute\n .nb { color: #EEFFFF } // Name.Builtin\n .nc { color: #FFCB6B; font-weight: bold } // Name.Class\n .no { color: #008080 } // Name.Constant\n .ni { color: #800080 } // Name.Entity\n .ne { color: #900; font-weight: bold } // Name.Exception\n .nf { color: #82AAFF; font-weight: bold } // Name.Function\n .nn { color: #555 } // Name.Namespace\n .nt { color: #FFCB6B } // Name.Tag\n .nv { color: #EEFFFF } // Name.Variable\n .ow { font-weight: bold } // Operator.Word\n .w { color: #EEFFFF } // Text.Whitespace\n .mf { color: #F78C6C } // Literal.Number.Float\n .mh { color: #F78C6C } // Literal.Number.Hex\n .mi { color: #F78C6C } // Literal.Number.Integer\n .mo { color: #F78C6C } // Literal.Number.Oct\n .sb { color: #C3E88D } // Literal.String.Backtick\n .sc { color: #C3E88D } // Literal.String.Char\n .sd { color: #C3E88D } // Literal.String.Doc\n .s2 { color: #C3E88D } // Literal.String.Double\n .se { color: #EEFFFF } // Literal.String.Escape\n .sh { color: #C3E88D } // Literal.String.Heredoc\n .si { color: #C3E88D } // Literal.String.Interpol\n .sx { color: #C3E88D } // Literal.String.Other\n .sr { color: #C3E88D } // Literal.String.Regex\n .s1 { color: #C3E88D } // Literal.String.Single\n .ss { color: #C3E88D } // Literal.String.Symbol\n .bp { color: #999 } // Name.Builtin.Pseudo\n .vc { color: #FFCB6B } // Name.Variable.Class\n .vg { color: #EEFFFF } // Name.Variable.Global\n .vi { color: #EEFFFF } // Name.Variable.Instance\n .il { color: #F78C6C } // Literal.Number.Integer.Long\n }\n}\n\n\n// Mode selection\n// --------------\n\n\n// Classic skin (always light mode)\n// Assign outside of the if construct to establish global variable scope\n\n$brand-color: $lm-brand-color;\n$brand-color-light: $lm-brand-color-light;\n$brand-color-dark: $lm-brand-color-dark;\n\n$site-title-color: $lm-site-title-color;\n\n$text-color: $lm-text-color;\n$background-color: $lm-background-color;\n$code-background-color: $lm-code-background-color;\n\n$link-base-color: $lm-link-base-color;\n$link-visited-color: $lm-link-visited-color;\n$link-hover-color: $lm-link-hover-color;\n\n$border-color-01: $lm-border-color-01;\n$border-color-02: $lm-border-color-02;\n$border-color-03: $lm-border-color-03;\n\n$table-text-color: $lm-table-text-color;\n$table-zebra-color: $lm-table-zebra-color;\n$table-header-bg-color: $lm-table-header-bg-color;\n$table-header-border: $lm-table-header-border;\n$table-border-color: $lm-table-border-color;\n\n\n@if $color-scheme-auto {\n\n // Auto mode\n\n :root {\n --minima-brand-color: #{$lm-brand-color};\n --minima-brand-color-light: #{$lm-brand-color-light};\n --minima-brand-color-dark: #{$lm-brand-color-dark};\n\n --minima-site-title-color: #{$lm-site-title-color};\n\n --minima-text-color: #{$lm-text-color};\n --minima-background-color: #{$lm-background-color};\n --minima-code-background-color: #{$lm-code-background-color};\n\n --minima-link-base-color: #{$lm-link-base-color};\n --minima-link-visited-color: #{$lm-link-visited-color};\n --minima-link-hover-color: #{$lm-link-hover-color};\n\n --minima-border-color-01: #{$lm-border-color-01};\n --minima-border-color-02: #{$lm-border-color-02};\n --minima-border-color-03: #{$lm-border-color-03};\n\n --minima-table-text-color: #{$lm-table-text-color};\n --minima-table-zebra-color: #{$lm-table-zebra-color};\n --minima-table-header-bg-color: #{$lm-table-header-bg-color};\n --minima-table-header-border: #{$lm-table-header-border};\n --minima-table-border-color: #{$lm-table-border-color};\n }\n\n @include lm-highlight;\n\n @media (prefers-color-scheme: dark) {\n :root {\n --minima-brand-color: #{$dm-brand-color};\n --minima-brand-color-light: #{$dm-brand-color-light};\n --minima-brand-color-dark: #{$dm-brand-color-dark};\n\n --minima-site-title-color: #{$dm-site-title-color};\n\n --minima-text-color: #{$dm-text-color};\n --minima-background-color: #{$dm-background-color};\n --minima-code-background-color: #{$dm-code-background-color};\n\n --minima-link-base-color: #{$dm-link-base-color};\n --minima-link-visited-color: #{$dm-link-visited-color};\n --minima-link-hover-color: #{$dm-link-hover-color};\n\n --minima-border-color-01: #{$dm-border-color-01};\n --minima-border-color-02: #{$dm-border-color-02};\n --minima-border-color-03: #{$dm-border-color-03};\n\n --minima-table-text-color: #{$dm-table-text-color};\n --minima-table-zebra-color: #{$dm-table-zebra-color};\n --minima-table-header-bg-color: #{$dm-table-header-bg-color};\n --minima-table-header-border: #{$dm-table-header-border};\n --minima-table-border-color: #{$dm-table-border-color};\n }\n\n @include dm-highlight;\n }\n\n $brand-color: var(--minima-brand-color);\n $brand-color-light: var(--minima-brand-color-light);\n $brand-color-dark: var(--minima-brand-color-dark);\n\n $site-title-color: var(--minima-site-title-color);\n\n $text-color: var(--minima-text-color);\n $background-color: var(--minima-background-color);\n $code-background-color: var(--minima-code-background-color);\n\n $link-base-color: var(--minima-link-base-color);\n $link-visited-color: var(--minima-link-visited-color);\n $link-hover-color: var(--minima-link-hover-color);\n\n $border-color-01: var(--minima-border-color-01);\n $border-color-02: var(--minima-border-color-02);\n $border-color-03: var(--minima-border-color-03);\n\n $table-text-color: var(--minima-table-text-color);\n $table-zebra-color: var(--minima-table-zebra-color);\n $table-header-bg-color: var(--minima-table-header-bg-color);\n $table-header-border: var(--minima-table-header-border);\n $table-border-color: var(--minima-table-border-color);\n\n\n} @else if $color-scheme-dark {\n\n // Dark skin (always dark mode)\n\n $brand-color: $dm-brand-color;\n $brand-color-light: $dm-brand-color-light;\n $brand-color-dark: $dm-brand-color-dark;\n\n $site-title-color: $dm-site-title-color;\n\n $text-color: $dm-text-color;\n $background-color: $dm-background-color;\n $code-background-color: $dm-code-background-color;\n\n $link-base-color: $dm-link-base-color;\n $link-visited-color: $dm-link-visited-color;\n $link-hover-color: $dm-link-hover-color;\n\n $border-color-01: $dm-border-color-01;\n $border-color-02: $dm-border-color-02;\n $border-color-03: $dm-border-color-03;\n\n $table-text-color: $dm-table-text-color;\n $table-zebra-color: $dm-table-zebra-color;\n $table-header-bg-color: $dm-table-header-bg-color;\n $table-header-border: $dm-table-header-border;\n $table-border-color: $dm-table-border-color;\n\n @include dm-highlight;\n\n\n} @else {\n\n // Classic skin syntax highlighting\n @include lm-highlight;\n\n}\n","html {\n font-size: $base-font-size;\n}\n\n/**\n * Reset some basic elements\n */\nbody, h1, h2, h3, h4, h5, h6,\np, blockquote, pre, hr,\ndl, dd, ol, ul, figure {\n margin: 0;\n padding: 0;\n\n}\n\n\n\n/**\n * Basic styling\n */\nbody {\n font: $base-font-weight #{$base-font-size}/#{$base-line-height} $base-font-family;\n color: $text-color;\n background-color: $background-color;\n -webkit-text-size-adjust: 100%;\n -webkit-font-feature-settings: \"kern\" 1;\n -moz-font-feature-settings: \"kern\" 1;\n -o-font-feature-settings: \"kern\" 1;\n font-feature-settings: \"kern\" 1;\n font-kerning: normal;\n display: flex;\n min-height: 100vh;\n flex-direction: column;\n overflow-wrap: break-word;\n}\n\n\n\n/**\n * Set `margin-bottom` to maintain vertical rhythm\n */\nh1, h2, h3, h4, h5, h6,\np, blockquote, pre,\nul, ol, dl, figure,\n%vertical-rhythm {\n margin-bottom: $spacing-unit * .5;\n}\n\nhr {\n margin-top: $spacing-unit;\n margin-bottom: $spacing-unit;\n}\n\n/**\n * `main` element\n */\nmain {\n display: block; /* Default value of `display` of `main` element is 'inline' in IE 11. */\n}\n\n\n\n/**\n * Images\n */\nimg {\n max-width: 100%;\n vertical-align: middle;\n}\n\n\n\n/**\n * Figures\n */\nfigure > img {\n display: block;\n}\n\nfigcaption {\n font-size: $small-font-size;\n}\n\n\n\n/**\n * Lists\n */\nul, ol {\n margin-left: $spacing-unit;\n}\n\nli {\n > ul,\n > ol {\n margin-bottom: 0;\n }\n}\n\n\n\n/**\n * Headings\n */\nh1, h2, h3, h4, h5, h6 {\n font-weight: $base-font-weight;\n}\n\n\n\n/**\n * Links\n */\na {\n color: $link-base-color;\n text-decoration: none;\n\n &:visited {\n color: $link-visited-color;\n }\n\n &:hover {\n color: $link-hover-color;\n text-decoration: underline;\n }\n\n .social-media-list &:hover {\n text-decoration: none;\n\n .username {\n text-decoration: underline;\n }\n }\n}\n\n\n/**\n * Blockquotes\n */\nblockquote {\n color: $brand-color;\n border-left: 4px solid $border-color-01;\n padding-left: $spacing-unit * .5;\n @include relative-font-size(1.125);\n font-style: italic;\n\n > :last-child {\n margin-bottom: 0;\n }\n\n i, em {\n font-style: normal;\n }\n}\n\n\n\n/**\n * Code formatting\n */\npre,\ncode {\n font-family: $code-font-family;\n font-size: 0.9375em;\n border: 1px solid $border-color-01;\n border-radius: 3px;\n background-color: $code-background-color;\n}\n\ncode {\n padding: 1px 5px;\n}\n\npre {\n padding: 8px 12px;\n overflow-x: auto;\n\n > code {\n border: 0;\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n.highlight {\n border-radius: 3px;\n background: $code-background-color;\n @extend %vertical-rhythm;\n\n .highlighter-rouge & {\n background: $code-background-color;\n }\n}\n\n\n\n/**\n * Wrapper\n */\n.wrapper {\n max-width: calc(#{$content-width} - (#{$spacing-unit}));\n margin-right: auto;\n margin-left: auto;\n padding-right: $spacing-unit * .5;\n padding-left: $spacing-unit * .5;\n @extend %clearfix;\n\n @media screen and (min-width: $on-large) {\n max-width: calc(#{$content-width} - (#{$spacing-unit} * 2));\n padding-right: $spacing-unit;\n padding-left: $spacing-unit;\n }\n}\n\n\n\n/**\n * Clearfix\n */\n%clearfix:after {\n content: \"\";\n display: table;\n clear: both;\n}\n\n\n\n/**\n * Icons\n */\n\n.orange {\n color: #f66a0a;\n}\n\n.grey {\n color: #828282;\n}\n\n.svg-icon {\n width: 1.25em;\n height: 1.25em;\n display: inline-block;\n fill: currentColor;\n vertical-align: text-bottom;\n}\n\n\n/**\n * Tables\n */\ntable {\n margin-bottom: $spacing-unit;\n width: 100%;\n text-align: $table-text-align;\n color: $table-text-color;\n border-collapse: collapse;\n border: 1px solid $table-border-color;\n tr {\n &:nth-child(even) {\n background-color: $table-zebra-color;\n }\n }\n th, td {\n padding: ($spacing-unit * 33.3333333333 * .01) ($spacing-unit * .5);\n }\n th {\n background-color: $table-header-bg-color;\n border: 1px solid $table-header-border;\n }\n td {\n border: 1px solid $table-border-color;\n }\n\n @include media-query($on-laptop) {\n display: block;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n }\n}\n","@charset \"utf-8\";\n\n// Define defaults for each variable.\n\n$base-font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Apple Color Emoji\", Roboto, Helvetica, Arial, sans-serif !default;\n$code-font-family: \"Menlo\", \"Inconsolata\", \"Consolas\", \"Roboto Mono\", \"Ubuntu Mono\", \"Liberation Mono\", \"Courier New\", monospace;\n$base-font-size: 16px !default;\n$base-font-weight: 400 !default;\n$small-font-size: $base-font-size * 0.875 !default;\n$base-line-height: 1.5 !default;\n\n$spacing-unit: 30px !default;\n\n$table-text-align: left !default;\n\n// Width of the content area\n$content-width: 800px !default;\n\n$on-palm: 600px !default;\n$on-laptop: 800px !default;\n\n$on-medium: $on-palm !default;\n$on-large: $on-laptop !default;\n\n// Use media queries like this:\n// @include media-query($on-palm) {\n// .wrapper {\n// padding-right: $spacing-unit / 2;\n// padding-left: $spacing-unit / 2;\n// }\n// }\n// Notice the following mixin uses max-width, in a deprecated, desktop-first\n// approach, whereas media queries used elsewhere now use min-width.\n@mixin media-query($device) {\n @media screen and (max-width: $device) {\n @content;\n }\n}\n\n@mixin relative-font-size($ratio) {\n font-size: #{$ratio}rem;\n}\n\n// Import pre-styling-overrides hook and style-partials.\n@import\n \"minima/custom-variables\", // Hook to override predefined variables.\n \"minima/base\", // Defines element resets.\n \"minima/layout\", // Defines structure and style based on CSS selectors.\n \"minima/custom-styles\" // Hook to override existing styles.\n;\n","/**\n * Site header\n */\n.site-header {\n border-top: 5px solid $border-color-03;\n border-bottom: 1px solid $border-color-01;\n min-height: $spacing-unit * 1.865;\n line-height: $base-line-height * $base-font-size * 2.25;\n\n // Positioning context for the mobile navigation icon\n position: relative;\n}\n\n.site-title {\n @include relative-font-size(1.625);\n font-weight: 300;\n letter-spacing: -1px;\n margin-bottom: 0;\n float: left;\n\n @include media-query($on-palm) {\n padding-right: 45px;\n }\n\n &,\n &:visited {\n color: $site-title-color;\n }\n}\n\n.site-nav {\n position: absolute;\n top: 9px;\n right: $spacing-unit * .5;\n background-color: $background-color;\n border: 1px solid $border-color-01;\n border-radius: 5px;\n text-align: right;\n\n .nav-trigger {\n display: none;\n }\n\n .menu-icon {\n float: right;\n width: 36px;\n height: 26px;\n line-height: 0;\n padding-top: 10px;\n text-align: center;\n\n > svg path {\n fill: $border-color-03;\n }\n }\n\n label[for=\"nav-trigger\"] {\n display: block;\n float: right;\n width: 36px;\n height: 36px;\n z-index: 2;\n cursor: pointer;\n }\n\n input ~ .trigger {\n clear: both;\n display: none;\n }\n\n input:checked ~ .trigger {\n display: block;\n padding-bottom: 5px;\n }\n\n .page-link {\n color: $text-color;\n line-height: $base-line-height;\n display: block;\n padding: 5px 10px;\n\n // Gaps between nav items, but not on the last one\n &:not(:last-child) {\n margin-right: 0;\n }\n margin-left: 20px;\n }\n\n @media screen and (min-width: $on-medium) {\n position: static;\n float: right;\n border: none;\n background-color: inherit;\n\n label[for=\"nav-trigger\"] {\n display: none;\n }\n\n .menu-icon {\n display: none;\n }\n\n input ~ .trigger {\n display: block;\n }\n\n .page-link {\n display: inline;\n padding: 0;\n\n &:not(:last-child) {\n margin-right: 20px;\n }\n margin-left: auto;\n }\n }\n}\n\n\n\n/**\n * Site footer\n */\n.site-footer {\n border-top: 1px solid $border-color-01;\n padding: $spacing-unit 0;\n}\n\n.footer-heading {\n @include relative-font-size(1.125);\n margin-bottom: $spacing-unit * .5;\n}\n\n.feed-subscribe .svg-icon {\n padding: 5px 5px 2px 0\n}\n\n.contact-list,\n.social-media-list {\n list-style: none;\n margin-left: 0;\n}\n\n.footer-col-wrapper,\n.social-links {\n @include relative-font-size(0.9375);\n color: $brand-color;\n}\n\n.footer-col {\n margin-bottom: $spacing-unit * .5;\n}\n\n.footer-col-1,\n.footer-col-2 {\n width: calc(50% - (#{$spacing-unit} / 2));\n}\n\n.footer-col-3 {\n width: calc(100% - (#{$spacing-unit} / 2));\n}\n\n@media screen and (min-width: $on-large) {\n .footer-col-1 {\n width: calc(35% - (#{$spacing-unit} / 2));\n }\n\n .footer-col-2 {\n width: calc(20% - (#{$spacing-unit} / 2));\n }\n\n .footer-col-3 {\n width: calc(45% - (#{$spacing-unit} / 2));\n }\n}\n\n@media screen and (min-width: $on-medium) {\n .footer-col-wrapper {\n display: flex\n }\n\n .footer-col {\n width: calc(100% - (#{$spacing-unit} / 2));\n padding: 0 ($spacing-unit * .5);\n\n &:first-child {\n padding-right: $spacing-unit * .5;\n padding-left: 0;\n }\n\n &:last-child {\n padding-right: 0;\n padding-left: $spacing-unit * .5;\n }\n }\n}\n\n\n\n/**\n * Page content\n */\n.page-content {\n padding: $spacing-unit 0;\n flex: 1 0 auto;\n}\n\n.page-heading {\n @include relative-font-size(2);\n}\n\n.post-list-heading {\n @include relative-font-size(1.75);\n}\n\n.post-list {\n margin-left: 0;\n list-style: none;\n\n > li {\n margin-bottom: $spacing-unit;\n }\n}\n\n.post-meta {\n font-size: $small-font-size;\n color: $brand-color;\n}\n\n.post-link {\n display: block;\n @include relative-font-size(1.5);\n}\n\n\n\n/**\n * Posts\n */\n.post-header {\n margin-bottom: $spacing-unit;\n}\n\n.post-title,\n.post-content h1 {\n @include relative-font-size(2.625);\n letter-spacing: -1px;\n line-height: 1.15;\n\n @media screen and (min-width: $on-large) {\n @include relative-font-size(2.625);\n }\n}\n\n.post-content {\n margin-bottom: $spacing-unit;\n\n h1, h2, h3, h4, h5, h6 { margin-top: $spacing-unit }\n\n h2 {\n @include relative-font-size(1.75);\n\n @media screen and (min-width: $on-large) {\n @include relative-font-size(2);\n }\n }\n\n h3 {\n @include relative-font-size(1.375);\n\n @media screen and (min-width: $on-large) {\n @include relative-font-size(1.625);\n }\n }\n\n h4 {\n @include relative-font-size(1.25);\n }\n\n h5 {\n @include relative-font-size(1.125);\n }\n h6 {\n @include relative-font-size(1.0625);\n }\n}\n\n\n.social-media-list {\n display: table;\n margin: 0 auto;\n li {\n float: left;\n margin: 5px 10px 5px 0;\n &:last-of-type { margin-right: 0 }\n a {\n display: block;\n padding: 10px 12px;\n border: 1px solid $border-color-01;\n &:hover { border-color: $border-color-02 }\n }\n }\n}\n\n\n\n/**\n * Pagination navbar\n */\n.pagination {\n margin-bottom: $spacing-unit;\n @extend .social-media-list;\n li {\n a, div {\n min-width: 41px;\n text-align: center;\n box-sizing: border-box;\n }\n div {\n display: block;\n padding: $spacing-unit * .25;\n border: 1px solid transparent;\n\n &.pager-edge {\n color: $border-color-01;\n border: 1px dashed;\n }\n }\n }\n}\n\n\n\n/**\n * Grid helpers\n */\n@media screen and (min-width: $on-large) {\n .one-half {\n width: calc(50% - (#{$spacing-unit} / 2));\n }\n}\n"],"file":"style.css"} \ No newline at end of file diff --git a/docs/blog/assets/minima-social-icons.svg b/docs/blog/assets/minima-social-icons.svg new file mode 100644 index 0000000..492f5ff --- /dev/null +++ b/docs/blog/assets/minima-social-icons.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/docs/blog/feed.xml b/docs/blog/feed.xml new file mode 100644 index 0000000..96b5d34 --- /dev/null +++ b/docs/blog/feed.xml @@ -0,0 +1,493 @@ +Jekyll2023-11-22T23:55:31+02:00/blog/feed.xmlAlgorithm BlogA collection of classic algorithms, written in OCaml.Liang Wangliang@ocaml.xyzInsertion Sort2023-11-20T23:15:00+02:002023-11-20T23:15:00+02:00/blog/algorithm/2023/11/20/insertion-sortIntroduction +

Insertion sort is a simple sorting algorithm that is widely used in computer science. It works by taking one element from the unsorted list and inserting it into the correct position in the sorted list. The algorithm is efficient for small data sets but becomes inefficient for larger ones. Insertion sort can be used in situations where the data is already partially sorted or where the cost of swapping elements is high.

+ +

Implementation

+

Here is an implementation of insertion sort in OCaml:

+ +
let rec insertion_sort = function  
+  | [] -> []  
+  | x :: xs -> insert x (insertion_sort xs)  
+and insert x = function  
+  | [] -> [x]  
+  | y :: ys -> if x < y then x :: y :: ys else y :: insert x ys  
+
+ +

This implementation uses a recursive function to sort the list. The insertion_sort function takes a list as input and returns a sorted list. The insert function takes an element x and a sorted list as input and returns a new sorted list with x inserted in the correct position.

+ +

Step-by-step Explanation

+
    +
  1. The insertion_sort function is called with a list as input.
  2. +
  3. If the list is empty, an empty list is returned.
  4. +
  5. Otherwise, the first element x is removed from the list and the insert function is called with x and the sorted list returned by a recursive call to insertion_sort.
  6. +
  7. The insert function takes x and a sorted list as input.
  8. +
  9. If the list is empty, a list with x as the only element is returned.
  10. +
  11. Otherwise, the first element y is removed from the list and the insert function is called recursively with x and the remaining list ys.
  12. +
  13. If x is less than y, a new list with x and y followed by ys is returned.
  14. +
  15. Otherwise, a new list with y followed by the result of calling insert with x and ys is returned.
  16. +
  17. The sorted list returned by insert is returned by insertion_sort.
  18. +
+ +

Complexity Analysis

+

The time complexity of insertion sort is O(n^2) in the worst case, where n is the number of elements in the list. This is because each element must be compared to every other element in the list, resulting in n^2 comparisons. However, in the best case (when the list is already sorted), the time complexity is O(n) because each element only needs to be compared to the previous element. The space complexity of insertion sort is O(1) because the algorithm sorts the list in place without using any additional memory.

]]>
Liang Wangliang@ocaml.xyz
Radix Sort2023-11-20T23:15:00+02:002023-11-20T23:15:00+02:00/blog/algorithm/2023/11/20/radix-sortIntroduction +

Radix sort is a sorting algorithm that sorts elements by grouping them based on their digits or bits. It is a non-comparative integer sorting algorithm that sorts data with integer keys by grouping the keys by individual digits that share the same significant position and value. Radix sort is often used for sorting large numbers of records, such as in big data applications.

+ +

Implementation

+

Here is an implementation of radix sort in OCaml:

+ +
let radix_sort arr =  
+  let rec loop arr exp =  
+    if exp < 0 then arr else  
+      let zeroes, ones = List.partition (fun x -> x land (1 lsl exp) = 0) arr in  
+      loop zeroes (exp - 1) @ loop ones (exp - 1)  
+  in  
+  loop arr (List.fold_left (fun m x -> max m (int_of_float (log10 (float_of_int x)))) 0 arr)  
+
+ +

Here, radix_sort takes in an array of integers arr and returns a sorted array. The loop function recursively sorts the array by partitioning it into two subarrays based on the value of the exp-th bit (starting from the most significant bit). The exp parameter is initially set to the maximum number of digits in any element of the array. The function log10 is used to calculate the number of digits in each element.

+ +

Step-by-step Explanation

+
    +
  1. Find the maximum number of digits in any element of the array.
  2. +
  3. For each bit position starting from the most significant bit, partition the array into two subarrays based on the value of that bit.
  4. +
  5. Recursively sort each subarray by repeating step 2 with the next bit position.
  6. +
  7. Concatenate the sorted subarrays to get the final sorted array.
  8. +
+ +

For example, let’s say we have the following array:

+ +
[170, 45, 75, 90, 802, 24, 2, 66]  
+
+ +

The maximum number of digits is 3, so we start by partitioning the array based on the third bit:

+ +
[170, 90, 802, 2, 24, 45, 75, 66]  
+
+ +

We then recursively sort each subarray by partitioning based on the second bit:

+ +
[802, 2, 24, 45, 66, 170, 75, 90]  
+
+ +
[2, 24, 45, 66, 75, 90, 170, 802]  
+
+ +

Finally, we concatenate the sorted subarrays to get the final sorted array:

+ +
[2, 24, 45, 66, 75, 90, 170, 802]  
+
+ +

Complexity Analysis

+

The time complexity of radix sort is O(d * (n + k)), where d is the maximum number of digits in any element of the array, n is the number of elements in the array, and k is the range of values (i.e., the maximum value minus the minimum value). The space complexity is O(n + k).

+ +

In the worst case, when d is very large, radix sort can be slower than comparison-based sorting algorithms like quicksort or mergesort. However, radix sort has the advantage of being able to sort large integers and other non-comparable data types that cannot be easily sorted using comparison-based algorithms.

]]>
Liang Wangliang@ocaml.xyz
Merge Sort2023-11-20T23:01:00+02:002023-11-20T23:01:00+02:00/blog/algorithm/2023/11/20/mergesortIntroduction + +

Merge sort is a divide-and-conquer algorithm that sorts an array or list of elements by recursively dividing it into two halves, sorting each half, and then merging the sorted halves back together. It is a highly efficient sorting algorithm with a time complexity of O(n log n), making it suitable for large datasets. Merge sort is widely used in various applications, including sorting large databases, numerical analysis, and parallel computing.

+ +

Implementation

+ +

Here is an implementation of merge sort in OCaml:

+ +
let rec merge_sort = function  
+  | [] -> []  
+  | [x] -> [x]  
+  | xs ->  
+      let rec split left right = function  
+        | [] -> (left, right)  
+        | x :: xs -> split right (x :: left) xs  
+      in  
+      let rec merge left right = match left, right with  
+        | [], _ -> right  
+        | _, [] -> left  
+        | x :: xs, y :: ys ->  
+            if x < y then x :: merge xs right  
+            else y :: merge left ys  
+      in  
+      let left, right = split [] [] xs in  
+      merge (merge_sort left) (merge_sort right)  
+
+ +

Here is an example of using this implementation to sort a list of integers:

+ +
let sorted_list = merge_sort [4; 2; 7; 1; 3; 6; 5];;  
+
+ +

The resulting sorted_list will be [1; 2; 3; 4; 5; 6; 7].

+ +

Step-by-step Explanation

+ +
    +
  1. The merge_sort function takes a list of elements as input.
  2. +
  3. If the list is empty or contains only one element, it is already sorted, so the function returns the list as is.
  4. +
  5. Otherwise, the function recursively divides the list into two halves using the split function.
  6. +
  7. The split function takes two empty lists (left and right) and the original list as input.
  8. +
  9. If the original list is empty, the function returns the two half lists.
  10. +
  11. Otherwise, the function takes the first element of the original list and adds it to the right list, while the rest of the list is recursively split with the right list becoming the new left list.
  12. +
  13. The merge function takes two sorted lists (left and right) as input and returns a single sorted list.
  14. +
  15. If one of the input lists is empty, the function returns the other list as is.
  16. +
  17. Otherwise, the function compares the first elements of the two lists and adds the smaller one to the output list.
  18. +
  19. The function then recursively calls itself with the remaining elements of the input lists until both input lists are empty.
  20. +
  21. Finally, the merge_sort function merges the two sorted halves of the original list using the merge function.
  22. +
+ +

Complexity Analysis

+ +

The time complexity of merge sort is O(n log n), where n is the number of elements in the input list. This is because the algorithm recursively divides the input list into halves until each half contains only one element, which takes O(log n) time. Then, the algorithm merges the sorted halves back together, which takes O(n) time. Therefore, the total time complexity is O(n log n).

+ +

The space complexity of merge sort is O(n), where n is the number of elements in the input list. This is because the algorithm creates temporary lists to store the halves of the input list during the merge process. However, these temporary lists are deallocated after each recursive call, so the overall space complexity is O(n).

]]>
Liang Wangliang@ocaml.xyz
Heapsort2023-11-20T22:04:00+02:002023-11-20T22:04:00+02:00/blog/algorithm/2023/11/20/heapsortIntroduction +

Heapsort is a comparison-based sorting algorithm that uses a binary heap data structure. It was first proposed by J. W. J. Williams in 1964. Heapsort is an in-place algorithm, meaning that it sorts the array in place, without needing any additional memory. It has a time complexity of O(n log n), which makes it efficient for large data sets.

+ +

Implementation

+

Here is an implementation of heapsort in OCaml:

+ +
let swap arr i j =  
+  let temp = arr.(i) in  
+  arr.(i) <- arr.(j);  
+  arr.(j) <- temp  
+   
+let rec heapify arr n i =  
+  let largest = ref i in  
+  let left = 2 * i + 1 in  
+  let right = 2 * i + 2 in  
+  if left < n && arr.(left) > arr.(!largest) then  
+    largest := left;  
+  if right < n && arr.(right) > arr.(!largest) then  
+    largest := right;  
+  if !largest <> i then (  
+    swap arr i !largest;  
+    heapify arr n !largest  
+  )  
+   
+let heapsort arr =  
+  let n = Array.length arr in  
+  for i = n / 2 - 1 downto 0 do  
+    heapify arr n i  
+  done;  
+  for i = n - 1 downto 1 do  
+    swap arr 0 i;  
+    heapify arr i 0  
+  done  
+
+ +

Here is an example of how to use the heapsort function:

+ +
let arr = [|4; 2; 7; 1; 3|] in  
+heapsort arr;  
+Array.iter (Printf.printf "%d ") arr  
+
+ +

Output:

+
1 2 3 4 7  
+
+ +

Step-by-step Explanation

+
    +
  1. Build a max heap from the input data. A binary heap is a complete binary tree where each node is greater than or equal to its children. The largest element is stored at the root of the heap.
  2. +
  3. Swap the root node with the last element in the array. Decrease the heap size by 1.
  4. +
  5. Call heapify on the root node to restore the heap property.
  6. +
  7. Repeat steps 2-3 until the heap size is 1.
  8. +
+ +

The heapify function takes three arguments: the array to be sorted, the size of the heap, and the index of the current node. It compares the current node with its left and right children and swaps it with the largest child if necessary. It then recursively calls heapify on the largest child to ensure that the subtree rooted at the current node is also a heap.

+ +

Complexity Analysis

+

The time complexity of heapsort is O(n log n) in the worst case. Building the heap takes O(n) time, and each call to heapify takes O(log n) time. We call heapify n-1 times in the second loop, so the total time complexity is O(n log n).

+ +

Heapsort is an in-place sorting algorithm, so it requires no additional memory beyond the array to be sorted. However, it is not a stable sorting algorithm, meaning that it does not preserve the relative order of equal elements in the input array.

]]>
Liang Wangliang@ocaml.xyz
Quicksort2023-11-20T20:46:37+02:002023-11-20T20:46:37+02:00/blog/algorithm/2023/11/20/quicksortIntroduction + +

Quicksort was developed by British computer scientist Tony Hoare in 1959. It is one of the most widely used sorting algorithms and is commonly used in computer science and engineering applications.

+ +

Quicksort is particularly useful when sorting large datasets because it has an average time complexity of O(n log n), which is faster than many other sorting algorithms. It is also an in-place sorting algorithm, meaning that it does not require any additional memory beyond the input array.

+ +

Quicksort is used in a variety of applications, including sorting large databases, sorting elements in computer graphics and image processing, and in network routing algorithms. It is also used in many programming languages as a built-in sorting function, such as Python’s sorted() function and C++’s std::sort() function.

+ +

Implementation

+ +
let rec quicksort = function  
+  | [] -> []  
+  | pivot::tail ->  
+    let lesser, greater = List.partition (fun x -> x < pivot) tail in  
+    quicksort lesser @ [pivot] @ quicksort greater  
+
+ +

This implementation uses a functional programming style and takes advantage of pattern matching to handle the two cases of the input list: the empty list, which is already sorted, and a non-empty list, which is partitioned into two sub-lists based on a pivot element (in this case, the first element of the list).

+ +

The List.partition function is used to split the tail of the input list into two sub-lists: lesser, which contains all elements that are strictly less than the pivot, and greater, which contains all elements that are greater than or equal to the pivot. The @ operator is used to concatenate the sorted lesser sub-list, the pivot element, and the sorted greater sub-list into a single sorted list.

+ +

Here’s an example usage of the quicksort function:

+ +
let unsorted = [5; 1; 3; 9; 2]  
+let sorted = quicksort unsorted  
+
+ +

After running this code, the sorted variable should contain the list [1; 2; 3; 5; 9], which is the sorted version of the unsorted list.

+ +

Step-by-step Explanation

+ +

Here’s a step-by-step explanation of how the quicksort algorithm works:

+ +
    +
  1. +

    Choose a pivot element from the list. This can be any element, but a common choice is the first or last element in the list.

    +
  2. +
  3. +

    Partition the list into two sub-lists, with one sub-list containing elements less than the pivot and the other sub-list containing elements greater than or equal to the pivot. This can be done by iterating through the list and swapping elements as necessary to ensure that all elements less than the pivot are on one side of the pivot and all elements greater than or equal to the pivot are on the other side.

    +
  4. +
  5. +

    Recursively apply steps 1 and 2 to the sub-lists until the entire list is sorted. This can be done by calling the quicksort function on each sub-list.

    +
  6. +
+ +

Here’s an example of how this algorithm would sort the list [5; 1; 3; 9; 2]:

+ +
    +
  1. +

    Choose the first element, 5, as the pivot.

    +
  2. +
  3. +

    Partition the list into two sub-lists: [1; 3; 2] and [9]. All elements less than 5 are on the left and all elements greater than or equal to 5 are on the right.

    +
  4. +
  5. +

    Recursively apply steps 1 and 2 to each sub-list. For the left sub-list, choose 1 as the pivot and partition it into [ ], [1], and [3; 2]. For the right sub-list, it is already sorted.

    +
  6. +
  7. +

    Recursively apply steps 1 and 2 to the sub-lists [1] and [3; 2]. Both sub-lists are already sorted, so no further partitioning is necessary.

    +
  8. +
  9. +

    Concatenate the sorted sub-lists in the order [1], [2; 3], [5], and [9] to obtain the sorted list [1; 2; 3; 5; 9].

    +
  10. +
+ +

This example shows how the quicksort algorithm works by recursively dividing the input list into smaller sub-lists, sorting them, and then combining them to obtain the final sorted list.

+ +

Complexity

+ +

The time complexity of quicksort is O(n log n) on average, where n is the number of elements in the input list.

+ +

The average case occurs when the pivot element is chosen randomly and is close to the median value of the list. In this case, the list is divided roughly in half with each partition, and the algorithm will make log n recursive calls to sort the entire list. The partitioning step takes linear time, so the total time complexity is O(n log n).

+ +

However, in the worst case, quicksort can have a time complexity of O(n^2) if the pivot element is consistently chosen poorly. For example, if the pivot is always chosen as the smallest or largest element in the list, then each partition will only remove one element from the list, and the algorithm will make n recursive calls to sort the entire list. This worst-case scenario is rare in practice, but it can occur in certain edge cases.

+ +

In terms of space complexity, quicksort is an in-place sorting algorithm, meaning that it does not require any additional memory beyond the input list. However, the recursive nature of the algorithm means that it has a space complexity of O(log n) due to the call stack used for the recursive calls.

+ +

Overall, quicksort is a highly efficient sorting algorithm with a time complexity of O(n log n) on average, making it a popular choice for sorting large datasets.

]]>
Liang Wangliang@ocaml.xyz
Selection Sort2023-11-10T23:00:00+02:002023-11-10T23:00:00+02:00/blog/algorithm/2023/11/10/shell-sortIntroduction +

Shell sort is an efficient sorting algorithm that is a variation of insertion sort. It was invented by Donald Shell in 1959. The algorithm works by sorting elements that are far apart from each other and then gradually reducing the gap between them. This makes the algorithm faster than insertion sort for larger lists.

+ +

Implementation

+

Here is an implementation of Shell sort in OCaml:

+ +
let shell_sort arr =  
+  let n = Array.length arr in  
+  let gap = ref (n / 2) in  
+  while !gap > 0 do  
+    for i = !gap to n - 1 do  
+      let temp = arr.(i) in  
+      let j = ref i in  
+      while !j >= !gap && arr.(!j - !gap) > temp do  
+        arr.(!j) <- arr.(!j - !gap);  
+        j := !j - !gap  
+      done;  
+      arr.(!j) <- temp  
+    done;  
+    gap := !gap / 2  
+  done;  
+  arr  
+
+ +

To use this function, simply pass in an array of elements to sort:

+ +
let arr = [| 5; 3; 8; 4; 2 |]  
+let sorted_arr = shell_sort arr  
+
+ +

The sorted_arr variable will contain the sorted array.

+ +

Step-by-step Explanation

+
    +
  1. Start by dividing the list into sublists of equal intervals. The interval is called the gap.
  2. +
  3. Sort each sublist using insertion sort.
  4. +
  5. Reduce the gap by half and repeat step 2 until the gap is 1.
  6. +
+ +

For example, let’s say we have the following list of integers: [5, 3, 8, 4, 2]. We’ll use a gap of 2 for the first pass.

+ +
    +
  1. Divide the list into sublists with a gap of 2: [5, 8, 2] and [3, 4].
  2. +
  3. Sort each sublist using insertion sort. The first sublist becomes [2, 5, 8] and the second sublist stays the same: [3, 4].
  4. +
  5. Reduce the gap to 1 and sort the entire list using insertion sort. The sorted list is [2, 3, 4, 5, 8].
  6. +
+ +

Complexity Analysis

+

The time complexity of Shell sort depends on the gap sequence used. The worst-case time complexity is O(n^2), which occurs when the gap sequence is 1, making the algorithm equivalent to insertion sort. However, the average-case time complexity is O(n log n), which is faster than insertion sort for larger lists.

+ +

The space complexity of Shell sort is O(1) because it sorts the list in place.

]]>
Liang Wangliang@ocaml.xyz
Counting Sort2023-11-10T20:00:00+02:002023-11-10T20:00:00+02:00/blog/algorithm/2023/11/10/counting-sortIntroduction +

Counting sort is an efficient sorting algorithm that can be used to sort elements in a range of integers. It is a non-comparison based sorting algorithm that works by counting the number of occurrences of each element in the array and then using this information to determine the position of each element in the sorted output array.

+ +

Implementation

+

Here is an implementation of counting sort in OCaml:

+ +
let counting_sort arr =  
+  let max_val = Array.fold_left max arr 0 in  
+  let count_arr = Array.make (max_val + 1) 0 in  
+  Array.iter (fun x -> count_arr.(x) <- count_arr.(x) + 1) arr;  
+  let index_arr = Array.make (max_val + 1) 0 in  
+  let rec fill_index_arr i j =  
+    if i <= max_val then  
+      begin  
+        index_arr.(i) <- j;  
+        fill_index_arr (i + 1) (j + count_arr.(i))  
+      end  
+  in  
+  fill_index_arr 0 0;  
+  let sorted_arr = Array.make (Array.length arr) 0 in  
+  Array.iter (fun x -> sorted_arr.(index_arr.(x)) <- x; index_arr.(x) <- index_arr.(x) + 1) arr;  
+  sorted_arr  
+
+ +

Here, arr is the input array to be sorted. The function counting_sort first finds the maximum value in the input array and creates a new array count_arr to count the number of occurrences of each element in the input array. It then creates another array index_arr to store the index of each element in the sorted output array. The function fill_index_arr is a helper function that fills in the index_arr array based on the counts in count_arr. Finally, the function creates a new array sorted_arr and fills it in by iterating over the input array and using the index_arr array to determine the position of each element in the sorted output array.

+ +

Step-by-step Explanation

+
    +
  1. Find the maximum value in the input array.
  2. +
  3. Create a new array count_arr of length max_val + 1 and initialize all elements to 0.
  4. +
  5. Iterate over the input array and increment the count of each element in count_arr.
  6. +
  7. Create a new array index_arr of length max_val + 1 and initialize all elements to 0.
  8. +
  9. Define a helper function fill_index_arr that fills in the index_arr array based on the counts in count_arr. The function takes two arguments: i and j, where i is the current index in count_arr and j is the current index in index_arr.
  10. +
  11. Call the fill_index_arr function with initial arguments 0 and 0.
  12. +
  13. Create a new array sorted_arr of length n, where n is the length of the input array.
  14. +
  15. Iterate over the input array and use the index_arr array to determine the position of each element in the sorted output array. Store each element in the corresponding position in sorted_arr.
  16. +
  17. Return sorted_arr.
  18. +
+ +

Complexity Analysis

+

The time complexity of counting sort is O(n + k), where n is the length of the input array and k is the range of the input integers. The space complexity is also O(n + k).

+ +

The algorithm iterates over the input array twice: once to count the occurrences of each element and once to fill in the sorted output array. The time complexity of these two iterations is O(n). The algorithm also creates two additional arrays: count_arr and index_arr, each of length k. Therefore, the space complexity of the algorithm is O(n + k).

]]>
Liang Wangliang@ocaml.xyz
Selection Sort2023-11-10T19:00:00+02:002023-11-10T19:00:00+02:00/blog/algorithm/2023/11/10/selection-sortIntroduction +

Selection sort is a simple sorting algorithm that works by repeatedly finding the minimum element from an unsorted list and putting it at the beginning. The algorithm is not very efficient for large lists, but it has the advantage of being simple to understand and implement.

+ +

Implementation

+

Here is an implementation of selection sort in OCaml:

+ +
let rec find_min i arr =  
+  if i = Array.length arr then -1  
+  else  
+    let min_idx = find_min (i+1) arr in  
+    if min_idx = -1 || arr.(i) < arr.(min_idx) then i else min_idx  
+   
+let selection_sort arr =  
+  for i = 0 to Array.length arr - 1 do  
+    let min_idx = find_min i arr in  
+    let tmp = arr.(i) in  
+    arr.(i) <- arr.(min_idx);  
+    arr.(min_idx) <- tmp  
+  done  
+
+ +

Here, find_min is a helper function that finds the index of the minimum element in the array arr starting from index i. It returns -1 if i is already at the end of the array. selection_sort uses find_min to find the minimum element in the unsorted portion of the array and swaps it with the first element in the unsorted portion. This process is repeated until the entire array is sorted.

+ +

Here is an example of using selection_sort:

+ +
let arr = [|5; 2; 9; 3; 6|]  
+selection_sort arr  
+(* arr is now [|2; 3; 5; 6; 9|] *)  
+
+ +

Step-by-step Explanation

+
    +
  1. We start with an unsorted array arr.
  2. +
  3. We iterate over the array from index 0 to n-1, where n is the length of the array.
  4. +
  5. For each iteration, we call find_min to find the index of the minimum element in the unsorted portion of the array starting from index i.
  6. +
  7. We swap the element at index i with the minimum element found in step 3.
  8. +
  9. We repeat steps 3-4 until the entire array is sorted.
  10. +
+ +

Complexity Analysis

+

The time complexity of selection sort is O(n^2), where n is the length of the array. This is because we have to iterate over the entire array n times, and for each iteration, we have to find the minimum element in the unsorted portion of the array, which takes O(n) time. The space complexity of selection sort is O(1), because we only need to store a few variables to keep track of the indices and the temporary value during the swapping process.

+ +

Selection sort is not very efficient for large arrays, but it has the advantage of being simple to implement and understand. It can also be useful in situations where memory is limited, since it only requires a constant amount of extra memory.

]]>
Liang Wangliang@ocaml.xyz
Bubble Sort2023-11-10T18:00:00+02:002023-11-10T18:00:00+02:00/blog/algorithm/2023/11/10/bubble-sortIntroduction +

Bubble Sort is a simple sorting algorithm that repeatedly swaps adjacent elements if they are in the wrong order. It is named as bubble sort because the smaller elements bubble up to the top of the list as the algorithm iterates through the list. Bubble Sort is not an efficient algorithm for large lists and is generally used for educational purposes.

+ +

Implementation

+

Here is an implementation of Bubble Sort in OCaml:

+ +
let bubble_sort arr =  
+  let n = Array.length arr in  
+  for i = 0 to n - 2 do  
+    for j = 0 to n - i - 2 do  
+      if arr.(j) > arr.(j+1) then  
+        let temp = arr.(j) in  
+        arr.(j) <- arr.(j+1);  
+        arr.(j+1) <- temp  
+    done  
+  done;;  
+
+ +

Here, arr is the array to be sorted. The function bubble_sort uses two nested loops to iterate through the array and compare adjacent elements. If the elements are in the wrong order, they are swapped. The outer loop iterates from 0 to n-2, while the inner loop iterates from 0 to n-i-2. This is because the largest element in the list will already be in its correct position after each iteration of the outer loop.

+ +

Step-by-step Explanation

+
    +
  1. Start with an unsorted array of n elements.
  2. +
  3. Compare the first two elements. If the first element is greater than the second element, swap them.
  4. +
  5. Move to the next pair of adjacent elements and repeat step 2 until the end of the array is reached.
  6. +
  7. Repeat steps 2 and 3 for each pair of adjacent elements until the end of the array is reached.
  8. +
  9. After each iteration, the largest element will be in its correct position at the end of the array.
  10. +
  11. Repeat steps 2-5 n-1 times to sort the entire array.
  12. +
+ +

Complexity Analysis

+

The time complexity of Bubble Sort is O(n^2), where n is the number of elements in the array. This is because the algorithm uses two nested loops to iterate through the array and compare adjacent elements. In the worst case scenario, where the array is in reverse order, the algorithm will need to make n*(n-1)/2 comparisons and swaps. The space complexity of Bubble Sort is O(1), as the algorithm only requires a constant amount of additional memory to store temporary variables for swapping elements.

]]>
Liang Wangliang@ocaml.xyz
Bucket Sort2023-11-10T11:00:00+02:002023-11-10T11:00:00+02:00/blog/algorithm/2023/11/10/bucket-sortIntroduction +

Bucket sort is a sorting algorithm that works by distributing the elements of an array into a number of buckets. Each bucket is then sorted individually, either using a different sorting algorithm or by recursively applying the bucket sorting algorithm. Bucket sort is useful when the input is uniformly distributed over a range. It is commonly used in computer graphics, computational biology, and data mining.

+ +

Implementation

+

Here is an implementation of bucket sort in OCaml:

+ +
let bucket_sort arr =  
+  let n = Array.length arr in  
+  let buckets = Array.make n [] in  
+  for i = 0 to n - 1 do  
+    let bucket_index = int_of_float (arr.(i) *. (float_of_int n)) in  
+    buckets.(bucket_index) <- arr.(i) :: buckets.(bucket_index)  
+  done;  
+  let sorted = ref [] in  
+  for i = 0 to n - 1 do  
+    buckets.(i) <- List.sort compare buckets.(i);  
+    sorted := !sorted @ buckets.(i)  
+  done;  
+  Array.of_list !sorted  
+
+ +

This implementation takes an array of floating-point numbers as input and returns a sorted array.

+ +

Step-by-step Explanation

+
    +
  1. The input array is first traversed to determine the number of buckets required. This is done by taking the length of the array and creating an empty bucket for each index. +
    let n = Array.length arr in  
    +let buckets = Array.make n [] in  
    +
    +
  2. +
  3. The elements of the array are then distributed into the buckets. This is done by iterating over the array and calculating the index of the bucket for each element. The index is calculated by multiplying the element by the number of buckets and taking the integer part of the result. +
    for i = 0 to n - 1 do  
    +  let bucket_index = int_of_float (arr.(i) *. (float_of_int n)) in  
    +  buckets.(bucket_index) <- arr.(i) :: buckets.(bucket_index)  
    +done;  
    +
    +
  4. +
  5. Each bucket is then sorted individually. This is done using the OCaml List.sort function, which sorts a list in ascending order using the compare function. +
    for i = 0 to n - 1 do  
    +  buckets.(i) <- List.sort compare buckets.(i);  
    +done;  
    +
    +
  6. +
  7. Finally, the sorted elements are concatenated to form the final sorted array. +
    let sorted = ref [] in  
    +for i = 0 to n - 1 do  
    +  sorted := !sorted @ buckets.(i)  
    +done;  
    +Array.of_list !sorted  
    +
    +
  8. +
+ +

Complexity Analysis

+

The time complexity of bucket sort depends on the sorting algorithm used to sort the individual buckets. In the worst case, if each bucket contains all the elements of the input array, the time complexity of bucket sort is O(n^2), where n is the number of elements in the input array. However, if the input is uniformly distributed over a range, the time complexity can be improved to O(n) by using a linear-time sorting algorithm like counting sort or radix sort to sort the individual buckets.

+ +

The space complexity of bucket sort is O(n), where n is the number of elements in the input array. This is because we need to create a bucket for each element in the input array. However, if the input is uniformly distributed over a range, the space complexity can be improved to O(k), where k is the number of buckets required, which is much smaller than n.

]]>
Liang Wangliang@ocaml.xyz
\ No newline at end of file diff --git a/docs/blog/index.html b/docs/blog/index.html new file mode 100644 index 0000000..7542fff --- /dev/null +++ b/docs/blog/index.html @@ -0,0 +1,156 @@ + + + + + +Algorithm Blog | A collection of classic algorithms, written in OCaml. + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + +
+ +
+
+ + +