Insertion Sort with a Linked List - sorting

I am trying to create an insertion sort with linked lists. Here is what I have:
def insertion_sort(a):
"""
-------------------------------------------------------
Sorts a list using the Insertion Sort algorithm.
Use: insertion_sort( a )
-------------------------------------------------------
Preconditions:
a - linked list of comparable elements (?)
Postconditions:
Contents of a are sorted.
-------------------------------------------------------
"""
unsorted = a._front
a._front = None
while unsorted is not None and unsorted._next is not None:
current = unsorted
unsorted = unsorted._next
if current._value < unsorted._value:
current._next = unsorted._next
unsorted._next = current
unsorted = unsorted._next
else:
find = unsorted
while find._next is not None and current._value > find._next._value:
find = find._next
current._next = find._next
current = find._next
a._front = unsorted
return a
I believe what I have is correct in terms of sorting. However when I try to read the list in the main module I get a bunch of None values.
In this case, the insertion sort is not creating a new list when sorting. Rather, it is moving all sorted elements to the 'front'.
To summarize, I have two problems: I am not sure if the insertion sort is correct, and there are problems with the returned list a as it contains None values. Thanks in advance

Not exactly sure about the type of a is, but if you assume a simple:
class Node:
def __init__(self, value, node=None):
self._value = value
self._next = node
def __str__(self):
return "Node({}, {})".format(self._value, self._next)
Then your insertion sort isn't far off, it needs to handle the head case properly:
def insertion_sort(unsorted):
head = None
while unsorted:
current = unsorted
unsorted = unsorted._next
if not head or current._value < head._value:
current._next = head;
head = current;
else:
find = head;
while find and current._value > find._next._value:
find = find._next
current._next = find._next
find._next = current
return head
>>> print(insertion_sort(Node(4, Node(1, Node(3, Node(2))))))
Node(1, Node(2, Node(3, Node(4, None))))

Related

How would I write a method to turn a binary search tree (BST) into a sorted list for the values in the BST?

So I have a binary search tree and need to produce a list with the BSTtoList method, but I'm not sure what the general steps are or what I have to do.
class BinarySearchTree[A](comparator: (A, A) => Boolean) {
var root: BinaryTreeNode[A] = null
def search(a: A): BinaryTreeNode[A] = {
searchHelper(a, this.root)
}
def searchHelper(a: A, node: BinaryTreeNode[A]): BinaryTreeNode[A] = {
if(node == null){
null
}else if(comparator(a, node.value)){
searchHelper(a, node.left)
}else if(comparator(node.value, a)){
searchHelper(a, node.right)
}else{
node
}
}
def BSTtoList: List[A] = {
var sortedList = List()
if (root.left != null) {
sortedList :+ searchHelper(root.value, root.left).value
}
else if (root.right != null){
sortedList :+ searchHelper(root.value, root.right).value
}
sortedList
}
}
Let's first think about how a BST works. At any given node, say with value x, all the nodes in the left subtree will have values < x and all nodes in the right subtree will have values > x. Thus, to return the sorted list of the subtree rooted at node x, you just have to return [sorted list of left subtree] + [x] + [sorted list of right subtree], so you just have to call BSTtoList recursively on the left and right subtrees, and then return the list described above. From there you just have to handle the base case of returning an empty list at a NULL node.
The above algorithm is O(N^2) time, and there's a better solution using tail recursion that runs in O(N) time, pseudocode for which:
def BSTtoList(root, accumulator):
if root == NULL:
return accumulator
else:
return BSTtoList(root.left_child, [root.value] + BSTtoList(root.right_child, accumulator)
Where BSTtoList is initially called with an empty list as the accumulator. This second solution works similarly to the first but is optimized by minimizing array merges (this version works best if the language used has O(1) insertion into the front of a list; implementation is a bit different if the language allows O(1) insertion into the back).

Minimum in rotated sorted array with duplicates

I am trying to find the minimum in a rotated sorted array with duplicates:
I tried this:
def find_pivot(arr):
lo = 0
hi = len(arr) -1
while lo<=hi:
mid = (hi+lo)//2
if arr[mid]<arr[0]:
hi = mid-1
else:
lo = mid+1
return lo
class Solution:
"""
#param nums: a rotated sorted array
#return: the minimum number in the array
"""
def findMin(self, nums):
pivot_index = find_pivot(nums)
left = nums[:pivot_index]
right = nums[pivot_index:]
if right:
return right[0]
return left[0]
This fails when the array is [999,999,1000,1000,10000,0,999,999,999]. My algorithm returns 999, when it should return 0
How do I fix this?
Binary search will not work here because of duplicates.
Suppose your array is [1,1,1,1,1,0,1,1]. Then arr[lo] = arr[hi] = arr[mid] = 1: which half you dive in? You may say "right one!" of course, but why? All informations you have with those three items only is not enough to have the certainty of you choice. In fact the array could be [1,0,1,1,1,1,1,1], and yet arr[lo] = arr[hi] = arr[mid] = 1, but the pivot is not in right half now.
In the worst case, with this type of instances you stil need to scan the whole array.
If you could have a more tighten order in the array, which means no duplicates (or, no more than k duplicates) then binary search would be useful.

Can quicksort ever be stable?

If values equal to the pivot are also considered during quicksort can it be called a stable sort? Here is my implementation of quicksort:
def isOrdered(aList):
ordered = True
for i in range(len(aList)-1):
if aList[i] > aList[i+1]:
ordered = False
break
return ordered
def partition(List,pivotIndex):
pivot=List[pivotIndex]
less=[]
equal=[]
greater=[]
if pivotIndex<len(List):
for i in List:
if i<pivot:
less.append(i)
elif i==pivot:
equal.append(i)
else:
greater.append(i)
returnlist= [less,equal,greater]
return returnlist
def quicksort(List,pivotIndex=0):
sortedList = []
if pivotIndex>=len(List):
pivotIndex%=len(List)
for i in partition(List,pivotIndex):
for j in i:
sortedList.append(j)
pivotIndex+=1
if isOrdered(sortedList):
return sortedList
else:
return quicksort(sortedList,pivotIndex)
Is it possible to improve stability and maintain computational speed for quicksort at the same time?

Find two disjoint susequences with minimum difference( > n)

You are given an array of positive numbers and you need to find two disjoint sub sequences with minimum difference less than or equal to n. These sub sequences may or may not be contiguous
For Example
if array = [10,12,101,105,1000] and n = 10
Ans = [10,105] & [12,101]
If minimum difference > n then there is no solution.
Ex- array = [100, 150, 125] and n = 7
I assume this could be done using DP but I fail to derive a recurrence.
If the sum of all your elements is not too big (within millions), then you can do a solution similar to a knapsack problem. Your DP state is a difference between two sets, and for every element you iterate over all the differences you know so far, and update them. Since a difference cannot exceed the sum of all the elements, the complexity ends up being O(n * s) where n is the number of elements and s is their sum. You will need some kind of logic to restore the answer. For example, if all your elements are non-negative, you can just store the previous difference. Here's an example python code (I slightly modified your sample case, because for your case it finds a non-interesting answer [10], [12])
a = [5, 20, 30, 1000]
n = 7
states = {(0, False, False): None} # state is sum, hasPositive, hasNegative => prevsum, prevHasP, prevHasN
for el in a:
newStates = {}
for k, v in states.items():
newStates[k] = v
for v, hasP, hasN in states:
if (v + el, True, hasN) not in newStates:
newStates[(v + el, True, hasN)] = (v, hasP, hasN)
if (v - el, hasP, True) not in newStates:
newStates[(v - el, hasP, True)] = (v, hasP, hasN)
states = newStates
best = None
for key, hasP, hasN in states.keys():
if key >= -n and key <= n and hasP and hasN and (best == None or abs(best[0]) > abs(key)):
best = (key, hasP, hasN)
if best is None: print "Impossible"
else:
ans1 = []
ans2 = []
while best[1] or best[2]: # while hasPositive or hasNegative
prev = states[best]
delta = best[0] - prev[0]
if delta > 0:
ans1.append(delta)
else:
ans2.append(- delta)
best = prev
print ans1
print ans2
As I mentioned before, it will only work if all your elements are non-negative, but it is easy to adjust the code that restores the answer to also work if the elements can be negative.

Pseudocode to compare two trees

This is a problem I've encountered a few times, and haven't been convinced that I've used the most efficient logic.
As an example, presume I have two trees: one is a folder structure, the other is an in-memory 'model' of that folder structure. I wish to compare the two trees, and produce a list of nodes that are present in one tree and not the other - and vice versa.
Is there an accepted algorithm to handle this?
Seems like you just want to do a pre-order traversal, essentially. Where "visiting" a node means checking for children that are in one version but not the other.
More precisely: start at the root. At each node, get a set of items in each of the two versions of the node. The symmetric difference of the two sets contains the items in one but not the other. Print/output those. The intersection contains the items that are common to both. For each item in the intersection (I assume you aren't going to look further into the items that are missing from one tree), call "visit" recursively on that node to check its contents. It's a O(n) operation, with a little recursion overhead.
public boolean compareTrees(TreeNode root1, TreeNode root2) {
if ((root1 == null && root2 != null) ||
(root1 != null && root2 == null)) {
return false;
}
if (root1 == null && root2 == null) {
return true;
}
if (root1.data != root2.data) {
return false;
}
return compareTrees(root1.left, root2.left) &&
compareTrees(root1.right, root2.right);
}
If you use a sort tree, like an AVL tree, you can also traverse your tree efficiently in-order. That will return your paths in sorted order from "low" to "high".
Then you can sort your directory array (e.g. Using quicksort) using the same compare method as you use in your tree algorithm.
Then start comparing the two side by side, advancing to the next item by traversing your tree in-order and checking the next item in your sorted directory array.
This should be more efficient in practice, but only benchmarking can tell.
A simple example code in python.
class Node(object):
def __init__(self, val):
self.val = val
self.child = {}
def get_left(self):
# if left is not in the child dictionary that means the element does not have a left child
if 'left' in self.child:
return self.child['left']
else:
return None
def get_right(self):
# if right is not in the child dictionary that means the element does not have a right child
if 'right' in self.child:
return self.child['right']
else:
return None
def traverse_tree(a):
if a is not None:
print 'current_node : %s' % a.val
if 'left' in a.child:
traverse_tree(a.child['left'])
if 'right' in a.child:
traverse_tree(a.child['right'])
def compare_tree(a, b):
if (a is not None and b is None) or (a is None and b is not None):
return 0
elif a is not None and b is not None:
print a.val, b.val
# print 'currently comparing a : %s, b : %s, left : %s, %s , right : %s, %s' % (a.val, b.val, a.child['left'].val, b.child['left'].val, a.child['right'].val, b.child['right'].val)
if a.val==b.val and compare_tree(a.get_left(), b.get_left()) and compare_tree(a.get_right(), b.get_right()):
return 1
else:
return 0
else:
return 1
# Example
a = Node(1)
b = Node(0)
a.child['left'] = Node(2)
a.child['right'] = Node(3)
a.child['left'].child['left'] = Node(4)
a.child['left'].child['right'] = Node(5)
a.child['right'].child['left'] = Node(6)
a.child['right'].child['right'] = Node(7)
b.child['left'] = Node(2)
b.child['right'] = Node(3)
b.child['left'].child['left'] = Node(4)
#b.child['left'].child['right'] = Node(5)
b.child['right'].child['left'] = Node(6)
b.child['right'].child['right'] = Node(7)
if compare_tree(a, b):
print 'trees are equal'
else:
print 'trees are unequal'
# DFS traversal
traverse_tree(a)
Also pasted an example that you can run.
You may also want to have a look at how git does it. Essentially whenever you do a git diff, under the hood a tree comparison is done.

Resources