Given an array say nums = { 1,2,5,3,6,-1,-2,10,11,12}, using max no of elements (say maxNums=3)
find the elements whose sum (say sum =10) = K
so if maxNums to be used = 3
sum to find = 10
the the answer is
{1 3 6}
{1 -1 10}
{1 -2 11}
{2 5 3}
{2 -2 10}
{5 6 -1}
{-1 11}
{-2 12}
{10}
I wrote a recursive function which does the job. How do I do it without recursion?
and/or with less memory ?
class Program
{
static Int32[] nums = { 1,2,5,3,6,-1,-2,10,11,12};
static Int32 sum = 10;
static Int32 maxNums = 3;
static void Main(string[] args)
{
Int32[] arr = new Int32[nums.Length];
CurrentSum(0, 0, 0, arr);
Console.ReadLine();
}
public static void Print(Int32[] arr)
{
for (Int32 i = 0; i < arr.Length; i++)
{
if (arr[i] != 0)
Console.Write(" " +arr[i]);
}
Console.WriteLine();
}
public static void CurrentSum(Int32 sumSoFar, Int32 numsUsed, Int32 startIndex, Int32[] selectedNums)
{
if ( startIndex >= nums.Length || numsUsed > maxNums)
{
if (sumSoFar == sum && numsUsed <= maxNums)
{
Print(selectedNums);
}
return;
}
**//Include the next number and check the sum**
selectedNums[startIndex] = nums[startIndex];
CurrentSum(sumSoFar + nums[startIndex], numsUsed+1, startIndex+1, selectedNums);
**//Dont include the next number**
selectedNums[startIndex] = 0;
CurrentSum(sumSoFar , numsUsed , startIndex + 1, selectedNums);
}
}
You function looks fine but possible a bit optimize:
class Program
{
static Int32[] nums = { 1, 2, 5, 3, 6, -1, -2, 10, 11, 12 };
static Int32 sum = 10;
static Int32 maxNums = 3;
static Int32[] selectedNums = new Int32[maxNums];
static void Main(string[] args)
{
CurrentSum(0, 0, 0);
Console.ReadLine();
}
public static void Print(int count)
{
for (Int32 i = 0; i < count; i++)
{
Console.Write(" " + selectedNums[i]);
}
Console.WriteLine();
}
public static void CurrentSum(Int32 sumSoFar, Int32 numsUsed, Int32 startIndex)
{
if (sumSoFar == sum && numsUsed <= maxNums)
{
Print(numsUsed);
}
if (numsUsed >= maxNums || startIndex >= nums.Length)
return;
for (int i = startIndex; i < nums.Length; i++)
{
// Include i'th number
selectedNums[numsUsed] = nums[i];
CurrentSum(sumSoFar + nums[i], numsUsed + 1, i + 1);
}
}
}
Also I fixed a bug in your function.
It fails on following testcase:
{10, 2, -2}
Sum = 10
K = 3
Your functions returns only {10} instead of {10} and {10, 2, -2}
And the Haskell solution...
import Data.List
listElements max_num k arr =
filter (\x -> sum x == k && length x == max_num) $ subsequences arr
*Main> listElements 3 10 [1,2,5,3,6,-1,-2,10,11,12]
[[2,5,3],[1,3,6],[5,6,-1],[1,-1,10],[2,-2,10],[1,-2,11]]
Related
I'm currently working on a LeetCode question called TwoSums.
It requires me to:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
My code works with different lengths of arrays. However, I found that when the numbers aren't in order, it gives the wrong answers.
My test case was [3,2,4] Target number = 6.
public class Solution {
public int[] TwoSum(int[] nums, int target)
{
int[] ret = new int[2];
int start = 0
int end = nums.Length - 1;
while(start < end)
{
if (nums[start] + nums[end] == target)
{
ret[0] = start;
ret[1] = end;
break;
}
else if(nums[start] + nums[end] < target)
{
start++;
}
else
{
end--;
}
}return(ret);
}
}
Here's a trivial brute-force solution which checks every pair of numbers. This has time complexity O(n^2):
public int[] TwoSum(int[] nums, int target)
{
for (int i = 0; i < nums.Length - 1; i++)
{
for (int j = i + 1; j < nums.Length; j++)
{
if (nums[i] + nums[j] == target)
{
return new[] { i, j };
}
}
}
throw new Exception("Solution not found");
}
We take care not to try any pair more than once - j always starts above i.
You can use 2 nested loops. :
public static int[] TwoSum(int[] nums, int target)
{
int[] ret = new int[2];
for (int i = 0; i < nums.Length - 1; i++)
{
for (int j = i + 1; j < nums.Length; j++)
{
if (nums[i] + nums[j] == target)
{
ret[0] = i;
ret[1] = j;
return ret;
}
}
}
return null; // This avoid compiler to complain about "not all path returns a value"
}
Your implementation assumes the list is sorted, because in the second if you check if the sum of start and end is smaller than target. Try this approach:
public class Solution
{
public int[] TwoSum(int[] nums, int target)
{
int[] ret = new int[2];
if (nums.Length < 2)
return ret;
int start = 0;
int end = 1;
while (start < (nums.Length -1))
{
if (nums[start] + nums[end] == target)
{
ret[0] = start;
ret[1] = end;
break;
}
if (end < nums.Length -1))
{
end++
}
else
{
start++;
end = start + 1
}
}
return ret;
}
}
It starts with start looking at index 0 and end at the next element. If it matches the target it returns the result. If not, it increments end until it reaches the end of the array. Than it wil increment start and reset end to start + 1, to look at the next element again. And so on until start reaches the last element. It then has checked all combinations.
There are numerous ways to approach this but the most direct - as already pointed out by the other answers - is nested loops.
What they all missed, including myself until I read your question again, was this:
You may assume that each input would have exactly one solution,
While it seems unimportant, this actually gives us a small optimization: reverse the search.
Using the forward method for your given inputs there are 3 comparisons done to find the answer:
[0, 1] => 3 + 2 != 6
[0, 2] => 3 + 4 != 6
[1, 2] => 2 + 4 == 6
For each pass through the outer loop the number of passes through the inner loop decreases. Unless the answer includes the first item in the array that means that you're testing more than you need to.
If we reverse the search we eliminate pairs from each outer loop faster:
static int[] TwoSums(int target, int[] array)
{
for (int i1 = array.Length - 2; i1 >= 0; i1--)
{
int v1 = array[i1];
for (int i2 = i1 + 1; i2 < array.Length; i2++)
{
if (v1 + array[i2] == target)
return new[] { i1, i2 };
}
}
return null;
}
This way the sequence for your example is:
[1, 2] => 2 + 4 == 6
That's a little bit of a cheat though, since the answer in this case is the last pair. Let's try something different and compare:
Array: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
Test value: 24
With a little instrumentation we can see how many times we run through the loop. For this particular case the forward search does 22 comparisons before it finds the one that works while the reverse does only 11. If the test value were 48 (19 + 29) the numbers would be: Forward=49, Reverse=5.
Of course if the answer includes one of the first couple of values then the numbers flip. It's a game of averages.
class Program
{
static void Main(string[] args)
{
int[] indexes = GetSumIndexes(new int[] { 3, 2, 4 }, 6);
}
public static int[] GetSumIndexes(int[] numbers, int target)
{
for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers.Length; j++)
{
if (i != j)
{
if (numbers[i] + numbers[j] == target)
{
return new int[] { i, j };
}
}
}
}
return new int[] { };
}
}
Output:
[1,2]
Optimized version you can find in the other answers:
class Program
{
static void Main(string[] args)
{
int[] indexes = GetSumIndexes(new int[] { 3, 2, 4 }, 6);
}
public static int[] GetSumIndexes(int[] numbers, int target)
{
for (int i = 0; i < numbers.Length; i++)
{
for (int j = i + 1; j < numbers.Length; j++)
{
if (numbers[i] + numbers[j] == target)
{
return new int[] { i, j };
}
}
}
return new int[] { };
}
}
Output:
[1,2]
I need to determine the given input into all possible banknote combinations.
int[] currency = new int[] { 5, 10, 20, 50, 100, 200, 500 };
int total = 20; // result is { {5,5,5,5} {5,5,10} {10,10} {20} }
int[][] result = GetCombinations(total, 0, currency); // should return the 4 combinations
Here is what I've tried so far.
public static int GetCombinations(int total, int index, int[] list)
{
total = total - list[index];
if (total < 0)
{
return 0;
}
else if (total == 0)
{
return 1;
}
else
{
return 1 + GetCombinations(total, index + 1, list);
}
}
QUESTION for Bounty:
I need a way to get all combinations - not just the count.
You are only calculating {5}, {5, 10}.
You are calculating "How many different coins can use if the cost <= 20?".
So, you have to count for this algorithm.
The correct code is:
public static int GetCombinations(int total, int index, int[] list)
{
if (total == 0)
{
return 1;
}
if(index == list.Length) {
return 0;
}
int ret = 0;
for(; total >= 0; total -= list[index])
{
ret += GetCombinations(total, index + 1, list);
}
return ret;
}
If you want to calculate the number of combinations, you can also solve dynamic programming and memorize for dp[total][index], because GetCombinations(total, index, list) value is same if total and index is same.
EDIT:
If you want ALL combinations, you can do like this:
using System;
using System.Collections.Generic;
class Program {
public static int GetCombinations(int total, int index, int[] list, List<int> cur) {
if (total == 0) {
foreach(var i in cur) {
Console.Write(i + " ");
}
Console.WriteLine();
return 1;
}
if(index == list.Length) {
return 0;
}
int ret = 0;
for(; total >= 0; total -= list[index]) {
ret += GetCombinations(total, index + 1, list, cur);
cur.Add(list[index]);
}
for(int i = 0; i < cur.Count; i++) {
while(cur.Count > i && cur[i] == list[index]) {
cur.RemoveAt(i);
}
}
return ret;
}
public static void Main() {
int[] l = { 5, 10, 20, 50, 100, 200, 500 };
GetCombinations(20, 0, l, new List<int>());
}
}
I improved my code and now you're able to enumerate ALL combinations using recursion.
In this code, it enumerates combinations in lexicographical order.
I verified for sum=20, 75 cases.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I am trying to develop Max Sub Array Problem in C#
And my code is
try
{
int[] Values = { 9, 1, 4, 15, -5, -41, -8, 78, 145, 14 };//Will be executed once '1'
int StartIndex = 0;//Will be executed once '1'
double Sum = 0;//Will be executed once '1'
double Temp = 0;//Will be executed once '1'
double Max = 0;//Will be executed once '1'
do
{
for (int i = 0; i < Values.Length; i++)//1+(N+1)+N
{
Sum = Values[StartIndex];
if (StartIndex < i)
{
for (int j = StartIndex+1; j <= i; j++)
{
Sum += Values[j];
}
if (Sum > Temp)
{
Max = Sum;
Temp = Sum;
}
}
}
StartIndex++;
} while (StartIndex<Values.Length);
MessageBox.Show("The Max Value is " + Max);
}
catch { }
I would like to know if this is the best approach to solve this algorithm as I am trying to minimize the time complexity
Thank you all for your time
There's an O(N) algorithm presented here: http://en.wikipedia.org/wiki/Maximum_subarray_problem
It doesn't actually give you the subarray, just the maximal value of the subarray.
Note the important restriction that the input array must contain at least one positive (nonzero) number.
I have modified it to return the range as well as the maximal value:
using System;
namespace Demo
{
public static class Program
{
public static void Main(string[] args)
{
//int[] numbers = new[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
//int[] numbers = new[] { 1, 1, 1, 1, 1, 1, 1, 1 };
int[] numbers = new[] {9, 1, 4, 15, -5, -41, -8, 78, 145, 14};
var result = FindMaximumSubarray(numbers);
Console.WriteLine("Range = {0}..{1}, Value = {2}", result.StartIndex, result.EndIndex, result.Value);
}
public static MaximumSubarray FindMaximumSubarray(int[] numbers)
{
int maxSoFar = numbers[0];
int maxEndingHere = numbers[0];
int begin = 0;
int startIndex = 0;
int endIndex = 0;
for (int i = 1; i < numbers.Length; ++i)
{
if (maxEndingHere < 0)
{
maxEndingHere = numbers[i];
begin = i;
}
else
{
maxEndingHere += numbers[i];
}
if (maxEndingHere > maxSoFar)
{
startIndex = begin;
endIndex = i;
maxSoFar = maxEndingHere;
}
}
return new MaximumSubarray
{
StartIndex = startIndex,
EndIndex = endIndex,
Value = maxSoFar
};
}
public struct MaximumSubarray
{
public int StartIndex;
public int EndIndex;
public int Value;
}
}
}
time complexity of your code is O(n^3), but you can improve it with two renovations and change it to O(N^2). but there is a better algorithm or this that designed by the dynamic programming.
this solution solve it in matrix array.
Note: maximum default value should be set to the infinite negative.
This is a code from the wiki:
A variation of the problem that does not allow zero-length subarrays to be returned in the case that the entire array consists of negative numbers can be solved with the following code, expressed here in C++ Programming Language.
int sequence(std::vector<int>& numbers)
{
// Initialize variables here
int max_so_far = numbers[0], max_ending_here = numbers[0];
size_t begin = 0;
size_t begin_temp = 0;
size_t end = 0;
// Find sequence by looping through
for(size_t i = 1; i < numbers.size(); i++)
{
// calculate max_ending_here
if(max_ending_here < 0)
{
max_ending_here = numbers[i];
begin_temp = i;
}
else
{
max_ending_here += numbers[i];
}
// calculate max_so_far
if(max_ending_here > max_so_far )
{
max_so_far = max_ending_here;
begin = begin_temp;
end = i;
}
}
return max_so_far ;
}
Divide-and-Conquer realization with O(N*logN) complexity was described in Inroduction to Algorithms: CLRS, Chapter 4 Divide-and-Conquer 4.1 The maximum-subarray problem. C# port from.
class Program {
static void Main(string[] args) {
int[] values = { 9, 1, 4, 15, -5, -41, -8, 78, 145, 14 };
Console.WriteLine(FindMaxSubarray(values, 0, values.Length - 1));
}
public struct MaxSubArray {
public int Low;
public int High;
public int Sum;
public override string ToString() {
return String.Format("From: {0} To: {1} Sum: {2}", Low, High, Sum);
}
}
private static MaxSubArray FindMaxSubarray(int[] a, int low, int high) {
var res = new MaxSubArray {
Low = low,
High = high,
Sum = a[low]
};
if (low == high) return res;
var mid = (low + high) / 2;
var leftSubarray = FindMaxSubarray(a, low, mid);
var rightSubarray = FindMaxSubarray(a, mid + 1, high);
var crossingSubarray = FindMaxCrossingSubarray(a, low, mid, high);
if (leftSubarray.Sum >= rightSubarray.Sum &&
leftSubarray.Sum >= crossingSubarray.Sum)
return leftSubarray;
if (rightSubarray.Sum >= leftSubarray.Sum &&
rightSubarray.Sum >= crossingSubarray.Sum)
return rightSubarray;
return crossingSubarray;
}
private static MaxSubArray FindMaxCrossingSubarray(int[] a, int low, int mid, int high) {
var maxLeft = 0;
var maxRight = 0;
var leftSubarraySum = Int32.MinValue;
var rightSubarraySum = Int32.MinValue;
var sum = 0;
for (var i = mid; i >= low; i--) {
sum += a[i];
if (sum <= leftSubarraySum) continue;
leftSubarraySum = sum;
maxLeft = i;
}
sum = 0;
for (var j = mid + 1; j <= high; j++) {
sum += a[j];
if (sum <= rightSubarraySum) continue;
rightSubarraySum = sum;
maxRight = j;
}
return new MaxSubArray {
Low = maxLeft,
High = maxRight,
Sum = leftSubarraySum + rightSubarraySum
};
}
}
Try this
static void Main()
{
try
{
int[] Values = { 9, 1, 4, 15, -5, -41, -8, 78, 145, 14 };//Will be executed once '1'
int max_ending_here = 0;
int max_so_far = 0;
foreach(int x in Values)
{
max_ending_here = Math.Max(0, max_ending_here + x);
max_so_far = Math.Max(max_so_far, max_ending_here);
}
Console.WriteLine("The Max Value is " + max_so_far);
Console.ReadKey();
}
catch { }
}
Reference Source
I am trying to solve my task using a List and I know I am very close to solving it but I am stuck now. Something is not ok in the code and I can not figure out what it is. Could you please take a look and help:
/*
Write a program that reads an array of integers and removes from it a minimal number of elements in such way that the
remaining array is sorted in increasing order. Print the remaining sorted array.
Example: {6, 1, 4, 3, 0, 3, 6, 4, 5} {1, 3, 3, 4, 5}
*/
using System;
using System.Collections.Generic;
class RemoveMinimalElements
{
static void Main()
{
int n;
n = int.Parse(Console.ReadLine());
List<int> arr = new List<int>();
List<int> sorted = new List<int>();
int maxSubsetLenght = 0;
for (int i = 0; i < n; i++)
{
arr.Add(int.Parse(Console.ReadLine()));
}
for (int i = 1; i <= (int)Math.Pow(2, n) - 1; i++)
{
int tempSubsetLenght = 0;
string tempString = "";
List<int> temp = new List<int>();
for (int j = 1; j <= n; j++)
{
int andMask = i & (1 << j);
int bit = andMask >> j;
if (bit == 1)
{
temp.Add(arr[n - 1 - j]);
tempSubsetLenght++;
}
if (tempSubsetLenght > maxSubsetLenght)
{
maxSubsetLenght = tempSubsetLenght;
for(int k =1; k < temp.Count; k ++)
{
if (temp[k] >= temp[k - 1])
{
sorted = temp;
}
}
}
}
}
for (int i = sorted.Count - 1; i > 0; i--)
{
Console.WriteLine(sorted[i]);
}
}
}
I didn't follow the code, I just tested your app.
This is my first input: 5.
Then I entered these 5 inputs 2,4,6,8,10 so
arr = {2,4,6,8,10};
And when it came to the last lines it gave me the ArguementOutOfRangeException (Index was out of range. Must be non-negative and less than the size of the collection.) because it was trying to fetch arr[item] and item is 6 so it's trying to fetch arr[6] which does not exist.
I don't know if an exhaustive search is suitable for your case, but will this work for you?
static void Main(string[] args)
{
int[] input = new[] { 6, 1, 4, 3, 0, 3, 6, 4, 5 };
int[] expectedOutput = new[] { 1, 3, 3, 4, 5 };
int[] solution = TryGetSolution(input);
Console.WriteLine("Input: " + FormatNumbers(input));
Console.WriteLine("Expected Output: " + FormatNumbers(expectedOutput));
Console.WriteLine("Output: " + FormatNumbers(solution));
Console.ReadLine();
}
private static string FormatNumbers(int[] numbers)
{
return string.Join(", ", numbers);
}
private static int[] TryGetSolution(int[] input)
{
return TryWithoutAnyItem(input);
}
private static int[] TryWithoutAnyItem(int[] items)
{
return Enumerable.Range(0, items.Length)
.Select(i => TryWithoutItem(items, i))
.Where(solution => solution != null)
.OrderByDescending(solution => solution.Length)
.FirstOrDefault();
}
private static int[] TryWithoutItem(int[] items, int withoutIndex)
{
if (IsSorted(items)) return items;
var removed = items.Take(withoutIndex).Concat(items.Skip(withoutIndex + 1));
return TryWithoutAnyItem(removed.ToArray());
}
private static bool IsSorted(IEnumerable<int> items)
{
return items.Zip(items.Skip(1), (a, b) => a.CompareTo(b)).All(c => c <= 0);
}
}
I solved it! Thank you very much for your support. I am a beginer and I am not able to use and understand more difficult stuff yet so here is what I did whit the things I already know:
/*
Write a program that reads an array of integers and removes from it a minimal number of elements in such way that the
remaining array is sorted in increasing order. Print the remaining sorted array.
Example: {6, 1, 4, 3, 0, 3, 6, 4, 5} {1, 3, 3, 4, 5}
*/
using System;
using System.Collections.Generic;
class RemoveMinimalElements
{
static bool CheckAscending(List<int> list)
{
bool ascending = true;
for (int i = 0; i < list.Count - 1; i++)
{
if (list[i] > list[i + 1])
{
ascending = false;
}
}
return ascending;
}
static void Main()
{
int n;
n = int.Parse(Console.ReadLine());
List<int> arr = new List<int>();
List<int> sorted = new List<int>();
int maxSubsetLenght = 0;
for (int i = 0; i < n; i++)
{
arr.Add(int.Parse(Console.ReadLine()));
}
for (int i = 1; i <= (int)Math.Pow(2, n) - 1; i++)
{
int tempSubsetLenght = 0;
List<int> temp = new List<int>();
for (int j = 1; j <= n; j++)
{
if (((i >> (j - 1)) & 1) == 1)
{
temp.Add(arr[j - 1]);
tempSubsetLenght++;
}
}
if ((tempSubsetLenght > maxSubsetLenght) && (CheckAscending(temp)))
{
sorted = temp;
maxSubsetLenght = tempSubsetLenght;
}
}
for (int i = 0; i < sorted.Count; i++)
{
Console.WriteLine(sorted[i]);
}
}
}
This works for me
private static void FindLongestRisingSequence(int[] inputArray)
{
int[] array = inputArray;
List<int> list = new List<int>();
List<int> longestList = new List<int>();
int highestCount = 1;
for (int i = 0; i < array.Length; i++)
{
list.Add(array[i]);
for (int j = i+1; j < array.Length; j++)
{
if (array[i] < array[j])
{
list.Add(array[j]);
i++;
}
else
{
break;
}
i = j;
}
// Compare with in previous lists
if (highestCount < list.Count)
{
highestCount = list.Count;
longestList = new List<int>(list);
}
list.Clear();
}
Console.WriteLine();
// Print list
Console.WriteLine("The longest subsequence");
foreach (int iterator in longestList)
{
Console.Write(iterator + " ");
}
Console.WriteLine();
}
I found quicksort algorithm from this book
This 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)
x=A[r]
i=p-1
for j = p to r - 1
if A <= x
i = i + 1
exchange A[i] with A[j]
exchange A[i+1] with A[r]
return i + 1
And I made this c# code:
private void quicksort(int[] input, int low, int high)
{
int pivot_loc = 0;
if (low < high)
pivot_loc = partition(input, low, high);
quicksort(input, low, pivot_loc - 1);
quicksort(input, pivot_loc + 1, high);
}
private int partition(int[] input, int low, int high)
{
int pivot = input[high];
int i = low - 1;
for (int j = low; j < high-1; j++)
{
if (input[j] <= pivot)
{
i++;
swap(input, i, j);
}
}
swap(input, i + 1, high);
return i + 1;
}
private void swap(int[] ar, int a, int b)
{
temp = ar[a];
ar[a] = ar[b];
ar[b] = temp;
}
private void print(int[] output, TextBox tbOutput)
{
tbOutput.Clear();
for (int a = 0; a < output.Length; a++)
{
tbOutput.Text += output[a] + " ";
}
}
When I call function like this quicksort(arr,0,arr.Length-1); I get this error An unhandled exception of type 'System.StackOverflowException' occurred it pass empty array... when call function like this quicksort(arr,0,arr.Length); I get error Index was outside the bounds of the array. on this line int pivot = input[high]; but array passed successfully.
I also want to print it like this print(input,tbQuick); but where to place it so it would print when quicksort finished?
You did not properly implement the base case termination, which causes quicksort to never stop recursing into itself with sublists of length 0.
Change this:
if (low < high)
pivot_loc = partition(input, low, high);
quicksort(input, low, pivot_loc - 1);
quicksort(input, pivot_loc + 1, high);
to this:
if (low < high) {
pivot_loc = partition(input, low, high);
quicksort(input, low, pivot_loc - 1);
quicksort(input, pivot_loc + 1, high);
}
In addition to Deestan's answer, you also have this wrong:
for (int j = low; j < high-1; j++)
It should be:
for (int j = low; j < high; j++)
Just in case you want some shorter code for Quicksort:
IEnumerable<int> QuickSort(IEnumerable<int> i)
{
if (!i.Any())
return i;
var p = (i.First() + i.Last) / 2 //whichever pivot method you choose
return QuickSort(i.Where(x => x < p)).Concat(i.Where(x => x == p).Concat(QuickSort(i.Where(x => x > p))));
}
Get p (pivot) with whatever method is suitable of course.
This is the shortest implementation of Quick Sort algorithm (Without StackOverflowException)
IEnumerable<T> QuickSort<T>(IEnumerable<T> i) where T :IComparable
{
if (!i.Any()) return i;
var p = i.ElementAt(new Random().Next(0, i.Count() - 1));
return QuickSort(i.Where(x => x.CompareTo(p) < 0)).Concat(i.Where(x => x.CompareTo(p) == 0)).Concat(QuickSort(i.Where(x => x.CompareTo(p) > 0)));
}
A Simple Quick Sort Implementation.
https://github.com/bharathkumarms/AlgorithmsMadeEasy/blob/master/AlgorithmsMadeEasy/QuickSort.cs
using System;
using System.Collections.Generic;
using System.Linq;
namespace AlgorithmsMadeEasy
{
class QuickSort
{
public void QuickSortMethod()
{
var input = System.Console.ReadLine();
string[] sInput = input.Split(' ');
int[] iInput = Array.ConvertAll(sInput, int.Parse);
QuickSortNow(iInput, 0, iInput.Length - 1);
for (int i = 0; i < iInput.Length; i++)
{
Console.Write(iInput[i] + " ");
}
Console.ReadLine();
}
public static void QuickSortNow(int[] iInput, int start, int end)
{
if (start < end)
{
int pivot = Partition(iInput, start, end);
QuickSortNow(iInput, start, pivot - 1);
QuickSortNow(iInput, pivot + 1, end);
}
}
public static int Partition(int[] iInput, int start, int end)
{
int pivot = iInput[end];
int pIndex = start;
for (int i = start; i < end; i++)
{
if (iInput[i] <= pivot)
{
int temp = iInput[i];
iInput[i] = iInput[pIndex];
iInput[pIndex] = temp;
pIndex++;
}
}
int anotherTemp = iInput[pIndex];
iInput[pIndex] = iInput[end];
iInput[end] = anotherTemp;
return pIndex;
}
}
}
/*
Sample Input:
6 5 3 2 8
Calling Code:
QuickSort qs = new QuickSort();
qs.QuickSortMethod();
*/
Code Implemented with Iteration With last element as Pivot
<code>https://jsfiddle.net/zishanshaikh/5zxvwoq0/3/ </code>
function quickSort(arr,l,u) {
if(l>=u)
{
return;
}
var pivot=arr[u];
var pivotCounter=l;
for(let i=l;i<u;i++)
{
if(arr[i] <pivot )
{
var temp= arr[pivotCounter];
arr[pivotCounter]=arr[i] ;
arr[i]=temp;
pivotCounter++;
}
}
var temp2= arr[pivotCounter];
arr[pivotCounter]=arr[u] ;
arr[u]=temp2;
quickSort(arr,pivotCounter+1,u);
quickSort(arr,0,pivotCounter-1);
}
<code>https://jsfiddle.net/zishanshaikh/exL9cdoe/1/</code>
Code With first element as Pivot
//Logic For Quick Sort
function quickSort(arr,l,u) {
if(l>=u)
{
return;
}
var pivot=arr[l];
var pivotCounter=l+1;
for(let i=l+1;i<u;i++)
{
if(arr[i] <pivot )
{
var temp= arr[pivotCounter];
arr[pivotCounter]=arr[i] ;
arr[i]=temp;
pivotCounter++;
}
}
var j=pivotCounter-1;
var k=l+1;
while(k<=j)
{
var temp2= arr[k-1];
arr[k-1]=arr[k] ;
arr[k]=temp2;
k++;
}
arr[pivotCounter-1]=pivot;
quickSort(arr,pivotCounter,u);
quickSort(arr,0,pivotCounter-2);
}
A simple generic C# implementation of QuickSort, can use first or last value or any other intermediate value for pivot
using System;
namespace QuickSort
{
class Program
{
static void Main(string[] args)
{
int[] arInt = { 6, 4, 2, 8, 4, 5, 4, 5, 4, 5, 4, 8, 11, 1, 7, 4, 13, 5, 45, -1, 0, -7, 56, 10, 57, 56, 57, 56 };
GenericQuickSort<int>.QuickSort(arInt, 0, arInt.Length - 1);
string[] arStr = { "Here", "Is", "A", "Cat", "Really", "Fast", "And", "Clever" };
GenericQuickSort<string>.QuickSort(arStr, 0, arStr.Length - 1); ;
Console.WriteLine(String.Join(',', arInt));
Console.WriteLine(String.Join(',', arStr));
Console.ReadLine();
}
}
class GenericQuickSort<T> where T : IComparable
{
public static void QuickSort(T[] ar, int lBound, int uBound)
{
if (lBound < uBound)
{
var loc = Partition(ar, lBound, uBound);
QuickSort(ar, lBound, loc - 1);
QuickSort(ar, loc + 1, uBound);
}
}
private static int Partition(T[] ar, int lBound, int uBound)
{
var start = lBound;
var end = uBound;
var pivot = ar[uBound];
// switch to first value as pivot
// var pivot = ar[lBound];
while (start < end)
{
while (ar[start].CompareTo(pivot) < 0)
{
start++;
}
while (ar[end].CompareTo(pivot) > 0)
{
end--;
}
if (start < end)
{
if (ar[start].CompareTo(ar[end]) == 0)
{
start++;
}
else
{
swap(ar, start, end);
}
}
}
return end;
}
private static void swap(T[] ar, int i, int j)
{
var temp = ar[i];
ar[i] = ar[j];
ar[j] = temp;
}
}
}
Output:
-7,-1,0,1,2,4,4,4,4,4,4,5,5,5,5,6,7,8,8,10,11,13,45,56,56,56,57,57
A,And,Cat,Clever,Fast,Here,Is,Really
One important thing to notice here is that this optimized and simple code properly handles duplicates. I tried several posted quick sort code. Those do not give correct result for this (integer array) input or just hangs, such as https://www.w3resource.com/csharp-exercises/searching-and-sorting-algorithm/searching-and-sorting-algorithm-exercise-9.php and http://www.softwareandfinance.com/CSharp/QuickSort_Iterative.html. Therefore, if author also wants to use the code which handles duplicates this would be a good reference.