Saving course

drew/sql-it
Drew Bednar 1 year ago
parent 1eb4871631
commit 91831262c6

@ -0,0 +1,85 @@
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
func stringsToInt(inputStrings []string) []int {
integers := make([]int, len(inputStrings))
for i, v := range inputStrings {
intValue, err := strconv.Atoi(v)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %s could not be converted to integer", v)
os.Exit(1)
}
integers[i] = intValue
}
return integers
}
func quarterArray(input_arr []int) ([4][]int, error) {
if len(input_arr) < 4 {
return [4][]int{}, fmt.Errorf("slice is too small to be divided into 4 parts")
}
partSize := len(input_arr) / 4
remainder := len(input_arr) % 4
var result [4][]int
start := 0
for i := 0; i < 4; i++ {
end := start + partSize
if remainder > 0 {
end++
remainder--
}
result[i] = input_arr[start:end]
start = end
}
return result, nil
}
func sortArray(arr []int, c chan []int) {
fmt.Println("Will sort: ", arr)
sort.Ints(arr)
c <- arr
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("Input a sequence of ints and I will sort them for you: ")
// Process text into input []int
scanner.Scan()
input_text := scanner.Text()
input_text = strings.TrimSpace(input_text)
split_input := strings.Split(input_text, " ")
user_int_slice := stringsToInt(split_input)
// quarter input []int
quartered, err := quarterArray(user_int_slice)
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
// Spawn 4 threads
c := make(chan []int, 4)
for _, quarter := range quartered {
go sortArray(quarter, c)
}
combined := []int{}
for i := 4; i > 0; i-- {
sorted_ints := <-c
// the ... is use the []int as a variadic argument
combined = append(combined, sorted_ints...)
}
sort.Ints(combined)
fmt.Println(combined)
}

@ -0,0 +1,146 @@
/*
* Note: This program is written to demonstrate the ideas behind channels and synronization.
* It isn't written to be efficient code in term of memory use (I use copy by value, not by reference)
* or in terms of runtime (I use a waitgroup where reading from channels could provides synronization instead).
*
* Using slice.Sort in mysort() followed by a 4 way merge in main() is particularly ugly.
*
* Main() is split into 6 main steps:
* Step 1: Get the list of ints from the user
* Step 2: Split the list into four partitions of approximately equal size
* Step 3: Pass each quater to a goroutine to sort
* Step 4: Fetch results from channels
* Step 5: Merge the results. N.B. I'm taking "merge the 4 sorted subarrays into one large sorted array." literally here.
* Step 6: Print the output
*
* Some shuffled sequences to test this on:
* 2 5 3 6 1 7 10 4 8 9
* 3 13 1 11 19 17 16 7 10 14 9 4 6 8 5 2 12 15 18 20
* 24 18 5 15 4 12 28 30 3 27 29 14 20 6 23 21 10 8 19 9 17 16 7 25 11 2 22 1 26 13
*
*/
package main
import (
"fmt"
"os"
"bufio"
"strings"
"strconv"
"sync"
"slices"
)
func mysort(wg *sync.WaitGroup, c chan []int, goroutineNum int, numbers []int) {
defer wg.Done()
fmt.Printf("mysort%d got: %v\n", goroutineNum, numbers)
slices.Sort(numbers) // Using the sort in slices as this isn't an exercise in writing a sort()
c <- numbers
fmt.Printf("mysort%d returned: %v\n", goroutineNum, numbers)
}
func main() {
numbers := make([]int, 0)
// Step 1: Get the list of ints from the user
scanner := bufio.NewScanner(os.Stdin)
fmt.Printf("\nPlease enter a list of integers separated by spaces ( e.g. \"1 3 5 2\" ):\n")
scanner.Scan()
line := scanner.Text()
fields := strings.Fields(line)
for _, v := range(fields) {
n, err := strconv.Atoi(v)
if err != nil {
fmt.Println("Ignoring string: " + v)
continue
}
numbers = append(numbers, n)
}
// Step 2: Split the list into four partitions of approximately equal size
quarter1 := numbers[:len(numbers)/4]
quarter2 := numbers[len(numbers)/4 : len(numbers)/2]
quarter3 := numbers[len(numbers)/2 : len(numbers)/4+len(numbers)/2]
quarter4 := numbers[len(numbers)/4+len(numbers)/2:]
// Step 3: Pass each quater to a goroutine to sort
// N.B. the waitgroups are not needed for syncronization here as reading from unbuffered channels in Step 4
// would perform the same function. I'm using buffered channels just so the waitgroup is needed.
// This is to demonstrate the idea of waitgroups.
c1 := make(chan []int, 1)
c2 := make(chan []int, 1)
c3 := make(chan []int, 1)
c4 := make(chan []int, 1)
var wg sync.WaitGroup
wg.Add(4)
go mysort(&wg, c1, 1, quarter1)
go mysort(&wg, c2, 2, quarter2)
go mysort(&wg, c3, 3, quarter3)
go mysort(&wg, c4, 4, quarter4)
wg.Wait()
// Step 4: Fetch results from channels
nums1 := <- c1
nums2 := <- c2
nums3 := <- c3
nums4 := <- c4
// Step 5: Merge the results. N.B. I'm taking "merge the 4 sorted subarrays into one large sorted array." literally here.
// It would be far easier, and more readable, to merge nums1 and nums2 into nums5, merge nums3 and nums4 into nums6,
// and then merge nums5 and nums6 into the final output.
sorted := []int{}
lowest_list := 0
lowest_number := 0
for len(sorted) < len(numbers) {
// Step 5a: Find which of nums1 to nums4 starts with the lowest number
if len(nums1) > 0 {
lowest_list = 1;
lowest_number = nums1[0];
}
if len(nums2) > 0 {
if (len(nums1) == 0) || nums2[0] < lowest_number {
lowest_list = 2
lowest_number = nums2[0]
}
}
if len(nums3) > 0 {
if (len(nums1) == 0 && len(nums2) == 0) || nums3[0] < lowest_number {
lowest_list = 3
lowest_number = nums3[0]
}
}
if len(nums4) > 0 {
if (len(nums1) == 0 && len(nums2) == 0 && len(nums3) == 0) || nums4[0] < lowest_number {
lowest_list = 4
lowest_number = nums4[0]
}
}
// Step 5b: Update sorted with the lowest found and offset the []int it was found in
sorted = append(sorted, lowest_number)
switch lowest_list {
case 1:
nums1 = nums1[1:]
case 2:
nums2 = nums2[1:]
case 3:
nums3 = nums3[1:]
case 4:
nums4 = nums4[1:]
}
}
// Step 6: Print the output
fmt.Println("Final merged output:\n")
fmt.Println(sorted)
}

@ -0,0 +1,90 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"sync"
)
func Swap(sli []int, i int) {
sli[i], sli[i+1] = sli[i+1], sli[i]
}
func BubbleSort(sli []int, wg *sync.WaitGroup) {
fmt.Println(sli)
swapped := true
for limit := len(sli) - 1; limit > 0 && swapped == true; limit-- {
swapped = false
for i := 0; i < limit; i++ {
if sli[i] > sli[i+1] {
Swap(sli, i)
swapped = true
}
}
}
wg.Done()
}
func Merge(sli1, sli2 []int) []int {
sorted := make([]int, 0, len(sli1)+len(sli2))
i, j := 0, 0
for i < len(sli1) && j < len(sli2) {
if sli1[i] < sli2[j] {
sorted = append(sorted, sli1[i])
i++
} else {
sorted = append(sorted, sli2[j])
j++
}
}
if i < len(sli1) {
sorted = append(sorted, sli1[i:]...)
} else {
sorted = append(sorted, sli2[j:]...)
}
return sorted
}
func main() {
var seq []int
OuterLoop:
for seq == nil {
scanner := bufio.NewScanner(os.Stdin)
fmt.Println(
"Type in a sequence of space-separated integers:",
)
scanner.Scan()
input := strings.Fields(scanner.Text())
for _, value := range input {
num, err := strconv.Atoi(value)
if err != nil {
fmt.Printf("Invalid input: %q\n", value)
continue OuterLoop
} else {
seq = append(seq, num)
}
}
}
a := seq[:len(seq)/2]
b := seq[len(seq)/2:]
a1 := a[:len(a)/2]
a2 := a[len(a)/2:]
b1 := b[:len(b)/2]
b2 := b[len(b)/2:]
var wg sync.WaitGroup
wg.Add(4)
go BubbleSort(a1, &wg)
go BubbleSort(a2, &wg)
go BubbleSort(b1, &wg)
go BubbleSort(b2, &wg)
wg.Wait()
a = Merge(a1, a2)
b = Merge(b1, b2)
fmt.Println(strings.Trim(fmt.Sprint(Merge(a, b)), "[]"))
}
Loading…
Cancel
Save