Cannot find the bug in QuickSort implementation? [closed] - c#

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I am applying the QuickSort algorithm from book introduction to Algorithm i wrote the code,but the output is not sorted correctly
Following is the algorithm
Quicksort(A, p, r)
{
if (p < r)
{
q = Partition(A, p, r)
Quicksort(A, p, q-1)
Quicksort(A, q+1, r)
}
}
Partition(A, p, r)
{
pivot = A[r]
i = p - 1
for j = p to r – 1
{
do if A[j] <= pivot
then
{
i = i + 1
exchange A[i]  A[j]
}
}
exchange A[i+1]  A[r]
return i+1
}
and here is my code
class Threads<T>
{
static bool IsLessThan(T x, T y)
{
if (((IComparable)(x)).CompareTo(y)<=0)
{
return true;
}
else {
return false;
}
}
public int Partition(T[] myarray, int low, int high)
{
T x = myarray[high];
T y;
int i = low - 1;
int j;
for (j = low; j < high - 1; j++)
{
//**************Added Text after edit,I forgot to put this
if (IsLessThan(myarray[j], x))
{
i++;
y = myarray[i];
myarray[i] = myarray[j];
myarray[j] = y;
}
}
y = myarray[i+1];
myarray[i+1] = myarray[high];
myarray[high] = y;
return i + 1;
}
public void QuickSort(T[] myarray, int low, int high)
{
if (low < high)
{
// int q = Partition(myarray,highh, low);
int q = Partition(myarray,low, high);
QuickSort(myarray, low, q - 1);
QuickSort(myarray, q + 1, high );
}
}
}
Following code shows, how the quicksort method is used
private void button1_Click(object sender, EventArgs e)
{
int[] myarray ={9,8,7,6,5,4,3,2};
textBox1.Text = "";
Threads<int> t1 = new Threads<int>();
t1.QuickSort(myarray, 0, myarray.Length-1);
for(int i=0;i<myarray.Length;i++)
textBox1.Text=textBox1.Text+" , "+myarray[i];
}
I get the Following output when i execute the program
8 , 7 , 6 , 5 , 4 , 3 , 9 , 2
Answer
value of i must be one less than j and low at start in the Partition function
I forgot to Swap myarray[i+1] and myarray[high] outside the loops in Partition Function.
Now the code is working accurately fine for strings ,int ,char etc

Try this:
public int Partition(T []myarray, int low, int high)
{
T x = myarray[high];
int i=low;
int j=high;
while(i< j)
{
while(i<j&& IsLessThan(myarray[i], x))
i++;
myarray[j]=myarray[i];
while(i<j&& IsLessThan(x,myarray[j]))
j--;
myarray[i]=myarray[j];
}
myarray[i] = myarray[high];
return i ;
}

Try some changes and debug your code
I tried following
private static int Partition(int[] input, int left, int right)
{
int pivot = input[right];
int temp;
int i = left;
for (int j = left; j < right; j++)
{
if (input[j] <= pivot)
{
temp = input[j];
input[j] = input[i];
input[i] = temp;
i++;
}
}
input[right] = input[i];
input[i] = pivot;
return i;
}
if Pivot element is middle element
private static List<int> QuickSort(List<int> a, int left, int right)
{
int i = left;
int j = right;
double pivotValue = ((left + right) / 2);
int x = a[Convert.ToInt32(pivotValue)];
int w = 0;
while (i <= j)
{
while (a[i] < x)
{
i++;
}
while (x < a[j])
{
j--;
}
if (i <= j)
{
w = a[i];
a[i++] = a[j];
a[j--] = w;
}
}
if (left < j)
{
QuickSort(a, left, j);
}
if (i < right)
{
QuickSort(a, i, right);
}
return a;
}

First this part looked plain wrong, but even after changing the sort doesn't work
int q = Partition(myarray, high, low);
Low and high should be changed
int q = Partition(myarray, low, high);
I think this question is less about an algorithm, and more about the methods of debugging one. So I used a Quicksort algorithm I found online and tried to implement it in C#. I had problems of my own, but debugged it fairly quickly. The code below has some useful techniques to help with debugging. (The algorithm came from http://rosettacode.org/wiki/Sorting_algorithms/Quicksort.)
Here are my general comments when comparing your code:
It was confusing having an array of ints to test with when dealing with integer indices as well, so I changed my array to strings.
I used a lot of Console.WriteLine so I could trace the steps the algorithm was taking. That's what quickly helped me find that low/high issue.
I didn't not use a variable named i as anything but a for loop index. That's just confusing as all heck to use it as anything else -- don't do that!
Since every QuickSort algortithm had multiple swaps I created a Swap function. Even if you only do it once in your code, it clutters up the purpose of the Partition method to have such a trival pattern in there. To put this another way, why did it make sense for you to make IsLessThan a method but not Swap?
Speaking about IsLessThan, technically you actually wrote a method for IsLessThanOrEqual. Don't name things incorrectly, because if somebody uses that and assumes it is just for Less Then, they'll have a hard time when they have unpredictable results. IsLSE would be understandable by most.
Your for loop is the only place you use the variable j so why declare it outside of the for statement? Just adds an extra line and variable in a scope you don't need it.
Here's my QuickSort. It appears to work:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string[] myarray = { "g", "b", "e", "f", "a", "d", "c"};
QuickSort<string> t1 = new QuickSort<string>();
t1.Sort(myarray, 0, myarray.Length - 1);
}
}
public class QuickSort<T>
{
static int Compare (T x, T y)
{
return ((IComparable)(x)).CompareTo(y);
}
private void Swap(T[] myarray, int i, int j)
{
// swapping indices just for writeline purposes
if (i > j)
{
int t = i;
i = j;
j = t;
}
Console.WriteLine("Swap: {0}:{1} with {2}:{3}",
i, myarray[i], j, myarray[j]);
T temp = myarray[i];
myarray[i] = myarray[j];
myarray[j] = temp;
Console.WriteLine("Result: {0}", String.Join(",", myarray));
}
private int Partition(T[] myarray, int low, int high, int pivotIndex)
{
T pivotVal = myarray[pivotIndex];
Swap(myarray, pivotIndex, high);
int currentLow = low;
while (low <= high) {
while (Compare(myarray[low], pivotVal) < 0) {
low++;
}
while (Compare(myarray[high], pivotVal) > 0) {
high--;
}
if (low <= high) {
Swap(myarray, low, high);
low++;
high--;
}
}
return low;
}
public void Sort(T[] myarray, int low, int high)
{
if (low < high)
{
Console.WriteLine(("Start: {0}", String.Join(",", myarray));
int pivotIndex = (low + high) / 2;
Console.WriteLine("QuickSort: P: {0}, L: {1}, H: {2}",
pivotIndex, low, high);
pivotIndex = Partition(myarray, low, high, pivotIndex);
Sort(myarray, low, pivotIndex - 1);
Sort(myarray, pivotIndex + 1, high);
}
}
}

Related

Getting Stack overflow Exception while sorting an array with 15000+ elements [duplicate]

This question already has answers here:
StackOverflowException when perform Quicksort with ordered list
(1 answer)
Quicksort Algorithm (Cormen) gives Stackoverflow
(1 answer)
Closed 2 years ago.
This is my quick sort algorithm implementation. I'm getting System.StackOverflowException with the message 'Exception of type 'System.StackOverflowException' was thrown.' while trying to sort an array larger than 15k elements. I actually checked with 15000, 19000, 20000, 30000 elements, and the exception was thrown for the last 3 inputs.
private static int ArraySplitter(int[] intArr, int low, int high)
{
int pivot = intArr[high];
int lowIndex = (low - 1);
for (int i = low; i < high; i++)
{
if (intArr[i] <= pivot)
{
lowIndex++;
int temp = intArr[lowIndex];
intArr[lowIndex] = intArr[i];
intArr[i] = temp;
}
}
int tempHigh = intArr[lowIndex + 1];
intArr[lowIndex + 1] = intArr[high];
intArr[high] = tempHigh;
return lowIndex + 1;
}
private static void QSort(int[] intArr, int low, int high)
{
if (low < high)
{
int index = ArraySplitter(intArr, low, high);
QSort(intArr, low, index - 1);
QSort(intArr, index + 1, high);
}
}
public static void QuickSort(int[] intArr)
{
QSort(intArr, 0, intArr.Length - 1);
}
My python implementation also breaking for an array with larger than 5000 elements. Here is my python code -
def QUICKSORT(arr, p, r):
if p < r:
q = PARTITION(arr, p, r)
QUICKSORT(arr, p, q-1)
QUICKSORT(arr, q+1, r)
def PARTITION(arr, p, r):
x = arr[r]
i = p-1
for j in range(p, r-1):
if arr[j] <= x:
i = i + 1
temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
temp = arr[i+1]
arr[i+1] = arr[r]
arr[r] = temp
return i+1
I followed the pseudocode from Thomas H Cormen's Introduction to algorithms.
What's seems to be the problem and how to fix this issue?
Choosing the first or last element in a sub-array for pivot leads to worst case space complexity O(n) if the data is already sorted or reverse sorted. For the questions code, swap the middle element with the last element (array[high]) before splitting to handle sorted or reverse sorted data. Still there are other patterns that result in worst case behavior.
Only using recursion for the smaller partition will limit stack space complexity to O(log(n)), but worst case time complexity remains O(n^2).
private static void QSort(int[] intArr, int low, int high)
{
while (low < high)
{
int index = ArraySplitter(intArr, low, high);
if((index - low) <= (high - index)){
QSort(intArr, low, index - 1);
low = index + 1;
} else {
QSort(intArr, index + 1, high);
high = index - 1;
}
}
}

merge sort implementation query

I found this example of a merge sort algorithm online on a tutorial webpage and I have been trying to understand ow the code implements the algorithm. The example i found uses recursion and a temporary array to sort the array of unsorted algorithms.
My query is in the final step of the process. When copying the elements of the temporary array into the original array to sort the array. why does the algorithm decrements the right attribute instead of incrementing the left attribute? when i incremented the left left value the algorithm does not work.
class Assignment1
{
static void Main(string[] args)
{
Console.WriteLine("Size of array:");
int n = Convert.ToInt16(Console.ReadLine());
int[] unsorted = new int[n];
for(int i = 0; i < n; i++)
{
Console.WriteLine("Enter a number:");
unsorted[i] = Convert.ToInt16(Console.ReadLine());
}
Console.WriteLine("--------Sort---------");
Recursion_Sort(unsorted, 0, n - 1);
for (int i = 0; i < n; i++)
{
Console.WriteLine(unsorted[i]);
}
}
static public void Merge(int[] numbers, int left, int mid, int right, int n)
{
int[] tempArray = new int[n];
int i, lEnd, size, pos;
lEnd = mid - 1;
pos = left;
size = (right - left + 1);
while ((left <= lEnd) && (mid <= right))
{
if (numbers[left] <= numbers[mid])
{
tempArray[pos] = numbers[left];
pos++;
left++;
}
else
{
tempArray[pos] = numbers[mid];
pos++;
mid++;
}
}
while (left <= lEnd)
{
tempArray[pos] = numbers[left];
pos++;
left++;
}
while (mid <= right)
{
tempArray[pos] = numbers[mid];
pos++;
mid++;
}
Console.WriteLine(tempArray.Length);
for (i = 0; i < size; i++)
{
numbers[right] = tempArray[right];
right--;
}
}
static public void Recursion_Sort(int[] numbers, int left, int right)
{
int mid;
if (right > left)
{
mid = (right + left) / 2;
Recursion_Sort(numbers, left, mid);
Recursion_Sort(numbers, (mid + 1), right);
// we then merge the sorted sub arrays using the merge method
Merge(numbers, left, (mid + 1), right, numbers.Length);
}
}
}
left value is changing during merge and as you have code block
while (left <= lEnd)
{
//...
left++;
}
left will be finally assigned to lEnd + 1(the condition for ending while loop).
Otherwise right is not changing and is the last index of currently manipulated sequence.
Taking the risk of not answering the question like you want it, I would suggest LINQ. This is not merge sort in particular, but rather a concatenation of two arrays and then sorting.
If your array isn't so big that performance matters, you might want to go for this approach, because it's simple and less code (which is always good).
int[] arr1 = new[] { 1, 2, 3, 7, 8, 10 };
int[] arr2 = new[] { 4, 6, 9, 12, 15 };
int[] merged = arr1.Concat(arr2).OrderBy(n => n).ToArray();
Furthermore, I post this if it is interesting for others.

Implementing QuickSort recursively in C#

I started learning algorithms and I am trying to implement Quicksort in C#.
This is my code:
class QuickSortDemo
{
public void Swap(ref int InputA, ref int InputB)
{
InputA = InputA + InputB;
InputB = InputA - InputB;
InputA = InputA - InputB;
}
public int Partition(int[] InputArray, int Low, int High)
{
int Pivot = InputArray[Low];
int LoopVariable1 = Low - 1;
int LoopVariable2 = High + 1;
while (true)
{
while (InputArray[--LoopVariable2] > Pivot) ;
while (InputArray[++LoopVariable1] < Pivot) ;
if (LoopVariable1 < LoopVariable2)
{
Swap(ref InputArray[LoopVariable1], ref InputArray[LoopVariable2]);
for (int LoopVariable = Low; LoopVariable <= High; LoopVariable++)
{
Console.Write(InputArray[LoopVariable] + " ");
}
Console.WriteLine();
}
else
{
for (int LoopVariable = Low; LoopVariable <= High; LoopVariable++)
{
Console.Write(InputArray[LoopVariable] + " ");
}
Console.WriteLine();
return LoopVariable2;
}
}
}
public void QuickSort(int[] InputArray,int Low, int High)
{
if (Low < High)
{
int Mid = Partition(InputArray, Low, High);
QuickSort(InputArray, Low, Mid);
QuickSort(InputArray, Mid + 1, High);
}
}
public static void Main()
{
int[] InputArray = { 10, 5, 6, 8, 23, 19, 12, 17 };
QuickSortDemo Demo = new QuickSortDemo();
for (int LoopVariable = 0; LoopVariable < InputArray.Length; LoopVariable++)
{
Console.Write(InputArray[LoopVariable]+" ");
}
Console.WriteLine();
Demo.QuickSort(InputArray, 0, InputArray.Length - 1);
for (int LoopVariable = 0; LoopVariable < InputArray.Length; LoopVariable++)
{
Console.Write(InputArray[LoopVariable] + " ");
}
Console.WriteLine();
}
}
For some reason I can't get this to work when I take the rightmost element in the array as pivot. I don't know what I am doing wrong. It would be really helpful if someone could explain me why this doesn't work when I take my rightmost element as the pivot. From what I learned, this should work for any input and any pivot element. Correct me if I am wrong.
Thank you.
I'm still not entirely sure I understand the question. But I was able to reproduce a problem (infinite recursion) when I change the line of code in the Partition() method from int pivot = inputArray[low]; to int pivot = inputArray[high];, and doing so seems consistent with your narrative:
I can't get this to work when I take the rightmost element in the array as pivot.
If I've understood the question correctly, then the basic problem is that when you change where you get the pivot, you also need to take this into account when returning the new mid-point. Currently, you return loopVariable2, which is correct when picking the pivot from the lower end of the array. But if you switch to picking the pivot from the upper end of the array, you need to return loopVariable2 - 1.
Another problem is that as you are scanning, you unconditionally increment or decrement the respective "loop variable", regardless of whether the current index is already at an element in the wrong partition. You need to check the current element position first, and only adjust the index if that element is in the correct partition.
Here is a correct version of the Partition() method where the pivot is selected using high instead of low:
public int Partition(int[] inputArray, int low, int high)
{
int pivot = inputArray[high];
int loopVariable1 = low;
int loopVariable2 = high;
while (true)
{
while (inputArray[loopVariable2] > pivot) loopVariable2--;
while (inputArray[loopVariable1] < pivot) loopVariable1++;
if (loopVariable1 < loopVariable2)
{
Swap(ref inputArray[loopVariable1], ref inputArray[loopVariable2]);
for (int loopVariable = low; loopVariable <= high; loopVariable++)
{
Console.Write(inputArray[loopVariable] + " ");
}
Console.WriteLine();
}
else
{
for (int loopVariable = low; loopVariable <= high; loopVariable++)
{
Console.Write(inputArray[loopVariable] + " ");
}
Console.WriteLine();
return loopVariable2 - 1;
}
}
}
In either case, note that the effect is to ensure that regardless of the pivot value selected, you always partition the array in such a way to ensure that a new pivot is always selected with each level of recursion, preventing the infinite loop.
By the way, and for what it's worth, I would not implement Swap() as you have. It's an interesting gimmick to do a no-temp-variable swap, but there is no practical benefit to doing so, while it does incur a significant code maintenance and comprehension cost. In addition, it will only work with integral numeric types; what if you want to extend your sort implementation to handle other types? E.g. ones that implement IComparable or where you allow the caller to provide an IComparer implementation?
IMHO a better Swap() method looks like this:
public void Swap<T>(ref T inputA, ref T inputB)
{
T temp = inputA;
inputA = inputB;
inputB = temp;
}
quick sort:
static public int Partition(int [] numbers, int left, int right)
{
int pivot = numbers[left];
while (true)
{
while (numbers[left] < pivot)
left++;
while (numbers[right] > pivot)
right--;
if (left < right)
{
int temp = numbers[right];
numbers[right] = numbers[left];
numbers[left] = temp;
}
else
{
return right;
}
}
}
static public void QuickSort_Recursive(int [] arr, int left, int right)
{
// For Recusrion
if(left < right)
{
int pivot = Partition(arr, left, right);
if(pivot > 1)
QuickSort_Recursive(arr, left, pivot - 1);
if(pivot + 1 < right)
QuickSort_Recursive(arr, pivot + 1, right);
}
}

Generic Quick sorting algorithm

I am very new to this site and also a beginner programmer. I have been given a quick sort method which will sort an array of generic objects. I am using the in built compareTo method but when i come to call my method, it wont compile. The quicksort method takes an array of T items and an int left and int right. I do not know how to call on my method and when i do get it to work, my array doesnt become sorted. Can anyone give me any help at all? Im really struggling to understand and most sites on the internet are slightly to complex for my knowledge :( Heres the code:
namespace QuickSort2
{
class Program
{
private void QuickSort<T>(T[] items, int left, int right) where T: IComparable
{
int i, j;
i = left; j = right;
IComparable pivot = items[left];
while (i <= j)
{
for (; (items[i].CompareTo(pivot) < 0) && (i.CompareTo(right) < 0); i++);
for (; (pivot.CompareTo(items[j]) < 0) && (j.CompareTo(left) > 0); j--);
if (i <= j)
swap(ref items[i++], ref items[j--]);
}
if (left < j) QuickSort<T>(items, left, j);
if (i < right) QuickSort<T>(items, i, right);
}
static void swap<T>(ref T x, ref T y)
{
//swapcount++;
T temp = x;
x = y;
y = temp;
}
static void Main(string[] args)
{
IComparable[] array1 = { 3,5,7,8,1,2 };
foreach (int s in array1)
{
Console.WriteLine(" {0} ", s);
}
Console.ReadKey();
Console.WriteLine("Sorted version");
foreach (int x in array1)
{
QuickSort(array1, 0, array1.Length - 1);
Console.WriteLine(" {0} ", x);
}
Console.ReadKey();
}
}
}
Your code is fine, but you're not actually calling the QuickSort method... (EDIT: not true anymore after you edited your question...)
QuickSort(array1, 0, array1.Length - 1);
You also need to make the QuickSort method static to be able to call it from the static method Main.
private static void QuickSort<T>(T[] items, int left, int right) where T: IComparable

Fibonacci Sequence Error in C#

I've recently started learning C# (having learnt other languages) and I'm trying to create a function that generates the fibonacci sequence to the 'nth' term using a while loop and then returns the value of the 'nth' term.
My current code is this:
void fibonacci(int n)
{
int[] terms = { 0, 1 };
int i = 2;
while (i<=n)
{
terms.Concat( terms[i-1] + terms[i-2] );
i += 1;
}
return terms[n];
}
My understanding of C# is very poor as visual studio is telling me that I can't use 'Concat' with int[] - I'm trying to append the array with the new values. Any help would be great.
Arrays in C# are fixed length.
If you want to use a variable length collection, use a strongly typed List<T> instead, which has an Add method:
int fibonacci(int n)
{
var terms = new List<int>{ 0, 1 };
int i = 2;
while (i<=n)
{
terms.Add( terms[i-1] + terms[i-2] );
i += 1;
}
return terms[n];
}
You can't append to an array. In .Net, arrays have constant size and you can't resize them after creation.
Instead, you should use List<int> and its Add() method.
You can for example use list and change your code to:
int fibonacci(int n)
{
List<int> terms = new List<int> { 0, 1 };
int i = 2;
while (i<=n)
{
terms.Add(terms[i-1] + terms[i-2]);
i += 1;
}
return terms[n];
}
You can't add items to an array as it has fixed length. Use List<int> instead of array
I'm surprised nobody mentioned fixing the array size.
Well, maybe I'm missing something, but you could do:
int[] FibonacciArray(int n)
{
int[] F = new int[n+1];
F[0] = 0;
F[1] = 1;
for (int i = 2; i <= n; ++i)
{
F[i] = F[i - 1] + F[i - 2];
}
return F;
}
It's in average 2.5x faster than the version using a list.
But as often there is no free-lunch: the drawback is that your memory consumption is not smoothed: you pay upfront for all the memory you'll need.
Don't append values to an array. arrays have static size and you can't resize them after creation.
use
List<int> and its Add() method instead of array.
here is your solution for fibonacci series.
int fibonacci(int n)
{
var terms = new List<int>{ 0, 1 };
int i = 2;
while (i<=n)
{
terms.Add( terms[i-1] + terms[i-2] );
i += 1;
}
return terms[n];
}
also can be done like this :
class FibonacciSeries
{
static void Main(string[] args)
{
Console.WriteLine("Enter a num till which you want fibonacci series : ");
int val = Convert.ToInt32(Console.ReadLine());
int num1, num2;
num1 = num2 = 1;
Console.WriteLine(num1);
if (val > num2)
{
while (num2 < val)
{
Console.WriteLine(num2);
num2 += num1;
num1 = num2 - num1;
}
}
Console.ReadLine();
}
}
in your array format here is the solution
public int[] FibonacciSeriesArray(int num)
{
int[] arr = new int[num+1];
arr[0] = 0;
arr[1] = 1;
for (int startnum = 2; startnum <= num; startnum++)
{
arr[startnum] = arr[startnum - 1] + arr[startnum - 2];
}
return arr;
}
I would do it as a recursion, and not as a loop.
private static int fibonacci(int fib)
{
if (fib == 2 || fib == 1)
{
return 1;
}
else
{
return fibonacci(fib - 1) + fibonacci(fib - 2);
}
}
Here's a much more efficient way of finding fibonnaci numbers.
public static IEnumerable<double> FibList(int n)
{
for (int i = 1; i <= n; i++)
{
yield return Math.Round(Fib(i));
}
}
public static double Fib(double n)
{
double golden = 1.61803398875;
return (n == 0 || n == 1) ? 1 : (Math.Pow(golden, n) - Math.Pow(-golden, -n))/Math.Sqrt(5);
}

Categories

Resources