Bubble sort doesn't print the right winner - CS50 week 3 as a beginner - I'm lost - cs50

please help a newbie like me, I'm lost, I don't get it - I looked at answers, it still doesn't work and I can't spot the error.
I'm working on plurality, I know we can solve it without bubble sort but I want to find out why my solution isn't working.
I bubble sorted it - and I can't get the right names to print.
I feel like I tried to put the printf everywhere in any bracket and it is never right and shows me any solution but the right one.
Currently, it prints the last 2 names regardless of who has the most votes.
I feel like it's something pretty simple and basic but it's been 3 days now and I can't get anywhere - please help me, where am I misunderstanding things?
void print_winner(void)
{
int temp;
for (int i = 0; i < candidate_count; i++) //going through each name/vote struct - -1 because c-count is acvg arguments
{
for(int j = 0; j < (candidate_count - i - 1); j++) // c_c - i - 1 is for ignoring already compared candidates
{
if (candidates[j].votes < candidates[j + 1].votes)
{
temp = candidates[j].votes;
candidates[j].votes = candidates[j + 1].votes;
candidates[j + 1].votes = temp;
}
}
}
int top = candidates[candidate_count - 1].votes;
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].votes == top)
{
printf("%s\n", candidates[i].name);
}
}
return;
}

Related

CS50 Plurality – having trouble understanding why candidate_count is used

I'm trying to understand why candidate_count is used instead of voter count in CS50's Plurality (week 3). Below is my code.
If we imagine we have three candidates (Alice, Bob, Charlie) and every time we iterate through the bool function or the print_winner function, would we not miss out on counting votes if we had something like 10 voters? According to my understanding, 'i' would only ever iterate 3 times. I'm having a conceptual issue in understanding why we wouldn't use voter_count instead in the print winner function at the bottom.
I'm still trying to refine my code a bit, so parts may still be buggy. I'm just looking for some help in clarifying the logic in this problem.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
// Max number of candidates
#define MAX 9
// Candidates have name and vote count
typedef struct
{
string name;
int votes;
}
candidate;
// Array of candidates
candidate candidates[MAX];
// Number of candidates
int candidate_count;
// Function prototypes
bool vote(string name);
void print_winner(void);
int main(int argc, string argv[])
{
// Check for invalid usage
if (argc < 2)
{
printf("Usage: plurality [candidate ...]\n");
return 1;
}
// Populate array of candidates (number of arguments - 1 because the first arg is going to be plurality)
candidate_count = argc - 1;
if (candidate_count > MAX)
{
printf("Maximum number of candidates is %i\n", MAX);
return 2;
}
for (int i = 0; i < candidate_count; i++)
{
candidates[i].name = argv[i + 1]; //
candidates[i].votes = 0;
}
int voter_count = get_int("Number of voters: ");
// Loop over all voters
for (int i = 0; i < voter_count; i++)
{
string name = get_string("Vote: ");
// Check for invalid vote
if (!vote(name))
{
printf("Invalid vote.\n");
}
}
// Display winner of election
print_winner();
}
// Update vote totals given a new vote
bool vote(string name)
{
for (int i = 0; i < candidate_count; i++)
{
if (strcmp(candidates[i].name, name) == 0)
{
candidates[i].votes++;
return true;
}
}
return false;
}
// Print the winner (or winners) of the election
void print_winner(void)
{
int maxvotes = 0;
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].votes > maxvotes)
{
maxvotes = candidates[i].votes;
}
}
for (int i = 0; i < candidate_count; i++)
{
printf("the winner is %s\n!", candidates[i].name);
}
return;
}
I think you misunderstand what we're looping through. candidate_count is used to loop through candidates which is an array with candidate_count number of elements.
Consider this simple array-
int arr[] = {1, 2, 3, 4, 5};
We would loop through this using-
for (int i = 0; i < 5; i++)
{
printf("value at index %d is %d\n", i, arr[i]);
}
notice the part i < 5. Why 5? Well because that's the length of the array arr, anything more and we'd be reading out of bounds, anything less and we would not be reading the entire arr.
Now replace arr with candidates, which is also an array and replace 5 with candidate_count, which is obviously the length of said array.
The loops in vote or print_winner functions do not "count votes", they iterate through the array of candidates. That's the purpose of those loops. Hence, to iterate through an array, we must use index < length_of_array. That's exactly what it does.
Just to address the concern of "where does it count votes then?". Let's look at vote real quick-
bool vote(string name)
{
for (int i = 0; i < candidate_count; i++)
{
if (strcmp(candidates[i].name, name) == 0)
{
candidates[i].votes++;
return true;
}
}
return false;
}
This function is triggered after user input, so let's say the user is asked for a name - they pick some name, assume this name matches with a candidate. So vote is called, it iterates through the array of candidates. Why does it iterate? It needs to find the candidate who has the same name as the name just provided by the user.
So the purpose of this loop, is to iterate through the array candidates, and the purpose of the code within this loop is to compare the names of each candidate to the name provided by the user. If it matches, it increments the votes of that candidate.
This line- candidates[i].votes++;
That is where the votes are counted. It's a simple as incrementing a counter.
Imagine a real life scenario, you're the program. The candidates are all standing in a line (an array). Each candidate starts with 0 cards (votes). Assume none of them have the same name.
A user tells you that they wanna vote for candidate foo (just a name).
You then go to that line of candidates. You start by the first candidate and ask them "what is your name?".
The candidate tells you their name.
If their name matches with the name the user gave you, this is it, you give them a card representing the vote. Now they have 1 more card than they had before
If their name does not match, you move to the next candidate and repeat.
But where do you stop? Simple, you stop before the last candidate. How many iterations could this take maximum? candidate_count, i.e the number of candidates standing in that line. So, worst case scenario, the person you're looking for is at the very end of the line, so you have to ask candidate_count number of people before finally finding the one you're looking for. Traversing an array.
In the end, you just count how many cards each candidate has to realize who's the winner. (.votes)
The print_winner function should do the same thing. Though your code seems a bit crooked.
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].votes > maxvotes)
{
maxvotes = candidates[i].votes;
}
}
This loop is the equivalent of going through the whole line of candidates, asking each one how many cards (votes) they have and finding out who has the maximum number of cards (votes).
But you also need to ask the name of the person with the maxvotes! That's what you're looking for.
But you completely ditch the maxvotes you just calculated later, you never use it.
for (int i = 0; i < candidate_count; i++)
{
printf("the winner is %s\n!", candidates[i].name);
}
That loop will print the name of every single candidate. It's the equivalent of going through the whole line of candidates (array), asking each one "what is your name?" and shouting out "The winner is [their name]!". But that's not true!
You should store the name of the candidate, as well as maxvotes and then print it after the first loop-
string winner_name;
...
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].votes > maxvotes)
{
maxvotes = candidates[i].votes;
winner_name = candidates[i].name;
}
}
printf("the winner is %s\n!", candidates[i].name);
Of course, this does not take care of multiple winners, what if 2 candidates have the same number of votes? That's something you'll have to try yourself.
But I hope this answers your question about the confusion.

Optimal algorithm for this string decompression

I have been working on an exercise from google's dev tech guide. It is called Compression and Decompression you can check the following link to get the description of the problem Challenge Description.
Here is my code for the solution:
public static String decompressV2 (String string, int start, int times) {
String result = "";
for (int i = 0; i < times; i++) {
inner:
{
for (int j = start; j < string.length(); j++) {
if (isNumeric(string.substring(j, j + 1))) {
String num = string.substring(j, j + 1);
int times2 = Integer.parseInt(num);
String temp = decompressV2(string, j + 2, times2);
result = result + temp;
int next_j = find_next(string, j + 2);
j = next_j;
continue;
}
if (string.substring(j, j + 1).equals("]")) { // Si es un bracket cerrado
break inner;
}
result = result + string.substring(j,j+1);
}
}
}
return result;
}
public static int find_next(String string, int start) {
int count = 0;
for (int i = start; i < string.length(); i++) {
if (string.substring(i, i+1).equals("[")) {
count= count + 1;
}
if (string.substring(i, i +1).equals("]") && count> 0) {
count = count- 1;
continue;
}
if (string.substring(i, i +1).equals("]") && count== 0) {
return i;
}
}
return -111111;
}
I will explain a little bit about the inner workings of my approach. It is a basic solution involves use of simple recursion and loops.
So, let's start from the beggining with a simple decompression:
DevTech.decompressV2("2[3[a]b]", 0, 1);
As you can see, the 0 indicates that it has to iterate over the string at index 0, and the 1 indicates that the string has to be evaluated only once: 1[ 2[3[a]b] ]
The core here is that everytime you encounter a number you call the algorithm again(recursively) and continue where the string insides its brackets ends, that's the find_next function for.
When it finds a close brackets, the inner loop breaks, that's the way I choose to make the stop sign.
I think that would be the main idea behind the algorithm, if you read the code closely you'll get the full picture.
So here are some of my concerns about the way I've written the solution:
I could not find a more clean solution to tell the algorithm were to go next if it finds a number. So I kind of hardcoded it with the find_next function. Is there a way to do this more clean inside the decompress func ?
About performance, It wastes a lot of time by doing the same thing again, when you have a number bigger than 1 at the begging of a bracket.
I am relatively to programming so maybe this code also needs an improvement not in the idea, but in the ways It's written. So would be very grateful to get some suggestions.
This is the approach I figure out but I am sure there are a couple more, I could not think of anyone but It would be great if you could tell your ideas.
In the description it tells you some things that you should be awared of when developing the solutions. They are: handling non-repeated strings, handling repetitions inside, not doing the same job twice, not copying too much. Are these covered by my approach ?
And the last point It's about tets cases, I know that confidence is very important when developing solutions, and the best way to give confidence to an algorithm is test cases. I tried a few and they all worked as expected. But what techniques do you recommend for developing test cases. Are there any softwares?
So that would be all guys, I am new to the community so I am open to suggestions about the how to improve the quality of the question. Cheers!
Your solution involves a lot of string copying that really slows it down. Instead of returning strings that you concatenate, you should pass a StringBuilder into every call and append substrings onto that.
That means you can use your return value to indicate the position to continue scanning from.
You're also parsing repeated parts of the source string more than once.
My solution looks like this:
public static String decompress(String src)
{
StringBuilder dest = new StringBuilder();
_decomp2(dest, src, 0);
return dest.toString();
}
private static int _decomp2(StringBuilder dest, String src, int pos)
{
int num=0;
while(pos < src.length()) {
char c = src.charAt(pos++);
if (c == ']') {
break;
}
if (c>='0' && c<='9') {
num = num*10 + (c-'0');
} else if (c=='[') {
int startlen = dest.length();
pos = _decomp2(dest, src, pos);
if (num<1) {
// 0 repetitions -- delete it
dest.setLength(startlen);
} else {
// copy output num-1 times
int copyEnd = startlen + (num-1) * (dest.length()-startlen);
for (int i=startlen; i<copyEnd; ++i) {
dest.append(dest.charAt(i));
}
}
num=0;
} else {
// regular char
dest.append(c);
num=0;
}
}
return pos;
}
I would try to return a tuple that also contains the next index where decompression should continue from. Then we can have a recursion that concatenates the current part with the rest of the block in the current recursion depth.
Here's JavaScript code. It takes some thought to encapsulate the order of operations that reflects the rules.
function f(s, i=0){
if (i == s.length)
return ['', i];
// We might start with a multiplier
let m = '';
while (!isNaN(s[i]))
m = m + s[i++];
// If we have a multiplier, we'll
// also have a nested expression
if (s[i] == '['){
let result = '';
const [word, nextIdx] = f(s, i + 1);
for (let j=0; j<Number(m); j++)
result = result + word;
const [rest, end] = f(s, nextIdx);
return [result + rest, end]
}
// Otherwise, we may have a word,
let word = '';
while (isNaN(s[i]) && s[i] != ']' && i < s.length)
word = word + s[i++];
// followed by either the end of an expression
// or another multiplier
const [rest, end] = s[i] == ']' ? ['', i + 1] : f(s, i);
return [word + rest, end];
}
var strs = [
'2[3[a]b]',
'10[a]',
'3[abc]4[ab]c',
'2[2[a]g2[r]]'
];
for (const s of strs){
console.log(s);
console.log(JSON.stringify(f(s)));
console.log('');
}

Wrapping around negative numbers in Rust

I'm rewriting C code in Rust which heavily relies on u32 variables and wrapping them around. For example, I have a loop defined like this:
#define NWORDS 24
#define ZERO_WORDS 11
int main()
{
unsigned int i, j;
for (i = 0; i < NWORDS; i++) {
for (j = 0; j < i; j++) {
if (j < (i-ZERO_WORDS+1)) {
}
}
}
return 0;
}
Now, the if statement will need to wrap around u32 for a few values as initially i = 0. I came across the wrapping_neg method but it seems to just compute -self. Is there any more flexible way to work with u32 in Rust by also allowing wrapping?
As mentioned in the comments, the literal answer to your question is to use u32::wrapping_sub and u32::wrapping_add:
const NWORDS: u32 = 24;
const ZERO_WORDS: u32 = 11;
fn main() {
for i in 0..NWORDS {
for j in 0..i {
if j < i.wrapping_sub(ZERO_WORDS).wrapping_add(1) {}
}
}
}
However, I'd advocate avoiding relying on wrapping operations unless you are performing hashing / cryptography / compression / something similar. Wrapping operations are non-intuitive. For example, j < i-ZERO_WORDS+1 doesn't have the same results as j+ZERO_WORDS < i+1.
Even better would be to rewrite the logic. I can't even tell in which circumstances that if expression will be true without spending a lot of time thinking about it!
It turns out that the condition will be evaluated for i=9, j=8, but not for i=10, j=0. Perhaps all of this is clearer in the real code, but devoid of context it's very confusing.
This appears to have the same logic, but seems much more understandable to me:
i < ZERO_WORDS - 1 || i - j > ZERO_WORDS - 1;
Compare:
j < i.wrapping_sub(ZERO_WORDS).wrapping_add(1);

Alphabet string code, looping

So I need to finish this program that asks user to type in a word and then he needs to write it back "encrypted", only in number. So a is 1, b is 2... For example if I give the word "bad", it should come back as "2 1 4". The program I made seems to do this always only for the 1st letter of the word. My question that I would need help with is, why does this program stop looping after the 1st letter? Am I even doin it right or is it completely off? Any help would be much appreciated.
Console.Write("Please, type in a word: ");
string start = Console.ReadLine();
string alphabet = "abcdefghijklmnopqrstuvwxyz";
for (int c = 0; c < alphabet.Length; c++)
{
int a = 0;
if (start[a] == alphabet[c])
{
Console.Write(c + 1);
a++;
continue;
}
if (start[a] != alphabet[c])
{
a++;
continue;
}
}
I accomplished it with a nested loop:
Console.Write("Please, type in a word: ");
string start = Console.ReadLine();
string alphabet = "abcdefghijklmnopqrstuvwxyz";
for (int a = 0; a < start.Length; a++)
{
for (int c = 0; c < alphabet.Length; c++)
{
if (start[a] == alphabet[c])
{
Console.Write(c + 1);
}
}
}
While comparing the strings, it makes sense, at least to me, to loop through both of them.
Your program was stopping after the first letter because your were resetting "a" to 0 at the beginning of every loop.

Is it possible to do a Levenshtein distance in Excel without having to resort to Macros?

Let me explain.
I have to do some fuzzy matching for a company, so ATM I use a levenshtein distance calculator, and then calculate the percentage of similarity between the two terms. If the terms are more than 80% similar, Fuzzymatch returns "TRUE".
My problem is that I'm on an internship, and leaving soon. The people who will continue doing this do not know how to use excel with macros, and want me to implement what I did as best I can.
So my question is : however inefficient the function may be, is there ANY way to make a standard function in Excel that will calculate what I did before, without resorting to macros ?
Thanks.
If you came about this googling something like
levenshtein distance google sheets
I threw this together, with the code comment from milot-midia on this gist (https://gist.github.com/andrei-m/982927 - code under MIT license)
From Sheets in the header menu, Tools -> Script Editor
Name the project
The name of the function (not the project) will let you use the func
Paste the following code
function Levenshtein(a, b) {
if(a.length == 0) return b.length;
if(b.length == 0) return a.length;
// swap to save some memory O(min(a,b)) instead of O(a)
if(a.length > b.length) {
var tmp = a;
a = b;
b = tmp;
}
var row = [];
// init the row
for(var i = 0; i <= a.length; i++){
row[i] = i;
}
// fill in the rest
for(var i = 1; i <= b.length; i++){
var prev = i;
for(var j = 1; j <= a.length; j++){
var val;
if(b.charAt(i-1) == a.charAt(j-1)){
val = row[j-1]; // match
} else {
val = Math.min(row[j-1] + 1, // substitution
prev + 1, // insertion
row[j] + 1); // deletion
}
row[j - 1] = prev;
prev = val;
}
row[a.length] = prev;
}
return row[a.length];
}
You should be able to run it from a spreadsheet with
=Levenshtein(cell_1,cell_2)
While it can't be done in a single formula for any reasonably-sized strings, you can use formulas alone to compute the Levenshtein Distance between strings using a worksheet.
Here is an example that can handle strings up to 15 characters, it could be easily expanded for more:
https://docs.google.com/spreadsheet/ccc?key=0AkZy12yffb5YdFNybkNJaE5hTG9VYkNpdW5ZOWowSFE&usp=sharing
This isn't practical for anything other than ad-hoc comparisons, but it does do a decent job of showing how the algorithm works.
looking at the previous answers to calculating Levenshtein distance, I think it would be impossible to create it as a formula.
Take a look at the code here
Actually, I think I just found a workaround. I was adding it in the wrong part of the code...
Adding this line
} else if(b.charAt(i-1)==a.charAt(j) && b.charAt(i)==a.charAt(j-1)){
val = row[j-1]-0.33; //transposition
so it now reads
if(b.charAt(i-1) == a.charAt(j-1)){
val = row[j-1]; // match
} else if(b.charAt(i-1)==a.charAt(j) && b.charAt(i)==a.charAt(j-1)){
val = row[j-1]-0.33; //transposition
} else {
val = Math.min(row[j-1] + 1, // substitution
prev + 1, // insertion
row[j] + 1); // deletion
}
Seems to fix the problem. Now 'biulding' is 92% accurate and 'bilding' is 88%. (whereas with the original formula 'biulding' was only 75%... despite being closer to the correct spelling of building)

Resources