Why can't I Selection Sort this library? - c#

I'm trying to use Selection Sort for a library of books so that it sorts them alphabetically, however I can't get it to work.
SelectionSort(library); doesn't work but SelectionSort(titles); does, any ideas? Thanks :)
Here is the full code:
using System;
using System.Collections.Generic;
using System.Text;
namespace BookSortingEx
{
class Program
{
static void swap<T>(ref T x, ref T y)
{
//swapcount++;
T temp = x;
x = y;
y = temp;
}
static void printArray(string[] a)
{
for (int i = 0; i < a.Length; i++)
{
Console.Write(a[i] + ",");
}
Console.WriteLine();
}
static bool IsInOrder<T>(T[] a) where T : IComparable
{
for (int i = 0; i < a.Length - 1; i++)
{
if (a[i].CompareTo(a[i + 1]) > 0)
return false;
}
return true;
}
static void Main(string[] args)
{
string[] array1 = { "Fred", "Zoe", "Angela", "Umbrella", "Ben" };
string[] titles = {"Writing Solid Code",
"Objects First","Programming Gems",
"Head First Java","The C Programming Language",
"Mythical Man Month","The Art of Programming",
"Coding Complete","Design Patterns",
"Problem Solving in Java"};
string[] authors = { "Maguire", "Kolling", "Bentley", "Sierra", "Richie", "Brooks", "Knuth", "McConnal", "Gamma", "Weiss" };
string[] isbns = { "948343", "849328493", "38948932", "394834342", "983492389", "84928334", "4839455", "21331322", "348923948", "43893284", "9483294", "9823943" };
Book[] library = new Book[10];
for (int i = 0; i < library.Length; i++)
{
library[i] = new Book(isbns[i], titles[i], authors[i]);
}
**DOESNT WORK - // SelectionSort(library);**
SelectionSort(titles);
printArray(titles);
foreach (Book book in library)
{
Console.WriteLine(" {0} ", book);
}
Console.WriteLine();
Console.ReadKey();
}
static public void SelectionSort(string[] a)
{
for (int i = 0; i < a.Length - 1; i++)
{
int smallest = i;
for (int j = i + 1; j < a.Length; j++)
{
if (a[j].CompareTo(a[smallest]) < 0)
smallest = j;
}
swap(ref a[i], ref a[smallest]);
}
}
}
}

Your method expects a string[], but you're giving it a Book[]
You'll want to change the implementation of SelectionSort to support Comparable Collections, as well as have Book implement the IComparable interface.
public class Book : IComparable
{
// Implementation
public int CompareTo(Book otherBook)
{
// Implementation
}
}
static public void SelectionSort<T>(IList<T> a) where T : IComparable
{
// Implementation
}
The advantage of this approach, is that you won't have to create a different version of SelectionSort for every kind of object collection you'll want to sort.

Because SelectionSort takes as an argument an array of type string and you are passing it an array of type Book. SelectionSort(titles) works because titles is an array of type string.
You need to write a method that takes an array of type Book
static public void SelectionSort(Book[] books)
and if you haven't done this already you probably need to define a CompareTo method in your Book class, so your sorting algorithm can figure out how to sort books.

Related

Return all powers of 2 less then n in C# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
For a given number n, I need to return all powers of 2 less than n, as a string in a way that elements are separated with "-". If n < 2, it needs to return an empty string.
For example:
n = 20 => 1-2-4-8-16
n = 8 => 1-2-4
I'm a beginner, so any help would be much appreciated! :)
EDIT: this is not working
using System;
class N
{
static int[] powerof2(int n)
{
int[] array = new int[n];
if (n < 2)
return new int[0];
for (int i = 0; i < 8 * sizeof(uint); i++)
{
int curr = 1 << i;
if (curr > n)
break;
array[i] = curr;
}
return array;
public override string ToString()
{
for (int i = 0; i < array.length; i++)
return (array[i] + "-");
}
}
static public void Main ()
{
int n = 10;
Console.WriteLine(powerof2(n).ToString());
}
}
You need to run the for loop with the following rule
for (int i = 1; i < n; i *= 2)
Whole solution
class Program
{
static void powerof2(int n)
{
if (n < 2)
Console.WriteLine(string.Empty);
for (int i = 1; i < n; i *= 2)
{
if (i > 1)
Console.Write("-");
Console.Write(i);
}
}
static void Main(string[] args)
{
powerof2(20);
}
Using iterator methods makes this case trivial (Fiddle):
using System;
using System.Collections.Generic;
public class Program
{
public static IEnumerable<int> GetPowersOf2(int maxN)
{
for (int p = 1; p < maxN; p *= 2)
{
yield return p;
}
}
public static void Main(string[] args)
{
IEnumerable<int> powersOf2LessThan20 = GetPowersOf2(20);
Console.WriteLine(string.Join("-", powersOf2LessThan20));
}
}
I suppose this is what you're looking for:
class Program
{
public static string Pow2LessThan(ulong n)
{
if (n < 2)
return "";
// start with 2^0
string res = "1";
// try further
int p = 1;
ulong cnum = 2;
while (cnum < n)
{
res += "-" + cnum.ToString();
++p;
cnum = (ulong)(1 << p);
}
return res;
}
static void Main(string[] args)
{
ulong n = 20;
Console.WriteLine(Pow2LessThan(n));
Console.ReadLine();
}
}
The reason that it's not working is: you never access the class N in any way. The call should be
Console.WriteLine(N.powerof2(n).ToString());
^^
With that modification, you'll be notified that the method powerof2() is inaccessible due to its protection level. You need to make it at least internal like so:
internal static int[] powerof2(int n)
Next, note that you're missing a } for that method.
return array;
}
With that fixed, the compiler will tell you that you can't access array inside ToString(), because the scope of array is limited to powerof2(). Make the array a field of the class like
static int[] array;
Now, the compiler complains about array.length in ToString(). Fix that by capitalizing Length.
Mistake number 6: ToString() will return in the first iteration of the loop. It will not return anything if array.Length is 0. The function should look a little bit like this:
public override string ToString()
{
string result = "";
for (int i = 0; i < array.Length; i++)
result += array[i] + "-";
return result;
}
Now, this will still not work, because the main method calls ToString() on the return value of powerof2(), which is of type int[] and not of type N. That's because your stuff is static. Make it non-static instead and create an instance of N.
static public void Main ()
{
var n = new N();
n.powerof2(10);
Console.WriteLine(n.ToString());
}
With 7 issues fixed, the output is now 1-2-4-8-0-0-0-0-0-0-, so there's still stuff to fix. Maybe you get a little bit of a feeling why everyone proposes a totally different solution.
What else to fix:
the output of course is still incorrect.
if someone inputs 4000000000 as the number, you certainly don't want to allocate 4 GB of RAM in the array.
Why allocate an array at all and not construct the string right away?
Why 8*sizeof(uint)? You can't shift more often than sizeof(uint).
class Program
{
static string powerof2(int n)
{
var str="1" ;
if (n < 2)
return "" ;
else
{
var i=1;
while(Math.Pow(i, 2)<n)
{
str+="-" +Math.Pow(2, i);
i++;
}
return str;
}
}
static void Main(string[] args)
{
powerof2(50);
}
}

c# comparing list of IDs

I have a List<Keyword> where Keyword class is:
public string keyword;
public List<int> ids;
public int hidden;
public int live;
public bool worked;
Keyword has its own keyword, a set of 20 ids, live by default is set to 1 and hidden to 0.
I just need to iterate over the whole main List to invalidate those keywords whose number of same ids is greater than 6, so comparing every pair, if the second one has more than 6 ids repeated respect to the first one, hidden is set to 1 and live to 0.
The algorithm is very basic but it takes too long when the main list has many elements.
I'm trying to guess if there could be any method I could use to increase the speed.
The basic algorithm I use is:
foreach (Keyword main_keyword in lista_de_keywords_live)
{
if (main_keyword.worked) {
continue;
}
foreach (Keyword keyword_to_compare in lista_de_keywords_live)
{
if (keyword_to_compare.worked || keyword_to_compare.id == main_keyword.id) continue;
n_ids_same = 0;
foreach (int id in main_keyword.ids)
{
if (keyword_to_compare._lista_models.IndexOf(id) >= 0)
{
if (++n_ids_same >= 6) break;
}
}
if (n_ids_same >= 6)
{
keyword_to_compare.hidden = 1;
keyword_to_compare.live = 0;
keyword_to_compare.worked = true;
}
}
}
The code below is an example of how you would use a HashSet for your problem. However, I would not recommend using it in this scenario. On the other hand, the idea of sorting the ids to make the comparison faster still.
Run it in a Console Project to try it out.
Notice that once I'm done adding new ids to a keyword, I sort them. This makes the comparison faster later on.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace KeywordExample
{
public class Keyword
{
public List<int> ids;
public int hidden;
public int live;
public bool worked;
public Keyword()
{
ids = new List<int>();
hidden = 0;
live = 1;
worked = false;
}
public override string ToString()
{
StringBuilder s = new StringBuilder();
if (ids.Count > 0)
{
s.Append(ids[0]);
for (int i = 1; i < ids.Count; i++)
{
s.Append(',' + ids[i].ToString());
}
}
return s.ToString();
}
}
public class KeywordComparer : EqualityComparer<Keyword>
{
public override bool Equals(Keyword k1, Keyword k2)
{
int equals = 0;
int i = 0;
int j = 0;
//based on sorted ids
while (i < k1.ids.Count && j < k2.ids.Count)
{
if (k1.ids[i] < k2.ids[j])
{
i++;
}
else if (k1.ids[i] > k2.ids[j])
{
j++;
}
else
{
equals++;
i++;
j++;
}
}
return equals >= 6;
}
public override int GetHashCode(Keyword keyword)
{
return 0;//notice that using the same hash for all keywords gives you an O(n^2) time complexity though.
}
}
class Program
{
static void Main(string[] args)
{
List<Keyword> listOfKeywordsLive = new List<Keyword>();
//add some values
Random random = new Random();
int n = 10;
int sizeOfMaxId = 20;
for (int i = 0; i < n; i++)
{
var newKeyword = new Keyword();
for (int j = 0; j < 20; j++)
{
newKeyword.ids.Add(random.Next(sizeOfMaxId) + 1);
}
newKeyword.ids.Sort(); //sorting the ids
listOfKeywordsLive.Add(newKeyword);
}
//solution here
HashSet<Keyword> set = new HashSet<Keyword>(new KeywordComparer());
set.Add(listOfKeywordsLive[0]);
for (int i = 1; i < listOfKeywordsLive.Count; i++)
{
Keyword keywordToCompare = listOfKeywordsLive[i];
if (!set.Add(keywordToCompare))
{
keywordToCompare.hidden = 1;
keywordToCompare.live = 0;
keywordToCompare.worked = true;
}
}
//print all keywords to check
Console.WriteLine(set.Count + "/" + n + " inserted");
foreach (var keyword in set)
{
Console.WriteLine(keyword);
}
}
}
}
The obvious source of inefficiency is the way you calculate intersection of two lists (of ids). The algorithm is O(n^2). This is by the way problem that relational databases solve for every join and your approach would be called loop join. The main efficient strategies are hash join and merge join. For your scenario the latter approach may be better I guess, but you can also try HashSets if you like.
The second source of inefficiency is repeating everything twice. As (a join b) is equal to (b join a), you do not need two cycles over the whole List<Keyword>. Actually, you only need to loop over the non duplicate ones.
Using some code from here, you can write the algorithm like:
Parallel.ForEach(list, k => k.ids.Sort());
List<Keyword> result = new List<Keyword>();
foreach (var k in list)
{
if (result.Any(r => r.ids.IntersectSorted(k.ids, Comparer<int>.Default)
.Skip(5)
.Any()))
{
k.hidden = 1;
k.live = 0;
k.worked = true;
}
else
{
result.Add(k);
}
}
If you replace the linq with just the index manipulation approach (see the link above), it would be a tiny bit faster I guess.

Comparing Generic Values

So i wanted to make a generic method that makes you an array with a specific length that you insert into and it sorts it at the same time.
so i was transfering it from int to generic T and i stumbled into a problem while trying to compare 2 variables of T.
this is the code so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication7
{
class Program
{
public static T[] insertWhileSorting<T>(int x)
{
T[] arr = new T[x];
for (int i = 0, k; i < arr.Length; i++)
{
T value = (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
for (k = i; k > 0 && value.CompareTo(arr[k - 1]) < 0; --k) arr[k] = arr[k - 1];
arr[k] = value;
}
return arr;
}
static void Main(string[] args)
{
int[] arr = insertWhileSorting<int>(5);
Console.WriteLine(string.Join(", ", arr));
}
}
}
and yes i know(i think)that simply inserting the values into an array and then sorting it is better but i'm doing it for an assignment
You would need to assert that the type T as implemented IComparable<T>. Using the where key word you can restrict the type T with a condition that T has to implement IComparable<T>:
public static T[] insertWhileSorting<T>(int x) where T: IComparable<T>
IComparable demands that the class in question implements the method CompareTo. Now the compiler should stop complaining that
"T" does not contain a definition for "CompareTo" and cannot find an extension method "CompareTo"
EDIT:
this line can get you easily into trouble:
T value = (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
because the user can type simply a string like "break" which would result in an FormatException if you initially called it like this:
int [] adda = insertWhileSorting<int>(5);
You can put this whole conversion and sorting routine into a try catch clause and give a warning when it crashes:
for (int i = 0, k; i < arr.Length; i++)
{
try
{
T value = (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
for (k = i; k > 0 && value.CompareTo(arr[k - 1]) < 0; --k) arr[k] = arr[k - 1];
arr[k] = value;
}
catch (Exception ex)
{
Console.WriteLine("That stuff was not convertible!");
Console.WriteLine("Error: " + ex.Message);
}
}

How can I make my trie more efficient?

I'm working on a hacker rank problem and I believe my solution is correct. However, most of my test cases are being timed out. Could some one suggest how to improve the efficiency of my code?
The important part of the code starts at the "Trie Class".
The exact question can be found here: https://www.hackerrank.com/challenges/contacts
using System;
using System.Collections.Generic;
using System.IO;
class Solution
{
static void Main(String[] args)
{
int N = Int32.Parse(Console.ReadLine());
string[,] argList = new string[N, 2];
for (int i = 0; i < N; i++)
{
string[] s = Console.ReadLine().Split();
argList[i, 0] = s[0];
argList[i, 1] = s[1];
}
Trie trie = new Trie();
for (int i = 0; i < N; i++)
{
switch (argList[i, 0])
{
case "add":
trie.add(argList[i, 1]);
break;
case "find":
Console.WriteLine(trie.find(argList[i, 1]));
break;
default:
break;
}
}
}
}
class Trie
{
Trie[] trieArray = new Trie[26];
private int findCount = 0;
private bool data = false;
private char name;
public void add(string s)
{
s = s.ToLower();
add(s, this);
}
private void add(string s, Trie t)
{
char first = Char.Parse(s.Substring(0, 1));
int index = first - 'a';
if(t.trieArray[index] == null)
{
t.trieArray[index] = new Trie();
t.trieArray[index].name = first;
}
if (s.Length > 1)
{
add(s.Substring(1), t.trieArray[index]);
}
else
{
t.trieArray[index].data = true;
}
}
public int find(string s)
{
int ans;
s = s.ToLower();
find(s, this);
ans = findCount;
findCount = 0;
return ans;
}
private void find(string s, Trie t)
{
if (t == null)
{
return;
}
if (s.Length > 0)
{
char first = Char.Parse(s.Substring(0, 1));
int index = first - 'a';
find(s.Substring(1), t.trieArray[index]);
}
else
{
for(int i = 0; i < 26; i++)
{
if (t.trieArray[i] != null)
{
find("", t.trieArray[i]);
}
}
if (t.data == true)
{
findCount++;
}
}
}
}
EDIT: I did some suggestions in the comments but realized that I can't replace s.Substring(1) with s[0]... because I actually need s[1..n]. AND s[0] returns a char so I'm going to need to do .ToString on it anyways.
Also, to add a little more information. The idea is that it needs to count ALL names after a prefix for example.
Input: "He"
Trie Contains:
"Hello"
"Help"
"Heart"
"Ha"
"No"
Output: 3
I could just post a solution here that gives you 40 points but i guess this wont be any fun.
Make use of Enumerator<char> instead of any string operations
Count while adding values
any charachter minus 'a' makes a good arrayindex (gives you values between 0 and 25)
I think, this link must be very helpfull
There, you can find the good implementation of a trie data structure, but it's a java implementation. I implemented trie on c# with that great article one year ago, and i tried to find solution to an another hackerrank task too ) It was successful.
In my task, i had to a simply trie (i mean my alphabet equals 2) and only one method for adding new nodes:
public class Trie
{
//for integer representation in binary system 2^32
public static readonly int MaxLengthOfBits = 32;
//alphabet trie size
public static readonly int N = 2;
class Node
{
public Node[] next = new Node[Trie.N];
}
private Node _root;
}
public void AddValue(bool[] binaryNumber)
{
_root = AddValue(_root, binaryNumber, 0);
}
private Node AddValue(Node node, bool[] val, int d)
{
if (node == null) node = new Node();
//if least sagnificient bit has been added
//need return
if (d == val.Length)
{
return node;
}
// get 0 or 1 index of next array(length 2)
int index = Convert.ToInt32(val[d]);
node.next[index] = AddValue(node.next[index], val, ++d);
return node;
}

mergesort - with an insignificant change throws SystemInvalidOperationException

A very strange thing occured in my program. Here is the simplified code.
class Program
{
static void Main(string[] args)
{
ArrayList numbers = new ArrayList();
numbers.Add(1);
numbers.Add(3);
numbers.Add(4);
numbers.Add(2);
var it = Sorts.MergeSort((ArrayList)numbers.Clone());
Sorts.PrintArray(it, "mergesort");
Console.WriteLine("DONE");
Console.ReadLine();
}
}
public static class Sorts
{
public static ArrayList BubbleSort(ArrayList numbers)
{
bool sorted = true;
for (int i = 0; i < numbers.Count; i++)
{
for (int j = 1; j < numbers.Count; j++)
{
if ((int)numbers[j - 1] > (int)numbers[j])
{
int tmp = (int)numbers[j - 1];
numbers[j - 1] = numbers[j];
numbers[j] = tmp;
sorted = false;
}
}
if (sorted)
{
return numbers;
}
}
return numbers;
}
public static ArrayList MergeSort(ArrayList numbers, int switchLimit = 3)
{
//if I use this if - everything works
if (numbers.Count <= 1)
{
// return numbers;
}
//the moment I use this condition - it throws SystemInvalidOperationException in function Merge in the line of a "for"-loop
if (numbers.Count <=switchLimit)
{
return Sorts.BubbleSort(numbers);
}
ArrayList ret = new ArrayList();
int middle = numbers.Count / 2;
ArrayList L = numbers.GetRange(0, middle);
ArrayList R = numbers.GetRange(middle, numbers.Count - middle);
L = MergeSort(L);
R = MergeSort(R);
return Merge(L, R);
}
private static ArrayList Merge(ArrayList L, ArrayList R)
{
ArrayList ret = new ArrayList();
int l = 0;
int r = 0;
for (int i = 0; i < L.Count + R.Count; i++)
{
if (l == L.Count)
{
ret.Add(R[r++]);
}
else if (r == R.Count)
{
ret.Add(L[l++]);
}
else if ((int)L[l] < (int)R[r])
{
ret.Add(L[l++]);
}
else
{
ret.Add(R[r++]);
}
}
return ret;
}
//---------------------------------------------------------------------------------
public static void PrintArray(ArrayList arr, string txt = "", int sleep = 0)
{
Console.WriteLine("{1}({0}): ", arr.Count, txt);
for (int i = 0; i < arr.Count; i++)
{
Console.WriteLine(arr[i].ToString().PadLeft(10));
}
Console.WriteLine();
System.Threading.Thread.Sleep(sleep);
}
}
There is a problem with my Sorts.MergeSort function.
When I use it normally (take a look at the first if-condition in a function - all works perfectly.
But the moment when I want it to switch to bubblesort with smaller input (the second if-condition in the function) it throws me an SystemInvalidOperationException. I have no idea where is the problem.
Do you see it?
Thanks. :)
Remark: bubblesort itself works - so there shouldn't be a problem in that sort...
The problem is with your use of GetRange:
This method does not create copies of the elements. The new ArrayList is only a view window into the source ArrayList. However, all subsequent changes to the source ArrayList must be done through this view window ArrayList. If changes are made directly to the source ArrayList, the view window ArrayList is invalidated and any operations on it will return an InvalidOperationException.
You're creating two views onto the original ArrayList and trying to work with both of them - but when one view modifies the underlying list, the other view is effectively invalidated.
If you change the code to create copies of the sublists - or if you work directly with the original list within specified bounds - then I believe it'll work fine.
(As noted in comments, I'd also strongly recommend that you use generic collections.)
Here's a short but complete program which demonstrates the problem you're running into:
using System;
using System.Collections;
class Program
{
static void Main()
{
ArrayList list = new ArrayList();
list.Add("a");
list.Add("b");
ArrayList view1 = list.GetRange(0, 1);
ArrayList view2 = list.GetRange(1, 1);
view1[0] = "c";
Console.WriteLine(view2[0]); // Throws an exception
}
}
on this line R = MergeSort(R); you alter the range of numbers represented by L. This invalidates L. Sorry I have to go so can't explain any further now.

Categories