Counting sort in singly-linked list C# - c#

Is there any way to make a counting sort in singly-linked list? I haven't seen any examples and it's quite hard to make it without them. I have example of it in array and would like to do it in singly-linked list.
Has anybody did it in singly-linked list?
public static int[] CountingSortArray(int[] array)
{
int[] aux = new int[array.Length];
// find the smallest and the largest value
int min = array[0];
int max = array[0];
for (int i = 1; i < array.Length; i++)
{
if (array[i] < min) min = array[i];
else if (array[i] > max) max = array[i];
}
int[] counts = new int[max - min + 1];
for (int i = 0; i < array.Length; i++)
{
counts[array[i] - min]++;
}
counts[0]--;
for (int i = 1; i < counts.Length; i++)
{
counts[i] = counts[i] + counts[i - 1];
}
for (int i = array.Length - 1; i >= 0; i--)
{
aux[counts[array[i] - min]--] = array[i];
}
return aux;
}

I found one that works on an array at: http://www.geeksforgeeks.org/counting-sort/
I think with minimal effort it could be changed to a linked list, the only problem is that you'll end up traversing the linked list many many times since you don't have random access eg.[] making it rather inefficient. Since you seem to have found the same thing i did before I could finish typing I think my answer is kinda pointless. However, I'm still a bit curious as to where you're having problems.
Heres a hint if figuring out where to start is the problem: Every time you see array[i] used, you will need to traverse your linked list first instead to get the i'th item first.
Edit: The only reason you would need to create a 2nd linked list of frequencies is if you needed to actually do work on the resulting linked list. If you just need a sorted list of the values inside the linked list for display purposes an array holding the frequencies would work (i suppose at the same time you could just create an array of all the values then do the counting sort you already have on it). I apologize if i have confused my c, c++, c++/cx, somewhere along the way (i don't have a compiler handy right now), but this should give you a good idea of how to do it.
public static node* FindMin(node* root){ //FindMax would be nearly identical
node* minValue = root;
while(node->Next){
if(node->Value < minValue->Value)
minValue = node;
}
return minValue;
}
public static node* CountingSortArray(node* linklist){
node* root = linkedlist
node* min = FindMin(linklist);
node* max = FindMax(linklist);
int[] counts = new int[max->Value - min->Value + 1];
while(root != NULL){
counts[root->Value] += 1;
root = root->Next;
}
int i = 0;
root = linkedlist;
while(ptr != NULL){
if(counts[i] == 0)
++i;
else{
root->Value = i;
--count[i];
root = root->Next;
}
}
}
void push(node** head, int new_data){
node* newNode = new node();
newNode->Value = new_data;
newNode->Next = (*head);
(*head) = newNode;
}
void printList(node* root){
while(root != NULL){
printf(%d ", root->Value);
root = root->Next;
}
printf("\n");
}
int main(void){
node* myLinkedList = NULL;
push(&head, 0);
push(&head, 1);
push(&head, 0);
push(&head, 2);
push(&head, 0);
push(&head, 2);
printList(myLinkedList);
CountingSortArray(myLinkedList);
printList(myLinkedList);
}

The example code is more like a radix sort with base (max-min+1). Usually a counting sort looks like the code below. Make a pass over the list to get min and max. Make a second pass to generate the counts. Make a pass over the counts to generate a new array based on the counts (instead of copying data). Example code fragment:
for (size_t i = 0; i < array.Length; i++)
counts[array[i]-min]++;
size_t i = 0;
for(size_t j = 0; j < counts.Length); j++){
for(size_t n = counts[j]; n; n--){
aux[i++] = j+min;
}
}

Related

Hello, I am trying to arrange an array from the small value to big value, but its not working

I am trying to arrange an array from the small value to grow, and for some reason this function does not work (SmallToGrow), the rest is excellent. Thanks.
There are auxiliary functions that I use and are excellent facts, only the (SmallToGrow) function does not work for me and I cannot understand why. I'd love anyone who can help. Thanks
enter code here
//this check if all cells equals
public bool EverybodyAreEqual(int [] array)
{
for (int i = 0; i < array.Length - 1; i++)
if (array[i] != array[i + 1])
return false;
return true;
}
//This function changes all the values ​​in the array that contain the -numInArray- value you entered,
// to the -numChanged- value you entered
public void ChangNumWhere(ref int [] array,int numInArray,int numChanged)
{
for (int i = 0; i < array.Length; i++)
if (array[i] == numInArray)
array[i] = numChanged;
}
//A function that returns the number of values ​​that are not equal in the array
public int NumDifferentArray(int [] array)
{
int[] arr = new int[array.Length];
for (int i = 0; i < arr.Length; i++)
arr[i] = array[i];
bool con = true;
int contain = 0;
int index = 0;
for(int i=0; con;i++)
{
if (!arr.Contains(i))
{
contain = i;
con = false;
}
}
while(!this.EverybodyAreEqual(arr))
{
for (int i = 0; i < arr.Length; i++)
if (arr[i] != contain)
{
this.ChangNumWhere(ref arr, arr[i], contain);
index++;
}
}
return index;
}
public int HowTimesExsist(int [] array,int num)
{
int index = 0;
for(int i=0;i<array.Length;i++)
{
if (array[i] == num)
index++;
}
return index;
}
/// This function returns a minimum value as required,
/// for example if you requested 0 the smallest value is returned,
/// if 1 is returned one above it and so on,
/// if the index is greater than the length of the array the largest number is returned
public int MinBottom(int[] array, int num)
{
if (num < 0)
throw new Exception("num canot be less then 0");
int max = this.MaxArray(array);
while (num > 0)
{
int min = this.MinArray(array);
for (int i = 0; i < array.Length; i++)
if(array[i]==min)
array[i] = max;
num--;
}
return this.MinArray(array);
}
public int[] SmallToGrow(int [] array)
{
int i = 0;
int[] arr = new int[array.Length];
for (int j = 0; j < this.NumDifferentArray(array); j++)
for (int b = 0; b < this.HowTimesExsist(array, MinBottom(array, j)); i++, b++)
arr[i] = this.MinBottom(array, j);
return arr;
}
Why don't you use a list instead? They have a method attached to it that sorts it all for you.
List<int> sortInt = new List<int>() { 2, 5, 1, 50, 258, 87, 63, 52, 100, 85, 21 };
sortInt.Sort();
Returned them in numerical order with [0] being 1 and [10] being 258.
you can then turn the list to an array with sortint.ToArray();.
Edit
As dymanoid mentioned you can just use your array and just run the array.Sort() method with it. Learn something new every day.
It looks like you are in large part re-engineering some common functionality in System.Collections.Generic and System.Linq -
public bool EverybodyAreEqual(int[] array)
{
// If all items are the same,
// there should only be one distinct item in the collection
return array.Distinct().Length == 1;
}
public int NumDifferentArray(int[] array)
{
// Group the numbers in the array and
// count the number of groups with only one item
return array.GroupBy(number => number).Where(g => g.Count() == 1);
}
public int HowTimesExsist(int[] array, int num)
{
// Count the number of times a number appears in the array
return array.Count(n => n == num);
}
/// This function returns a minimum value as required,
/// for example if you requested 0 the smallest value is returned,
/// if 1 is returned one above it and so on,
/// if the index is greater than the length of the array the largest number is returned
public int MinBottom(int[] array, int num)
{
if (num < 0)
{
// Be specific about the type of exception you are throwing
throw new ArgumentOutOfRangeException(nameof(num));
}
// Sort a copy of your array
var sorted = Array.Copy(array);
Array.Sort(sorted);
// If there are any items over the specified minimum, return those
// otherwise, return the highest number in the array
// Using LastOrDefault for the maximum will return 0 if the initial array is empty
var itemsOverMinimum = sorted.Where(n => n >= num);
return itemsOverMinimum.Any() ? itemsOverMinimum.First() : sorted.LastOrDefault();
}
public int[] SmallToGrow(int[] array)
{
// Because you are returning an array, that implies that the original array should not change
// Copy the array and sort it
var copy = Array.Copy(array);
Array.Sort(copy);
return copy;
}
I saw that you mentioned that you are trying to find alternative ways to accomplish some of these things, and I want to give you some advice about that.
I think it's pretty cool that you want to challenge yourself. However, this specific functionality is part of System libraries. One of the best parts about working in C# is how much of this sort of thing is already written for you, and this functionality being added to System means that Microsoft believes these pieces are the core (pun intended) building blocks for working in .NET.
Unless your project is to specifically write a better sorting algorithm, you are not going to write this better than it is in those libraries. I've been doing this for a while, and I'm not going to be able to either.
But that doesn't mean you should stop learning. Instead, I would encourage you to look at the github source for the methods I used in my snippets above. I think that will probably be a lot more helpful than re-engineering this stuff from scratch.
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/Distinct.cs
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/Grouping.cs
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/Where.cs
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/Count.cs

Write a program to find an index of Max item in an array

Write a console app in C# to find an index i in an array that is the maximum number in the array.
If the maximum element in the array occurs several times, you need to display the minimum index.
If the array is empty, output -1.
Please let me know what is wrong in my code?
If I input the array a = { 1, 2, 46, 14, 64, 64 };, for instance, it returns 0, while it should be returning 4.
public static void Main()
{
double[] a = { 1, 9, 9, 8, 9, 2, 2 };
Console.WriteLine(MaxIndex(a));
}
public static double MaxIndex(double[] array)
{
var max = double.MinValue;
int maxInd = 0, maxCount = 0;
int minIndex = 0;
var min = double.MaxValue;
for (var i = 0; i < array.Length; i++)
{
if (min > array[i])
{
min = array[i];
minIndex = i;
}
if (max == array[i])
maxCount++;
if (max < array[i])
{
maxCount = 1;
max = array[i];
maxInd = i;
}
}
if (array.Length == 0)
return -1;
if (maxCount > 1)
return minIndex;
return maxInd;
}
Your calculation is correct, but you return the wrong variable minIndex instead of maxIndex. Don't do more than necessary in a method. This calculates also the min-index and the count how often it appears, then it does nothing with the results. Here is a compact version:
public static int MaxIndex(double[] array)
{
var max = double.MinValue;
int maxInd = -1;
for (int i = 0; i < array.Length; i++)
{
if (max < array[i])
{
max = array[i];
maxInd = i;
}
}
return maxInd;
}
It also sets maxInd = -1 which was part of your requirement. Since MatthewWatson had an objection regarding repeating double.MinValue in the array, here is an optimized version:
public static int MaxIndex(double[] array)
{
if(array.Length == 0)
return -1;
else if (array.Length == 1)
return 0;
double max = array[0];
int maxInd = 0;
for (int i = 1; i < array.Length; i++)
{
if (max < array[i])
{
max = array[i];
maxInd = i;
}
}
return maxInd;
}
If code-readability/maintainability is more important and you don't care of few milliseconds more or less, you could use LINQ (a version that enumerates only once):
int minIndexOfMaxVal = a.Select((num, index) => new {num, index})
.OrderByDescending(x => x.num)
.Select(x => x.index)
.DefaultIfEmpty(-1)
.First();
This works with every kind of sequence and types not only with arrays and doubles.
Try this simple line of code:
int[] numbers = { 1, 2, 3, 4, 5, 4, 3, 2, 1 };
var index = numbers.ToList().IndexOf(numbers.Max());
I think code is simple enough to be self-explanatory.
However, if you aim for performance, conversion to List could be omitted and you could wirte own code to find index of maximum number.
Or even simplier, proposed by #fubo:
Array.IndexOf(numbers, numbers.Max());
A lot of simplification is possible in this code:
int? maxVal = null; // null because of array of negative value;
int index = -1;
for (int i = 0; i < array.Length; i++)
{
int current = array[i];
if (!maxVal.HasValue || current > maxVal.Value)
{
maxVal = current ;
index = i;
}
}
Will get you the first index of the max value. If you just need a short code and Don't mind iterating twice a simple linq can do the trick
var index = array.ToList().IndexOf(array.Max());
It returns zero, because minIndex is indeed zero:
Change minIndex to maxIndex:
if (maxCount > 1) return maxIndex;
In order to compare doubles use the following code instead of ==:
if (Math.Abs(a-b)<double.Epsilon)
Your code in general is way too complicated with way too many variables for what it has to do.
You want the index of the first occurence of the highest value, so there isn't any real reason to store anything but a MaxValueIndex and a MaxValue.
All other variables should be local so garbage collection can dispose of them.
As for what is actually wrong with your code, I can't help out, since the variable names are confusing to me.
But here is some code that achieves the goal you want to achieve.
double[] a = { 1, 9, 9, 8, 9, 2, 2 };
var highestValueInArray = a.Max();
var arrayLength = a.Length;
for (int i = 0; i < arrayLength; i++)
{
if (a[i] == highestValueInArray)
{
Console.WriteLine(i);
break;
}
}
instead of manually calculating the max value, you can just use YourArray.Max() to get the highest value.
then just iterate through it like normal, but at the first occurence, you break; out of the loop and return the index it is at.
I'm pretty sure there's also a way to use FirstOrDefault in combination with IndexOf, but couldn't get that to work myself.

Almost Ordered not sorting the exact amount of values i give it

this is a really easy question but i cant figure out a way around it. Apparently the almost ordered has a bug that it might randomize a little bit more than you ask it. the code is rather simple:
public void Section1Task1AlmostOrdered(int arraySize, int percentage)
{
int[] testArray = new int[arraySize];
Console.WriteLine("Ordered List: ");
for (int i = 1; i <= testArray.Length; i++)
{
testArray[i-1] = i;
Console.Write(i + "\t");
}
Console.WriteLine("Almost Ordered List: ");
testArray = shuffler.AlmostOrdered(arraySize, percentage);
for (int i = 0; i < testArray.Length; i++)
{
Console.Write(testArray[i] + "\t");
}
}
The shuffler is this part of the code:
public int[] AlmostOrdered(int n, double p)
{
if (p > 100)
{
throw new InvalidOperationException("Cannot shuffle more than 100% of the numbers");
}
int shuffled = 0;
//Create and Populate an array
int[] array = new int[n];
for(int i = 1; i <= n; i++)
{
array[i-1] = i;
}
//Calculate numbers to shuffle
int numsOutOfPlace = (int) Math.Ceiling(n * (p / 100));
int firstRandomIndex = 0;
int secondRandomIndex = 0;
do
{
firstRandomIndex = this.random.Next(n-1);
// to make sure that the two numbers are not the same
do
{
secondRandomIndex = this.random.Next(n - 1);
} while (firstRandomIndex == secondRandomIndex);
int temp = array[firstRandomIndex];
array[firstRandomIndex] = array[secondRandomIndex];
array[secondRandomIndex] = temp;
shuffled++;
}
while (shuffled < numsOutOfPlace);
return array;
}
When i enter values 10 for array size and 40 for percentage to be shuffled, it is shuffling 5 numbers instead of 4. Is there a way to perfect this method to make it more accurate?
Likely the problem is with the calculation:
int numsOutOfPlace = (int)Math.Ceiling(n * (p / 100));
So if p=40 and n=10, then in theory you should get 4. But you're dealing with floating point numbers. So if (p/100) returns 0.400000000001, then the result will be 4.000000001, and Math.Ceiling will round that up to 5.
You might want to replace Math.Ceiling with Math.Round and see how that works out.

c# - Binary search algorithm random generated array items not working

I have implemented binary search algorithm in a console window application in C#. I am generating random values to the array and sorting them using Random() and Array.Sort() functions respectively.
The Problem - No matter what Key(item to be searched in the array) I give, the program is returning Key not found when the array items are generated using Random function
This does not happen if I enter the array elements manually using Console.ReadLine().
TLDR: Binary Search algorithm works fine when array items are entered manually, but does not work when array items are generated using Random function.
Can anyone point out what is the mistake I am doing?
My code - Random Generated array items.
namespace BSA
{
class Program
{
static void Main(string[] args)
{
var arr = new int[10];
Random rnd = new Random();
for (int i = 0; i < arr.Length; i++)
{
arr[i] = rnd.Next(1, 1000);
}
Array.Sort(arr);
for (int i = 0; i < arr.Length; i++)
{
Console.Write("{0}\n", i);
}
while (true)
{
Console.WriteLine("Enter the number to be searched in the array.");
var searchItem = Convert.ToInt32(Console.ReadLine());
var foundPos = Search(arr, searchItem);
if (foundPos > 0)
{
Console.WriteLine("Key {0} found at position {1}", searchItem, foundPos);
}
else
{
Console.WriteLine("Key {0} not found", searchItem);
}
}
}
public static int Search(int[] arr, int item)
{
var min = 0;
var N = arr.Length;
var max = N - 1;
int basicOperations = 0;
basicOperations++;
do
{
var mid = (min + max)/2;
if (arr[mid] == item)
return mid;
if (item < arr[mid])
max = mid - 1;
else
min = mid + 1;
basicOperations++;
} while (min <= max);
return basicOperations;
}
}
}
Please let me know if I am doing any silly mistake or I am committing a blunder in the above code. Any help would be really helpful.
Your search code works fine as far as I can see. However when you list the contents of the random array, you should write arr[i] rather than i to see what's in the array so you can pick a search value in it. Alternatively, pass arr[x] as the search item. It should return x.
Your code works correctly. You're just not looking for the right keys. The function that prints the values generated into the array prints the loop counter instead:
for (int i = 0; i < arr.Length; i++)
{
Console.Write("{0}\n", i);
}
You need to change it to:
for (int i = 0; i < arr.Length; i++)
{
Console.Write("{0}\n", arr[i]);
}
This will show you the values actually generated.
Comment too short for this so added answer to show how to set basicOperations and still return search position. You declare basicOperations as an out parameter which means the method can change it so the caller can see it when method returns.
public static void Main(string[] args)
{
... ... ...
int basicOperations;
int searchPos = IntArrayBinarySearch(arr, arr[5], out basicOperations);
Console.WriteLine("Found at {0} basic ops={1}", searchPos, basicOperations);
}
public static int IntArrayBinarySearch(int[] data, int item, out int basicOperations)
{
var min = 0;
var N = data.Length;
var max = N - 1;
basicOperations = 0;
basicOperations++;
and at bottom, you don't need to return out parameters, just return -1 to indicate failure as you did before
return -1;

Counting sort - implementation differences

I heard about Counting Sort and wrote my version of it based on what I understood.
public void my_counting_sort(int[] arr)
{
int range = 100;
int[] count = new int[range];
for (int i = 0; i < arr.Length; i++) count[arr[i]]++;
int index = 0;
for (int i = 0; i < count.Length; i++)
{
while (count[i] != 0)
{
arr[index++] = i;
count[i]--;
}
}
}
The above code works perfectly.
However, the algorithm given in CLRS is different. Below is my implementation
public int[] counting_sort(int[] arr)
{
int k = 100;
int[] count = new int[k + 1];
for (int i = 0; i < arr.Length; i++)
count[arr[i]]++;
for (int i = 1; i <= k; i++)
count[i] = count[i] + count[i - 1];
int[] b = new int[arr.Length];
for (int i = arr.Length - 1; i >= 0; i--)
{
b[count[arr[i]]] = arr[i];
count[arr[i]]--;
}
return b;
}
I've directly translated this from pseudocode to C#. The code doesn't work and I get an IndexOutOfRange Exception.
So my questions are:
What's wrong with the second piece of code ?
What's the difference algorithm wise between my naive implementation and the one given in the book ?
The problem with your version is that it won't work if the elements have satellite data.
CLRS version would work and it's stable.
EDIT:
Here's an implementation of the CLRS version in Python, which sorts pairs (key, value) by key:
def sort(a):
B = 101
count = [0] * B
for (k, v) in a:
count[k] += 1
for i in range(1, B):
count[i] += count[i-1]
b = [None] * len(a)
for i in range(len(a) - 1, -1, -1):
(k, v) = a[i]
count[k] -= 1
b[count[k]] = a[i]
return b
>>> print sort([(3,'b'),(2,'a'),(3,'l'),(1,'s'),(1,'t'),(3,'e')])
[(1, 's'), (1, 't'), (2, 'a'), (3, 'b'), (3, 'l'), (3, 'e')]
It should be
b[count[arr[i]]-1] = arr[i];
I'll leave it to you to track down why ;-).
I don't think they perform any differently. The second just pushes the correlation of counts out of the loop so that it's simplified a bit within the final loop. That's not necessary as far as I'm concerned. Your way is just as straightforward and probably more readable. In fact (I don't know about C# since I'm a Java guy) I would expect that you could replace that inner while-loop with a library array fill; something like this:
for (int i = 0; i < count.Length; i++)
{
arrayFill(arr, index, count[i], i);
index += count[i];
}
In Java the method is java.util.Arrays.fill(...).
The problem is that you have hard-coded the length of the array that you are using to 100. The length of the array should be m + 1 where m is the maximum element on the original array. This is the first reason that you would think using counting-sort, if you have information about the elements of the array are all minor that some constant and it would work great.

Categories

Resources