cs50 pset3 sort function [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I am having trouble with implementing the sort function on pset3. I have used the GDB and found that my sort function does not sort anything. I am not sure if there is a syntax issue, or if the logic is a bit screwed up.
void sort(int values[], int n)
{
for (int k = 0; k < n; k++)
{
for (int j = 0; j < n; j++)
{
if (values[k] >= values[j])
{
int temp = values[k];
values[k] = values[j];
values[j] = temp;
}
}
}
}

You are close, but your loops are not quite right - change:
for (int k = 0; k < n; k++)
{
for (int j = 0; j < n; j++)
{
to:
for (int k = 0; k < n - 1; k++)
{
for (int j = k + 1; j < n; j++)
{
To understand why you need to make this change, consider that the inner loop (j) need only compare elements above index k with the current element at index k. So the outer loop (k) needs to iterate from 0 to n - 2 (one less than the last element), and for each outer loop iteration the inner loop needs to iterate from k + 1 (first element above k) to n - 1 (the last element).
NOTE: by pure chance it seems that the original code does appear to work correctly, even though it appears at first glance that it shouldn't. I have tested it with various edge cases and even though it performs many redundant swaps, the final result always seems to be sorted (suprisingly though the output is in descending order whereas the fixed code generates results in ascending order, as expected). Credit to Jonathan Leffler for spotting this - see his answer and demo program.
One other minor point -- this test:
if (values[k] >= values[j])
should really just be:
if (values[k] > values[j])
It's not incorrect as it stands (the code will still work), but there is no point in swapping elements that are equal, so it's somewhat inefficient as written.

I took your code and converted into a complete program. It's larger than an MCVE because it has support code for shuffling arrays, and for printing results, as well as a main() that exercises these, of course.
#include <stdio.h>
#include <stdlib.h>
static int rand_int(int n)
{
int limit = RAND_MAX - RAND_MAX % n;
int rnd;
while ((rnd = rand()) >= limit)
;
return rnd % n;
}
static void shuffle(int *array, int n)
{
for (int i = n - 1; i > 0; i--)
{
int j = rand_int(i + 1);
int tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}
}
static void print_array(int n, int a[n])
{
for (int i = 0; i < n; i++)
printf(" %d", a[i]);
putchar('\n');
}
static void sort(int values[], int n)
{
for (int k = 0; k < n; k++)
{
for (int j = 0; j < n; j++)
{
if (values[k] >= values[j])
{
int temp = values[k];
values[k] = values[j];
values[j] = temp;
}
}
}
}
int main(int argc, char **argv)
{
if (argc > 1)
{
long l = strtol(argv[1], 0, 0);
unsigned u = (unsigned)l;
printf("Seed: %u\n", u);
srand(u);
}
int data3[3] = { 3, 1, 2 };
print_array(3, data3);
sort(data3, 3);
print_array(3, data3);
int data5[5] = { 0, 2, 6, 1, 5, };
for (int i = 0; i < 5; i++)
{
shuffle(data5, 5);
print_array(5, data5);
sort(data5, 5);
print_array(5, data5);
}
int data9[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < 9; i++)
{
shuffle(data9, 9);
print_array(9, data9);
sort(data9, 9);
print_array(9, data9);
}
return 0;
}
The shuffle code implements a Fisher-Yates shuffle, and is
based on code from an answer by Roland Illig. If invoked without a seed argument, it generates the same output each time.
Code compiled and tested on macOS Sierra 10.12.1 with GCC 6.2.0.
An example output:
Seed: 123456789
3 1 2
3 2 1
6 0 1 5 2
6 5 2 1 0
0 6 1 2 5
6 5 2 1 0
0 1 2 6 5
6 5 2 1 0
5 0 6 1 2
6 5 2 1 0
1 6 5 2 0
6 5 2 1 0
0 4 8 3 7 5 1 6 2
8 7 6 5 4 3 2 1 0
7 4 0 5 6 8 3 2 1
8 7 6 5 4 3 2 1 0
1 2 7 5 0 8 3 6 4
8 7 6 5 4 3 2 1 0
3 8 7 5 2 1 0 6 4
8 7 6 5 4 3 2 1 0
1 4 2 6 3 0 7 5 8
8 7 6 5 4 3 2 1 0
2 3 7 4 8 0 5 6 1
8 7 6 5 4 3 2 1 0
3 4 5 8 6 2 0 7 1
8 7 6 5 4 3 2 1 0
3 6 7 4 8 2 5 1 0
8 7 6 5 4 3 2 1 0
0 8 7 3 4 6 5 1 2
8 7 6 5 4 3 2 1 0
This shows the data being sorted in descending order every time, despite different randomized inputs.

Related

Making an empy Sudoku solver on C

So i got an assignment in class to make an empty sudoku that every time creates a random solution of 9x9.
I got to the point where i get different number each row and column but not on every 3x3 matrix and i cannot figure out how to go on from here.
We didnt learn recursion yet and can use only the libraries listed in the code.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NINE 9
#define ONE 1
void solve_sudoku(int board[9][9])
{
srand(time(0));
int count = 0;
for (int i = 0;i <= NINE;i++)
{
for (int j = 0;j < NINE;j++)
{
board[i][j] =(rand() % NINE)+ONE;
for (int k = 0;k < 9;k++)
{
int clone_i = i;
int clone_j = j;
while (board[i][k] == board[i][j])
{
if (j == k)
{
break;
}
count++;
board[i][j] = (rand() % NINE) + ONE;
k = 0;
}
while(board[k][j]==board[i][j])
{
if (i == k)
{
break;
}
count++;
board[i][j] = (rand() % NINE) + ONE;
k = 0;
}
if (count > 300 || (board[i][j] == board[i][k] && j != k))
{
for (int i = clone_i;i < clone_i + 1;i++)
for (int l = 0;l < 9;l++)
{
board[i][l] = 0;
}
count = 0;
k = 0;
j = 0;
}
}
}
}
}
void print_sudoku(int board[][9])
{
printf("The soduko solution is: \n");
for (int i = 0;i < NINE;i++)
{
for (int k = 0;k < NINE;k++)
{
printf("%d ", board[i][k]);
}
printf("\n");
}
}
int main()
{
int sud[9][9] = { 0 };
int matrix_size = 9;
solve_sudoku(sud);
print_sudoku(sud);
return 0;
}
I take you to mean that you need to generate random 9 x 9 grids of digits that meet the Sudoku criterion that each row, column and block contains all nine digits. In that case, you are going about it a very difficult way. Perhaps that was inspired by viewing the program as a solver, instead of what it really needs to be: a generator.
Consider that it is easy to write down at least one valid Sudoku algorithmically:
1 2 3 | 4 5 6 | 7 8 9
4 5 6 | 7 8 9 | 1 2 3
7 8 9 | 1 2 3 | 4 5 6
------+-------+------
2 3 4 | 5 6 7 | 8 9 1
5 6 7 | 8 9 1 | 2 3 4
8 9 1 | 2 3 4 | 5 6 7
------+-------+------
3 4 5 | 6 7 8 | 9 1 2
6 7 8 | 9 1 2 | 3 4 5
9 1 2 | 3 4 5 | 6 7 8
Now consider that you can always transform one valid Sudoku into a different one by swapping two rows or two columns such that no entries move from one block to another. For example, you can swap the first row with the third, or the fifth column with the sixth. If you perform a bunch of random swaps of that kind on a valid starting Sudoku then you will end up with a random grid that meets the Sudoku criteria.
Note that it is a different story if you need to produce only Sudoku that can be solved by deduction alone, without trial & error. For that you probably do need a solver-based approach, but that starts with a bona fide solver, and nothing in your code is anything like that.

recursion - data structure course - print all possible series

I need to print all possible series that their sum is equal to N;
for example is n == 4 the output should be:
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[1, 3]
[2, 1, 1]
[2, 2]
[3, 1]
[4]
My way of thinking to solve this problem was:
print the series that the number i is not in the series
print the series that the number i is in the series, now need to find the sum of N-i.
my code:
#include <stdio.h>
#include <stdlib.h>
void printArr(int arr[], int n)
{
for (int i = 0; i < n; i++)
{
printf(" %d ", arr[i]);
}
printf("\n");
}
void printAllHelper(int* a,int size, int sum, int used,int index) {
if (sum == 0) {
a -= used;
printArr(a, used);
}
else if (sum < 0 || index == size)
{
return;
}
else {
for(int i = 1 ; i <= size ; i ++)
{
printAllHelper(a, size, sum, used, index + 1);
if (i <= sum)
{
*a = i;
}
printAllHelper(a+1, size, sum -i, used +1, index + 1);
}
}
}
void printAll(int num) {
int* myArray = (int*)malloc(num * sizeof(int));
printAllHelper(myArray,num,num,0,0);
}
void main() {
printAll(4);
}
my output:
3 1
3 1
3 1
3 1
3 1
3 1
3 1
3 1
3 1
4
1 3
4
2 2
4
3 1
4
4
1 3
1 1 2
1 3
1 2 1
1 3
1 3
1 3
4
1 3
4
2 2
4
3 1
4
4
2 2
2 1 1
2 2
2 2
2 2
2 2
4
1 3
4
2 2
4
3 1
4
4
3 1
3 1
3 1
3 1
3 1
4
1 3
4
2 2
4
3 1
4
4
4
4
Please try to explain to me your way of thinking, and how you approach this kind of problem, I want to be the very best like no one ever was :(.....
Your reasoning is not quite correct, but your code is almost right. The loop in your else part should be
for(int i = 1 ; i <= sum ; i ++) {
*a = i;
printAllHelper(a+1, size, sum-i, used+1, index+1);
}
With this, I get the output
1 1 1 1
1 1 2
1 2 1
1 3
2 1 1
2 2
3 1
4
The idea is basically: "The numbers sum to sum if the first number i is any number from 1 to sum and the rest of the numbers sum to sum - i."
Also, note that your code shows some room for improvement, e.g. the used and index variables seem a bit redundant. And with not adding numbers larger than sum or smaller than 1, the check whether sum < 0 || index == size is not necessary, either. Thus you also do not need the size parameter. Your printAllHelper could be simplified to something like this:
void printAllHelper(int* a, int sum, int index) {
if (sum == 0) {
printArr(a, index);
} else {
for(int i = 1 ; i <= sum ; i++) {
a[index] = i;
printAllHelper(a, sum-i, index+1);
}
}
}
(Note: C is not my native language, if you see more things to improve, please comment.)

Why 2 is not smaller than 10 on Codeblocks?

I just worked to my final exam with simple codes; when I try to sorting strings, I face annoying error. Why 2 is not smaller than 10 on my CodeBlocks IDE but is smaller than 10 on real and onlinegdb.com?
This is the annoying code:
#include <string.h>
#include <stdio.h>
#define STR_SIZ 20
int main()
{
char strArr[][STR_SIZ] = {"abc", "hdas", "sdfasf", "kakldf", "caksl", "casd", "keam", "cznjcx", "mnxzv", "jkalkds"};
char minStr[STR_SIZ];
strcpy(minStr, strArr[0]);
int N = sizeof(strArr)/sizeof(minStr);
// int N = 10;
for(int x = 0; x < N-1; x++)
{
printf("%d", x);
strcpy(minStr,strArr[x]);
int j;
for(j=1+x; j < 10; j++)
{
printf("%4d\n", j);
int cmp = strcmp(strArr[j], minStr);
if(cmp < 0)
strcpy(minStr,strArr[j]);
}
char temp[STR_SIZ];
strcpy(temp,strArr[x]);
strcpy(strArr[x], minStr);
strcpy(strArr[j], temp);
}
return 0;
}
Output on onlinegdb.com:
0 1
2
3
4
5
6
7
8
9
1 2
3
4
5
6
7
8
9
2 3
4
5
6
7
8
9
3 4
5
6
7
8
9
4 5
6
7
8
9
5 6
7
8
9
6 7
8
9
7 8
9
8 9
Output on CodeBlocks:
0 1
2
3
4
5
6
7
8
9
1 2
3
4
5
6
7
8
9
2
PS: I just have used Codeblock in the morning and it was okey with executing.
strArr has 10 elements. At the end of your loop, you call strcpy(strArr[j], temp);. This will write to strArr[10], which is out of bounds and will overwrite some unknown memory. Anything can happen after that.
You should save the j value when you copy a string into minStr.
FYI, your code above prints this as your final string order with onlinegdb:
abc
caksl
caksl
caksl
caksl
casd
cznjcx
cznjcx
jkalkds
jkalkds
So I think you have other problems as well.
try this
#include <string.h>
#include <stdio.h>
#define STR_SIZ 20
int main()
{
char strArr[][STR_SIZ] = {"abc", "hdas", "sdfasf", "kakldf", "caksl", "casd", "keam", "cznjcx", "mnxzv", "jkalkds"};
strcpy(minStr, strArr[0]);
// Calculate the number of elements this way.
const int N = sizeof(strArr)/sizeof(strArr[0]);
// int N = 10;
for(int x = 0; x < N-1; x++)
{
printf("%d", x);
int j;
for(j=1+x; j < N; j++) // Use N here too!
{
printf("%4d\n", j);
int cmp = strcmp(strArr[j], strArr[x]);
if(cmp < 0)
{
// Do the swaps only when needed.
char temp[STR_SIZ];
strcpy(temp,strArr[x]);
strcpy(strArr[x], strArr[j]);
strcpy(strArr[j], temp);
}
}
}
// Verify result
for(int x = 0; x < N; x++) printf("%s\n", strArr[x]);
return 0;
}
I moved your swap into your if check and got rid of your minStr as it was not needed. Notice how I calculate the N size too. Honestly, you were close, but you needed to verify your output.

C programming: Replacing if statements

Hello a beginner here who needs some of your help. My C program is good and does what it is supposed to do only that it is not supposed to use any kind of if statements. I wrote it that way as I saw it would be easier so that I can then replace the if statements. I have been trying to replace the if statements but am now stuck. What can I use instead of the if statement to still produce the same output.
The program is supposed to generate a sequence of thirty random integers between 0 and 9 and then print out the sequence both forward and backwards. Then print out a count of how many times each number between 0 and 9 appeared in the sequence.
This is the output
Here is a sequence of 30 random numbers between 0 and 9:
3 6 7 5 3 5 6 2 9 1 2 7 0 9 3 6 0 6 2 6 1 8 7 9 2 0 2 3 7 5
Printing them backwards, that's:
5 7 3 2 0 2 9 7 8 1 6 2 6 0 6 3 9 0 7 2 1 9 2 6 5 3 5 7 6 3
There were 3 0's
There were 2 1's
There were 5 2's
There were 4 3's
There were no 4's
There were 3 5's
There were 5 6's
There were 4 7's
There was only 1 8
There were 3 9's
This is my C program
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j, array[30]={0}, count=0,check;
srand(time(NULL));
for(i=0;i<30;i++)
array[i]=rand()%10;
for(i=0;i<30;i++)
printf("%d ",array[i]);
printf("\n\n");
for(i=29;i>=0;i--)
printf("%d ",array[i]);
printf("\n\n");
for(i=0;i<30;i++){
check=array[i];
if(array[i]!=-1)
array[i]=-1;
if(check == -1)
continue;
count =1;
for(j=0;j<30;j++){
if((i==j) || (array[j]==-1))
continue;
if(check==array[j]){
count++;
array[j]=-1;
}
}
printf("There were %d %d's\n",count,check);
}
return 0;
}
You'll understand the algorithm from comments:
#include <stdio.h>
#include <stdlib.h>
//time.h is needed for time()
#include <time.h>
int main()
{
int i, array[30] = {0};
srand(time(NULL));
//generate and print 30 random numbers
for(i = 0; i < 30; i++){
array[i] = rand() % 10;
printf("%d ", array[i]);
}
puts("\n\n");
//print these numbers backwards
for(i = 29; i >= 0; i--)
printf("%d ",array[i]);
puts("\n\n");
// print out a count of how many times each number
// between 0 and 9 appeared in the sequence.
int count[10] = {0};
for(i = 0; i < 30; i++)
count[array[i]]++;
//output the count for each number
for(i = 0; i < 10; i++)
printf("There were %d %d's\n",count[i], i);
return 0;
}
Output:
9 2 3 9 8 4 3 8 1 3 6 4 3 2 5 3 2 3 0 1 9 0 3 5 1 3 3 8 2 0
0 2 8 3 3 1 5 3 0 9 1 0 3 2 3 5 2 3 4 6 3 1 8 3 4 8 9 3 2 9
There were 3 0's
There were 3 1's
There were 4 2's
There were 9 3's
There were 2 4's
There were 2 5's
There were 1 6's
There were 0 7's
There were 3 8's
There were 3 9's
The following is a simplification of your original source while removing the if statements. There are implied if statements in several places where a logical expression is used as part of a source code statement.
For instance for(j = 0; j < 30 && match >= 0; j++) has several logical expressions but no if appears in this statement. The logical expressions are j < 30 and match >= 0 and the complete expression of j < 30 && match >= 0.
This example uses a logical expression and the evaluation short circuit behavior of the C compiler (see Short-circuit evaluation in Wikipedia) in the statement array[j] == match && ++count && (array[j] = -1); so that if the logical expression array[j] == match evaluates to false then the rest of the statement will not be executed.
We also depend on the preincrement operator with the ++count to increment count and then take the resulting value to check if it is false (zero) or true (non-zero). Since the variable count is initialized to zero and when incremented will always be non-zero then the next logical expression in the statement is evaluated the (array[j] = -1). We put the assignment statement within parenthesis to enforce the order of evaluation. We want the variable array[j] to be assigned the value of -1 and for the result to then be used in the logical statement. Since this is the last logical expression of the entire logical statement, whether it evaluates to false (zero) or true (non-zero) doesn't matter as what we want is the side effect of assigning the value of -1 to the array element.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int i, array[30] = {0};
srand(time(NULL));
for(i = 0; i < 30; i++)
array[i] = rand() % 10;
for(i = 0; i < 30; i++)
printf("%d ", array[i]);
printf("\n\n");
for(i = 29; i >= 0; i--)
printf("%d ",array[i]);
printf("\n\n");
for(i = 0; i < 30; i++){
int j;
int count = 0;
int match = array[i];
for(j = 0; j < 30 && match >= 0; j++){
array[j] == match && ++count && (array[j] = -1);
// replaces the following if as value of count is
// tested after it is incremented so will always be nonzero.
// if (array[j] == match) {
// count++; array[j] = -1;
// }
}
// if this is a valid array element value we are trying to match
// then print the count and the value being matched. printf()
// is a function that returns an int indicating number of character written.
match >= 0 && printf("There were %d %d's\n", count, match);
}
return 0;
}
An example output.
8 2 4 0 8 0 8 1 1 4 6 9 3 9 7 6 3 9 0 1 0 7 1 2 4 0 3 0 2 3
3 2 0 3 0 4 2 1 7 0 1 0 9 3 6 7 9 3 9 6 4 1 1 8 0 8 0 4 2 8
There were 3 8's
There were 3 2's
There were 3 4's
There were 6 0's
There were 4 1's
There were 2 6's
There were 3 9's
There were 4 3's
There were 2 7's

What should I do for sort array?

I tried to sort arr by excluding those who were already selected as the largest numbers but it didn't work.
The result is this:
As I intended, at first cycle, the store is {9, 0, 0, 0, 0 ... } and when arr[i] becomes 9, the rest of process should be skipped. I have to sort it without additional functions and it's too difficult to me. What is the problem?
int i = 0;
int j = 0;
int num = 0;
int sign = 0;
int arr[10] = { 1,5,3,4,8,7,5,9,8,0 };
int max = arr[0];
int store[10] = { 0 };
int k = 0;
for (j = 0; j < 10; j++) {
printf("store: ");
for (int n = 0; n < 10; on++)
printf("%d ", store[n]);
printf("\n");
for (i = 0; i < 10; i++) {
sign = 0;
k = 0;
while (k < 10) {
if (arr[i] == store[k]) {
sign = 1;
break;
}
k++;
}
if (sign == 1) {
continue;
}
if (arr[i] > max) {
max = arr[i];
}
}
store[j] = max;
}
You have several errors here:
The array store has a size of 10, but in the jth pass through the outer loop, only j values have been filled in; the rest is still zero. So whenever you iterate over store, you should use j as upper limit.
You are looking for the max in each iteration. Therefore, it is not enough to initialise max once outside the outer loop. You do that, and it will stay 9 ever after. You should reset max for every j.
Finally, your idea to go through the array to see whether you have already processed a certain value does not work. Your array has duplicates, two 8's and two 5's. You will only place one eight and one five with your strategy and re-use the last value of max for the last two elements. (Plus, that idea lead to O(n³) code, which is very wasteful.
You can work around that by keeping an extra array where you store whether (1) or not (0) you have already processed a value at a certain index or by setting processed entries in the array to a very low value.
What you want to implement is selection sort: Find the maximum value in the whole list and move it to the front. Then find the maximum in the whole list except the first item and move it to the second slot and so on:
* 1 5 3 4 8 7 5 9 8 0
9 * 5 3 4 8 7 5 1 8 0
9 8 * 3 4 5 7 5 1 8 0
9 8 8 * 4 5 7 5 1 3 0
9 8 8 7 * 5 4 5 1 3 0
9 8 8 7 5 * 4 5 1 3 0
9 8 8 7 5 5 * 4 1 3 0
9 8 8 7 5 5 4 * 1 3 0
9 8 8 7 5 5 4 3 * 1 0
9 8 8 7 5 5 4 3 1 * 0
9 8 8 7 5 5 4 3 1 0 *
Here, all items to the left of the asterisk have been sorted and everything to the right of the asterisk is still unsorted. When the * (at position j) has moved to the right, the whole array is sorted.
This sort is in-place: It destroys the original order of the array. That is useful, because the position of an element tells us whether it has been processed or not. In the third iteration, the algorithm can distinguish between the 8 that has been sorted and the 8 that hasn't been sorted yet. (This sort is often described as sorting a hand of cards: Look fo the lowest, put it to the left and so on. If you must sort into a second array, copy the original array and sort the copy in place.)
Here's the code that sorts your array and prints out the diagram above:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int arr[10] = {1, 5, 3, 4, 8, 7, 5, 9, 8, 0};
int i = 0;
int j = 0;
for (j = 0; j < 10; j++) {
int imax = j;
int swap = arr[j];
// print array
for (i = 0; i < 10; i++) {
if (i == j) printf("* ");
printf("%d ", arr[i]);
}
printf("\n");
// find index of maximum item
for (i = j + 1; i < 10; i++) {
if (arr[i] > arr[imax]) {
imax = i;
}
}
// swap first unsorted item and maximum item
arr[j] = arr[imax];
arr[imax] = swap;
}
// print fully sorted array
for (i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("*\n");
return 0;
}
Use i and j.
N is 10 and the data consists of shuffled numbers 0 to N-1.
j goes from 0 to N-1. At each step, you want to fill it with
the maximum of the unprocessed input.
So i goes from j+1 to N-1, in the inner loop. If arr[j] < arr[i],
swap arr[i] and arr[j].
It speeds up considerably as you get towards the end.

Resources