Saving course
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…
Reference in New Issue