Explanation of heap indexing example - sorting

This code is taken from the Go heap example (with my own added prints). Here's the playground.
https://play.golang.org/p/E69SfBIZF5X
Most everything is straightforward and makes sense, but the one thing I can't wrap around is why the 'minimum' print on index 0 of the heap in main() returns the value 1 (the correct minimum) but printing 4 in the heap's pop function returns 1 (see output).
If the root (minimum) of a heap is always at n=0, why is it n=4 in the pop function itself? It then seems to work fine, in descending order.
Can someone explain what's going on here? I don't feel comfortable implementing something like the Pop before I understand what's going on.
// This example demonstrates an integer heap built using the heap interface.
package main
import (
"container/heap"
"fmt"
)
// An IntHeap is a min-heap of ints.
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
fmt.Printf("n: %v\n", n)
fmt.Printf("x: %v\n", x)
return x
}
// This example inserts several ints into an IntHeap, checks the minimum,
// and removes them in order of priority.
func main() {
h := &IntHeap{2, 1, 5}
heap.Init(h)
heap.Push(h, 3)
fmt.Printf("minimum: %d\n", (*h)[0])
for h.Len() > 0 {
fmt.Printf("roll: %d\n", (*h)[0])
fmt.Printf("%d\n", heap.Pop(h))
}
}
-
Output
x = value
n = index
minimum: 1
roll: 1
n: 4
x: 1
1
roll: 2
n: 3
x: 2
2
roll: 3
n: 2
x: 3
3
roll: 5
n: 1
x: 5
5

The textbook heap algorithms include a way to fix up a heap if you know the entire heap structure is correct (a[n] < a[2*n+1] && a[n] < a[2*n+2], for all n in bounds), except that the root is wrong, in O(lg n) time. When you heap.Pop() an item, it almost certainly (*IntHeap).Swaps the first and last elements, does some more swapping to maintain the heap invariants, and then (*IntHeap).Pops the last element. That's what you're seeing here.
You can also use this to implement a heap sort. Say you have an array int[4] you're trying to sort. Take a slice s int[] = (a, len=4, cap=4), then:
If len(s) == 1, stop.
Swap s[0] and s[len(s)-1].
Shrink the slice by one item: s = (array(s), len=len(s)-1, cap=cap(s)).
If the heap is out of order, fix it.
Go to 1.
Say your example starts with [1, 2, 5, 3]. Then:
[1, 2, 5, 3]
[3, 2, 5, 1] Swap first and last
[3, 2, 5], 1 Shrink slice by one
[2, 3, 5], 1 Correct heap invariant
[5, 3, 2], 1 Swap first and last
[5, 3], 2, 1 Shrink slice by one
[3, 5], 2, 1 Correct heap invariant
[5, 3], 2, 1 Swap first and last
[5], 3, 2, 1 Shrink slice by one
5, 3, 2, 1 Sorted (descending order)

Related

Optimize the next permutations in n queens puzzle

I am solving the n queens problem.
I use an array of 1..=n to represent the position of the queen, and then keep finding the next permutation until I judge that this permutation is a solution.
/// Returns a bool value indicating whether the next permutation exists
pub fn next_permutation(arrange: &mut [usize]) -> bool {
let last_ascending = match arrange.windows(2).rposition(|w| w[0] < w[1]) {
Some(i) => i,
None => {
arrange.reverse();
return false;
}
};
let swap_with = arrange[last_ascending + 1..]
.binary_search_by(|n| usize::cmp(&arrange[last_ascending], n).then(Ordering::Less))
.unwrap_err();
arrange.swap(last_ascending, last_ascending + swap_with);
arrange[last_ascending + 1..].reverse();
true
}
pub fn is_solution(arrange: &[usize]) -> bool {
let iter = arrange.iter().enumerate();
iter.clone().all(|(i, &j)| {
iter.clone()
.filter(|&(c, _)| c != i)
.all(|(p, &q)| i as isize - j as isize != p as isize - q as isize && i as usize + j != p as usize + q)
})
}
Now my problem is that the next_permutation function does not quite meet my needs.
For example [1, 2, 3, 4, 5], the next permutation is [1, 2, 3, 5, 4], this results in a lot of wasted judgment.
It can be found that [1, 2, _, _, _] does not meet the requirements , the next permutation to check should be say [1, 3, 2, 4, 5].
How do I optimize the next_permutation function to implement this process?

Best way to remove selected elements from slice

I have a slice A and another slice B. Slice A contains n elements and slice B is a subset of slice A where each element is a pointer to Slice A.
What would be the cheapest method to remove all elements from A which is referred in B.
After bit of googling only method I can think of is to reslice slice A for each element in B. Is that is only method or is there a simpler one?
I have a slice A and another slice B. Slice A contains n elements and
slice B is a subset of slice A where each element is a pointer to
Slice A.
What would be the cheapest method to remove all elements from A which
is referred in B.
A and B may have duplicates and may not be sorted.
For example, growth rate O(n),
package main
import "fmt"
func remove(a []int, b []*int) []int {
d := make(map[*int]bool, len(b))
for _, e := range b {
d[e] = true
}
var c []int
if len(a) >= len(d) {
c = make([]int, 0, len(a)-len(d))
}
for i := range a {
if !d[&a[i]] {
c = append(c, a[i])
}
}
return c
}
func main() {
a := []int{0, 1, 2, 3, 4, 5, 6, 7}
fmt.Println(a)
b := []*int{&a[1], &a[3], &a[3], &a[7], &a[4]}
a = remove(a, b)
fmt.Println(a)
}
Playground: https://play.golang.org/p/-RpkH51FSt2
Output:
[0 1 2 3 4 5 6 7]
[0 2 5 6]

backtracking n staircases at most k steps in a single jump

You need to climb a staircase that has n steps, and you decide to get some extra exercise by jumping up the steps. You can cover at most k steps in a single jump. Return all the possible sequences of jumps that you could take to climb the staircase, sorted.
My implementation is obviously giving me the wrong answer.
def climbingStaircase(n, k):
final_res=[]
final_res.append(CSR(n,k,[]))
return final_res
def CSR(n,k,res):
if n == 0:
return res
else:
for i in range(1,k+1):
if n-i>=0:
res.append(i)
n=n-i
res=CSR(n,i,res)
return res
For n = 4 and k = 2, the output should be
[[1, 1, 1, 1],
[1, 1, 2],
[1, 2, 1],
[2, 1, 1],
[2, 2]]
Actual output:
[[1,1,1,1,2,1]]
Can someone point out which part I'm missing?
One huge problem is in the code below: you deduct the quantity of steps for each possibility within the step range.
n=n-i
res=CSR(n,i,res)
When you're done exploring what you can do with a 1-step jump, you need to backtrack and try from the same starting point (this instance's original value of n) with a 2-step jump. Change the code to:
res = CSR(n-i, i, res)
This keeps the n value intact as you go through the loop.
In addition, you can't limit future jumps to the max of what you just took. Change that second parameter, too:
res = CSR(n-i, k, res)
That should get you moving. Also try this lovely debug blog for help. At least insert one or two tracing statements, such as
print n, k, res
at the top of your routine.
CAVEAT
This is not all of your trouble. The largest remaining problem is that CSR returns only one solution: every step you take is appended to the same list. You need a way to gather the completed solutions as separate lists; the append in climbingStaircase is executed only once, after CSR is entirely finished.
You need to recognize a completed solution at n==0.
DEBUGGING HELP
Here is a version of your program with the recursion parameters fixed, and debugging traces inserted.
indent = ""
def climbingStaircase(n, k):
final_res = []
final_res.append(CSR(n, k, []))
return final_res
def CSR(n, k, res):
global indent
indent += " "
print indent, n, k, res
if n == 0:
print "SOLUTION", res
else:
for i in range(1, k+1):
if n-i >= 0:
CSR(n-i, k, res + [i])
indent = indent[:-2]
print climbingStaircase(4, 2)
Note the use of "indent" to help visualize your recursion and backtracking. The critical part here is that, instead of updating res globally, I've left it as a local variable. I've also removed the return value for now, simply dumping to output the solutions as they're found. You can see how it works:
4 2 []
3 2 [1]
2 2 [1, 1]
1 2 [1, 1, 1]
0 2 [1, 1, 1, 1]
SOLUTION [1, 1, 1, 1]
0 2 [1, 1, 2]
SOLUTION [1, 1, 2]
1 2 [1, 2]
0 2 [1, 2, 1]
SOLUTION [1, 2, 1]
2 2 [2]
1 2 [2, 1]
0 2 [2, 1, 1]
SOLUTION [2, 1, 1]
0 2 [2, 2]
SOLUTION [2, 2]
[None]
With this stuff in place, I'm hopeful you can trace your logic and figure out how to capture the sequence of solutions at a level of your choosing.
Successfully implemented Prune's answer.
def climbingStaircase(n, k):
res=[]
CSR(n,k,[],res)
return res
def CSR(n,k,str_, res):
if n == 0:
res.append(str_)
else:
for i in range(1,k+1):
if n-i>=0:
CSR(n-i,k,str_+[i],res)
A quick Java version of this solution:
int[][] climbingStaircase(int n, int k) {
List<ArrayList<Integer>> list = new ArrayList<>();
climb(n, k, new ArrayList<Integer>(), list);
// convert to int[][]
int[][] result = new int[list.size()][];
for (int i=0; i<list.size(); i++) {
List<Integer> l = list.get(i);
int [] arr = new int[l.size()];
for (int j=0; j<l.size(); j++)
arr[j] = l.get(j);
result[i] = arr;
}
return result;
}
void climb(int n, int k, ArrayList<Integer> prev, List<ArrayList<Integer>> list) {
if (n==0) { // no more stairs, done climbing
list.add(prev);
} else {
for (int i=1; i<=k; i++) { // climb remaining stairs in intervals from 1 to k steps
if (i <= n) { // no need to test intervals larger than remaining # of stairs
ArrayList<Integer> branch = new ArrayList<>(prev);
branch.add(i);
climb(n-i, k, branch, list);
}
}
}
}
In Swift 5.5
func solution(n: Int, k: Int) -> [[Int]] {
var res_final = [[Int]]()
SRC(n: n, k: k, res: [], &res_final)
return res_final
}
var indent: String = ""
func SRC(n: Int, k: Int, res: [Int], _ res_final: inout [[Int]]) {
indent += " "
print(indent, n, k, res)
if n == .zero {
res_final.append(res)
print("Solution", res)
} else {
for i in 1...k {
if n-i >= .zero {
SRC(n: n-i, k: k, res: res + [i], &res_final)
}
}
}
indent = " "
}
solution(n: 4, k: 2)

Decreasing slice capacity

My question is about slice length and capacity. I'm learning about Go here: https://tour.golang.org/moretypes/11.
(My question was marked as a possible duplicate of this; however, this is not the case. My question is specifically about the cutting off the first few elements of a slice and the implications of that.)
Why does the line s = s[2:] decrease the capacity when s = s[:4] and s = s[:0] do not? The only difference I see is that there is a number before the colon in s = s[2:] while there is a number after the colon in the other two lines.
Is there any way to recover the first two elements that we cut off with s = s[2:]?
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// Slice the slice to give it zero length.
s = s[:0]
printSlice(s)
// Extend its length.
s = s[:4]
printSlice(s)
// Drop its first two values.
s = s[2:]
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
After clicking the Run button, we get the following.
len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]
You can read more about slices here. But I think this passage answers your question:
Slicing does not copy the slice's data. It creates a new slice value that points to the original array. This makes slice operations as efficient as manipulating array indices. Therefore, modifying the elements (not the slice itself) of a re-slice modifies the elements of the original slice.
So you cannot recover the slice data if you are assigning it to the same variable.
The capacity decrease is because by dropping the first 2 elements you are changing the pointer to the new slice (slices are referenced by the pointer to the first element).
How slices are represented in the memory:
make([]byte, 5)
s = s[2:4]
You can use a full slice expression:
package main
func main() {
s := []int{2, 3, 5, 7, 11, 13}
{ // example 1
t := s[:0]
println(cap(t) == 6)
}
{ // example 2
t := s[:0:0]
println(cap(t) == 0)
}
}
https://golang.org/ref/spec#Slice_expressions
The slices.Clip of "golang.org/x/exp/slices" could reduce the capacity of slice through Full slice expressions.
Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
s = s[:4]
printSlice(s)
s = slices.Clip(s)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
len=6 cap=6 [2 3 5 7 11 13]
len=4 cap=6 [2 3 5 7]
len=4 cap=4 [2 3 5 7]
Playground

Golang: appending slices with or w/o allocation

Go's append() function only allocates new slice data, when the capacity of the given slice is not sufficient (see also: https://stackoverflow.com/a/28143457/802833). This can lead to unexpected behavior (at least for me as a golang newbie):
package main
import (
"fmt"
)
func main() {
a1 := make([][]int, 3)
a2 := make([][]int, 3)
b := [][]int{{1, 1, 1}, {2, 2, 2}, {3, 3, 3}}
common1 := make([]int, 0)
common2 := make([]int, 0, 12) // provide sufficient capacity
common1 = append(common1, []int{10, 20}...)
common2 = append(common2, []int{10, 20}...)
idx := 0
for _, k := range b {
a1[idx] = append(common1, k...) // new slice is allocated
a2[idx] = append(common2, k...) // no allocation
idx++
}
fmt.Println(a1)
fmt.Println(a2) // surprise!!!
}
output:
[[10 20 1 1 1] [10 20 2 2 2] [10 20 3 3 3]]
[[10 20 3 3 3] [10 20 3 3 3] [10 20 3 3 3]]
https://play.golang.org/p/8PEqFxAsMt
So, what ist the (idomatic) way in Go to force allocation of new slice data or more precisely to make sure that the slice argument to append() remains unchanged?
You might maintain a wrong idea of how slices work in Go.
When you append elements to a slice, the call to append() returns a new slice. If reallocation did not happen, both slice values — the one you called append() on and the one it returned back — share the same backing array but they will have different lengths; observe:
package main
import "fmt"
func main() {
a := make([]int, 0, 10)
b := append(a, 1, 2, 3)
c := append(a, 4, 3, 2)
fmt.Printf("a=%#v\nb=%#v\nc=%#v\n", a, b, c)
}
outputs:
a=[]int{}
b=[]int{4, 3, 2}
c=[]int{4, 3, 2}
So, len(a) == 0, len(b) == 3, len(c) == 3, and the second call to append() owerwrote what the first one did because all the slices share the same underlying array.
As to reallocation of the backing array, the spec is clear:
If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.
From this, it follows that:
append() never copies the underlying storage if the capacity of the slice being appeneded to is sufficient.
If there's not enough capacity, the array will be reallocated.
That is, given a slice s to which you want to append N elements, the reallocation won't be done iff cap(s) - len(s) ≥ N.
Hence I suspect your problem is not about unexpected reallocation results but rather about the concept of slices as implemented in Go. The code idea to absorb is that append() returns the resulting slice value, which you're supposed to be using after the call unless you fully understand the repercussions.
I recommend starting with this to fully understand them.
Thanx for your feedback.
So the solution to gain control of the memory allocation is to do it explicitely (which remembers me that Go is a more a system language than other (scripting) langs):
package main
import (
"fmt"
)
func main() {
a1 := make([][]int, 3)
a2 := make([][]int, 3)
b := [][]int{{1, 1, 1}, {2, 2, 2}, {3, 3, 3}}
common1 := make([]int, 0)
common2 := make([]int, 0, 12) // provide sufficient capacity
common1 = append(common1, []int{10, 20}...)
common2 = append(common2, []int{10, 20}...)
idx := 0
for _, k := range b {
a1[idx] = append(common1, k...) // new slice is allocated
a2[idx] = make([]int, len(common2), len(common2)+len(k))
copy(a2[idx], common2) // copy & append could probably be
a2[idx] = append(a2[idx], k...) // combined into a single copy step
idx++
}
fmt.Println(a1)
fmt.Println(a2)
}
output:
[[10 20 1 1 1] [10 20 2 2 2] [10 20 3 3 3]]
[[10 20 1 1 1] [10 20 2 2 2] [10 20 3 3 3]]
https://play.golang.org/p/Id_wSZwb84

Resources