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