UnExpected Results From 2 Sort Methods C - c

I am getting unexpected results from my bubble sort program in C.
The program below is a program which takes 5 inputs from the user, performs selection sort on them, then performs exchange sort on them.
If i use these inputs:
50
150
75
175
23
It should sort them to the following:
23
50
75
150
175
However, it doesnt sort correctly and sorts like the following (opposite way around for exchange as it does it in Descending order):
150
175
23
50
75
Its quite strange because if you enter certain values it will sort them correctly such as:
73
84
03
26
83
Not quite sure whats going on with it. I cant start making changes to it when it technically works for certain values.
I must be missing something somewhere.
Any help would be appreciated.
CODE IN FULL:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
int main(int argc, char *argv[])
{
char arc5Strings[5][256];
int nCount, nCount2, nCount3, nCount4, nCount5, nCount6, nCount7, letter, sorted;
int fMinVal[1][2] = {1,1};
int nMinValPosition;
int nMoves;
int nRow;
int i, j, k, indexOfCurrentSmallest, q, temp;
char arcTemp[256];
int nOutOrder;
int nNumValues;
int clean1, clean2;
//input the values
for(nCount=0; nCount < 5; nCount++)
{
printf("Please input string %d/5: ", nCount + 1);
fgets(arc5Strings[nCount], 256, stdin);
if(strlen(arc5Strings[nCount]) > 11)
{
printf("Your string contains more than 10 characters. Please try again.");
nCount = 5;
exit(0);
}
}
//------------------------------------------------------------------------------
//Selection Sort
printf("\n\n");
for(i=0;i<5;i++)
{
indexOfCurrentSmallest = i;
for(j=i;j<5;j++)
{
for(k=0;k<255;k++)
{
if(arc5Strings[j][k] < arc5Strings[indexOfCurrentSmallest][k])
{
//we found a new possible smallest
indexOfCurrentSmallest = j;
break;
}
else if(arc5Strings[j][k] > arc5Strings[indexOfCurrentSmallest][k])
{
//no point in searching further, the one we are looking at is already larger than the one we found.
break;
}
}
}
//let's do a swap
for(q=0;q<255;q++)
{
temp = arc5Strings[i][q];
arc5Strings[i][q] = arc5Strings[indexOfCurrentSmallest][q];
arc5Strings[indexOfCurrentSmallest][q] = temp;
}
}
//---------------------------------------------------------------
//print entire array
printf("This is your selection sorted array based on ASCII values\n\n");
for(nCount3 = 0; nCount3 < 5; nCount3++)
{
for(nCount4 = 0; arc5Strings[nCount3][nCount4] != '\0'; nCount4++)
{
printf("%c", arc5Strings[nCount3][nCount4]);
}
}
//---------------------------------------------------------------------
//Exchange Sort
nNumValues = 5;
nOutOrder = TRUE;
nMoves = 0;
while(nOutOrder && nNumValues > 0)
{
nOutOrder = FALSE;
for(i=0;i<5;i++)
{
for(nCount=0; nCount < nNumValues -1; nCount++)
{
for(nCount2=0, sorted=0; sorted==0; nCount2++)
{
if(arc5Strings[nCount][nCount2] < arc5Strings[nCount+1][nCount2])
{
for(letter=0; letter<256; letter++)
{
arcTemp[letter] = arc5Strings[nCount][letter];
}
for(letter=0; letter<256; letter++)
{
arc5Strings[nCount][letter]= arc5Strings[nCount+1][letter];
}
for(letter=0; letter<256; letter++)
{
arc5Strings[nCount+1][letter] = arcTemp[letter];
}
sorted = 1;
nMoves++;
}
else if (arc5Strings[nCount][nCount2] < arc5Strings[nCount+1][nCount2])
sorted = 1;
}
}
nNumValues--;
}
}
printf("\n\n\nThe sorted list in Descending order is: \n\n\n");
for(nCount5 = 0; nCount5 < 5; nCount5++)
{
printf("%s", arc5Strings[nCount5]);
}
//-----------------------------------------------
printf("\n %d moves were required to sort this list\n\n", nMoves);
return 0;
}

It's because you're sorting strings rather than numbers, so it's using character-based sorting.
In other words, "175" is less than "23" because "1" is less than "2".
If you want to sort them as numbers, convert them to numbers first.

You are using strings while you should be using integers. Either convert your string to integer or use int straight away
See this link an example if you want to compare string
compare two alphanumeric string
Again use Array of integers if you dont need text as an input to compare

Related

Searching a string by binary search

#include <stdio.h>
#include <string.h>
typedef struct {
char name[11];
int score;
} report;
int main() {
int n = 3;
report student[n];
for (int i = 0; i < 3; i++) {
scanf("%[^\#]#%d", student[i].name, &student[i].score);
}
// Input name that we search.
char search[11];
scanf("%s", search);
// bubble sort
for (int a = 0; a < n - 1; a++) {
for (int b = 0; b < n - 1 - a; b++) {
if (student[b].score < student[b+1].score) {
report temp;
strcpy(temp.name, student[b].name);
temp.score = student[b].score;
strcpy(student[b].name, student[b+1].name);
student[b].score = student[b+1].score;
strcpy(student[b+1].name, temp.name);
student[b+1].score = temp.score;
}
}
}
// binary search
int left = 0;
int right = n - 1;
int middleIndex;
int rank;
while (left <= right ) {
middleIndex = (int)(left + right) / 2;
if (strcmp(student[middleIndex].name, search) == 0) {
rank = middleIndex+1;
break;
} else if (strcmp(student[middleIndex].name, search) > 0) {
left = middleIndex + 1;
} else if (strcmp(student[middleIndex].name,search) < 0) {
right = middleIndex - 1;
}
}
// Rank of the student's name that we search.
printf("%d", rank);
return 0;
}
I want to create a program that will return a student ranking (from 3 students). The fourth line is the name that we searched. I put all the user input into a struct and sort it in descending order to represent students ranking. But the problem is, when it reach the binary search, it always return unexpected value. Could you guys help me solve the problem?
Sample Input :
Jojo#40
Ray#60
Liz#80
Jojo -> name that we searched.
""" [ {Liz, 80}, {Ray, 60}, {Jojo,40} ] """
Output : 3
At least one problem is that your names (except the first) will have a newline as the first character. That newline was left in the input stream when scanning the score.
Consequently your string compare doesn't work.
Add this
for (int a = 0; a < 3; a++) printf("|%s|\n", student[a].name);
printf("|%s|\n", search);
just after scan of search and you get the output:
|Jojo|
|
Ray|
|
Liz|
|Jojo|
As you can see there are "unexpected" newlines in front of both "Ray" and "Liz"
To solve that add a space here
scanf(" %[^\#]#%d"
^
space
As noted by #EricPostpischil in a comment, sorting by score and doing binary search by name makes no sense. The sort and the search must be based on the same.
BTW: When sorting arrays use qsort

Updating specific elements in C array

I'm having trouble conceptualising how to go about some of my code.
My C program wishes to compare each individual element of an array of structs aka arr_person[i].name against a user's input to see if there's a match. (i.e. if the user types in "Billy" and "Billy" is also a string in arr_person[].name array)
for(i=0;i<num_of_lines;i++)
{
if(strcmp(nameInput, arr_person[i].name)==0) {
printf("Match at element %d\n", i);
}
}
Then, a separate function finds reoccurring elements within arr_person[i].name by iterating through the array, and if the same name occurs twice, it will take the corresponding integer values of the same elemental positions and will add them up and store in new variable newChange. For example, if "Billy" occurs twice in the array, at arr_person[0].name and arr_person[4].name, and arr_person[0].number = 15 and arr_person[4].number = 10, then I want to update the number such that it becomes 25.
for(i = 0; i < num_of_lines; i++) {
for(j=0;j<num_of_lines;j++) {
if(strcmp(arr_person[j].name, arr_person[i].name)==0)
*newNumber = arr_person[i].number + arr_person[j].number;
}
}
How do I go about this so that any elements in the array that don't reoccur are still kept the same?
If the user inputs "Rachel" and Rachel only appears once in the array, and her corresponding number is 85, I want to print
Rachel 85
But if the user inputs "Billy" and Billy occurs twice, and he has the two numbers 10 and 15 as corresponding integers in another array, I want to print
Billy 25
I've only been programming for a few months. Thanks in advance.
Seems like the only thing you need to do is this:
int sum = 0;
for(int i=0;i<num_of_lines;i++)
{
if(strcmp(nameInput, arr_person[i].name)==0)
sum += arr_person[i].number;
}
I would structure it like this:
// Previous code from your post slightly modified to function
// returns -1 on no match and index otherwise
int match(struct person *arr_person, char *nameInput, int num_of_lines)
{
for(int i=0;i<num_of_lines;i++) {
if(strcmp(nameInput, arr_person[i].name)==0)
return i;
}
return -1;
}
int sum(struct person *arr_person, char *nameInput, int num_of_lines)
{
int sum = 0;
for(int i=0;i<num_of_lines;i++) {
if(strcmp(nameInput, arr_person[i].name)==0)
sum += arr_person[i].number;
}
return sum;
}
int main()
{
// Insert code for declaration and initialization
int index = match(arr_person, nameInput, num_of_lines);
if(index >= 0) {
printf("Match at element %d\n", index);
printf("%s %d\n", nameInput, sum(arr_person, nameInput, num_of_lines));
} else {
printf("No match\n");
}
}

How to check first letter of one string with last letter of another string inside of same char array

How can I complete the function canArrangeWords() ?
Question : Given a set of words check if we can arrange them in a list such that the last letter of any word and first letter of another word are same. The input function canArrangeWords shall contain an integer num and array of words arr. num denotes the number of word in the list (1<=num<=100). arr shall contain words consisting of lower case letters between 'a' - 'z' only . return 1 if words can be arranged in that fashion and -1 if cannot.
Input : 4 pot ten nice eye
output : 1
input : 3 fox owl pond
output: -1
Please help me complete this program .
**
#include<stdio.h>
#include<string.h>
int canArrangewords(int,char [100][100]);
void main(){
int n ,count=0 , i ;
char arrayS[100][100];
scanf("%d",&n);
for (i = 0; i < n; ++i)
{
scanf("%s",arrayS[i]);
}
for(i=0;i<n;i++)
{
printf("%s",arrayS[i]);
printf("\n");
}
printf("%c\n",arrayS[2][4]);
canArrangewords(n , arrayS);
}
int canArrangewords(int n,char arrayS[100][100]){
int i , j ;
for ( i = 0; i < n; i++)
{
for ( j = i+1 ; j < strlen(arrayS[j+1]); i++)
{
int flag = strlen(arrayS[j+1]) - 1;
int temp = strcmp(arrayS[i][0],arrayS[j][flag]);
}
}
}
}
Well, first of all think of the way you can reach that answer.
If you only need to know if they can or can not be arranged and you do not have to do so your self you can use an empty array of int array[26] for each letter a-z.
The rule is that from all the first and last letters for all the words only two MAY appear an odd amount of times - the first letter of first word in list and the last letter in the last word in the list, the rest MUST appear an even amount of times. I would add a check to make sure the letters are lowercase as well. good luck!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MINASCII 97
#define LETTERS 26
void UpdateArray(char letter, int* arr)
{
if(arr[letter - MINASCII] == 0)
{
++arr[letter - MINASCII];
}
else
{
--arr[letter - MINASCII];/*for each second time same letter is seen reduce back to zero */
}
}
int canArrangewords(int wordNum, char* wordArr[])
{
int arr[LETTERS] = {0};
int i = 0;
int count = 0 ;
char first;
char last;
char* string;
for (i= 0; i< wordNum; ++i)
{
string = wordArr[i];
first = string[0];
last = string[strlen(string)-1];
UpdateArray(first, &arr[0]);
UpdateArray(last, &arr[0]);
}
for(i = 0; i< LETTERS; ++i)
{
count+=arr[i];
}
if(count == 2 || count == 0)/*either once each or twice -see word1 example in main*/
{
return 1;
}
return -1;
}
int main()
{
int i = 0;
char* words[] = {"pot", "ten", "nice", "eye"};
char* words1[] = {"pot", "ten", "nip"};
char* words2[] = {"fox", "owl", "pond"};
i = canArrangewords(4,words);
printf("%d\n", i);
i = canArrangewords(3,words1);
printf("%d\n", i);
i = canArrangewords(3,words2);
printf("%d\n", i);
return 0;
}
Change your array of words into an array of pointers to words. Then you can simply exchange the pointers.
To speed things up, instead of a pointer to a word, have it point to a structure:
struct WORD {
char *firstchar; // begin of word
char *lastchar; // last char of word
} *words[100]; // array of 100 pointers to words
To read the words:
char buf[100];
for (i = 0; i < n; ++i)
{
scanf("%s",buf);
int len= strlen(buf);
words[i]= malloc(sizeof(struct WORDS));
words[i]->firstchar= malloc(len+1);
strcpy(words[i]->firstchar, buf);
words[i]->lastchar= words[i]->firstchar + len-1;
}
Now compare and sort:
if (*words[i]->lastchar == *words[j]->firstchar) {
struct WORDS *tmp= words[i+1];
words[i+1]= words[j];
words[j]= tmp;
}
Do this in a loop, a kind of bubble sort. I leave that to you.

Count of similar characters without repetition, in two strings

I have written a C program to find out the number of similar characters between two strings. If a character is repeated again it shouldn't count it.
Like if you give an input of
everest
every
The output should be
3
Because the four letters "ever" are identical, but the repeated "e" does not increase the count.
For the input
apothecary
panther
the output should be 6, because of "apther", not counting the second "a".
My code seems like a bulk one for a short process. My code is
#include<stdio.h>
#include <stdlib.h>
int main()
{
char firstString[100], secondString[100], similarChar[100], uniqueChar[100] = {0};
fgets(firstString, 100, stdin);
fgets(secondString, 100, stdin);
int firstStringLength = strlen(firstString) - 1, secondStringLength = strlen(secondString) - 1, counter, counter1, count = 0, uniqueElem, uniqueCtr = 0;
for(counter = 0; counter < firstStringLength; counter++) {
for(counter1 = 0; counter1 < secondStringLength; counter1++) {
if(firstString[counter] == secondString[counter1]){
similarChar[count] = firstString[counter];
count++;
break;
}
}
}
for(counter = 0; counter < strlen(similarChar); counter++) {
uniqueElem = 0;
for(counter1 = 0; counter1 < counter; counter1++) {
if(similarChar[counter] == uniqueChar[counter1]) {
uniqueElem++;
}
}
if(uniqueElem == 0) {
uniqueChar[uniqueCtr++] = similarChar[counter];
}
}
if(strlen(uniqueChar) > 1) {
printf("%d\n", strlen(uniqueChar));
printf("%s", uniqueChar);
} else {
printf("%d",0);
}
}
Can someone please provide me some suggestions or code for shortening this function?
You should have 2 Arrays to keep a count of the number of occurrences of each aplhabet.
int arrayCount1[26],arrayCount2[26];
Loop through strings and store the occurrences.
Now for counting the similar number of characters use:
for( int i = 0 ; i < 26 ; i++ ){
similarCharacters = similarCharacters + min( arrayCount1[26], arrayCount2[26] )
}
There is a simple way to go. Take an array and map the ascii code as an index to that array. Say int arr[256]={0};
Now whatever character you see in string-1 mark 1 for that. arr[string[i]]=1; Marking what characters appeared in the first string.
Now again when looping through the characters of string-2 increase the value of arr[string2[i]]++ only if arr[i] is 1. Now we are tallying that yes this characters appeared here also.
Now check how many positions of the array contains 2. That is the answer.
int arr[256]={0};
for(counter = 0; counter < firstStringLength; counter++)
arr[firstString[counter]]=1;
for(counter = 0; counter < secondStringLength; counter++)
if(arr[secondString[counter]]==1)
arr[secondString[counter]]++;
int ans = 0;
for(int i = 0; i < 256; i++)
ans += (arr[i]==2);
Here is a simplified approach to achieve your goal. You should create an array to hold the characters that has been seen for the first time.
Then, you'll have to make two loops. The first is unconditional, while the second is conditional; That condition is dependent on a variable that you have to create, which checks weather the end of one of the strings has been reached.
Ofcourse, the checking for the end of the other string should be within the first unconditional loop. You can make use of the strchr() function to count the common characters without repetition:
#include <stdio.h>
#include <string.h>
int foo(const char *s1, const char *s2);
int main(void)
{
printf("count: %d\n", foo("everest", "every"));
printf("count: %d\n", foo("apothecary", "panther"));
printf("count: %d\n", foo("abacus", "abracadabra"));
return 0;
}
int foo(const char *s1, const char *s2)
{
int condition = 0;
int count = 0;
size_t n = 0;
char buf[256] = { 0 };
// part 1
while (s2[n])
{
if (strchr(s1, s2[n]) && !strchr(buf, s2[n]))
{
buf[count++] = s2[n];
}
if (!s1[n]) {
condition = 1;
}
n++;
}
// part 2
if (!condition ) {
while (s1[n]) {
if (strchr(s2, s1[n]) && !strchr(buf, s1[n]))
{
buf[count++] = s1[n];
}
n++;
}
}
return count;
}
NOTE: You should check for buffer overflow, and you should use a dynamic approach to reallocate memory accordingly, but this is a demo.

Perform Selection Sort On 2D Char Array

I currently have a 2D char array size: [5][256].
The array can hold either numbers or letters.
I have been tasked with using the Selection Sort to sort the strings into ascending order.
My idea is to convert each row into ASCII and then sort the values in ascending order then convert back to chars.
Ive implemented a 2D Array Selection sort for another task, however, it doesnt work here as i coded it to work with 2 columns not 256 like here (not sure how to change it).
What i need help with is how do i use the ASCII value for each row and use it in a selection sort.
Been trying to figure this out for hours now, driving me mental.
Any help is appreciated.
Im not necessarily looking for someone to code everything for me, more of a kick in the right direction. Im new to C and not aware of every function C can do.
Here is my current code in full:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char arc5Strings[5][256];
int nCount, nCount2, nCount3, nCount4, nCount5, nCount6, nCount7;
int fMinVal[1][2] = {1,1};
int nMinValPosition;
int nMoves;
int nRow;
int fTemp[1][2] = {1,1};
int fTemp2[1][2] = {1,1};
//input the values
for(nCount=0; nCount < 5; nCount++)
{
printf("Please input string %d/5: ", nCount + 1);
fgets(arc5Strings[nCount], 256, stdin);
}
printf("\n\n");
//print entire array
for(nCount3 = 0; nCount3 < 5; nCount3++)
{
for(nCount4 = 0; arc5Strings[nCount3][nCount4] != '\0'; nCount4++)
{
printf("%d ", arc5Strings[nCount3][nCount4]);
//ASCII values outputted in a line instead of in array format when using %c
}
}
return 0;
}
Old 2D Array selection sort i devised - extracted from code:
//-----------------------------------
//set up the switch
for(nCount5 = 0; nCount5 < 5; nCount5++)
{
fMinVal[0][0] = arc5Strings[nCount5][0]; //min value is row 0 col 1
nMinValPosition = nCount5;
for(nCount6 = nCount5 + 1; nCount6 < 5; nCount6++)
{
if(arc5Strings[nCount6][1] < fMinVal[0][0])
{
fMinVal[0][0] = arc5Strings[nCount6][0];
nMinValPosition = nCount6;
}
/* Perform the switch - actually switch the values */
if(fMinVal[0][0] < arc5Strings[nCount5][0])
{
fTemp[0][1] = arc5Strings[nCount5][1];
fTemp2[0][0] = arc5Strings[nCount5][0];
arc5Strings[nCount5][1] = arc5Strings[nMinValPosition][1];
arc5Strings[nCount5][0] = arc5Strings[nMinValPosition][0];
arc5Strings[nMinValPosition][1] = fTemp[0][1];
arc5Strings[nMinValPosition][0] = fTemp2[0][0];
nMoves++;
}
}
}
//------------------------------
printf("\n\n");
printf("The sorted list, in ascending order, using selection sort, is:\n\n");
for(nCount3 = 0; nCount3 < 5; nCount3++)
{
for(nCount4 = 0; arc5Strings[nCount3][nCount4] != '\0'; nCount4++)
{
printf("%c", arc5Strings[nCount3][nCount4]);
}
}
printf("\n %d moves were made to sort this list\n", nMoves);
EDIT - RESULTS OF GEORGE'S ANSWER:
Input1 = 90
Input2 = 70
Input3 = abc
Input4 = 500
Input5 = 200
Sorted Array Results:
200
90
70
abc
500
You're on the right track. I would implement this as follows:
for(i=0;i<5;i++)
{
indexOfCurrentSmallest = i;
for(j=i;j<5;j++)
{
for(k=0;k<255;k++)
{
if(arc5Strings[j][k] < arc5Strings[indexOfCurrentSmallest][k])
{
//we found a new possible smallest
indexOfCurrentSmallest = j;
break;
}
else if(arc5Strings[j][k] > arc5Strings[indexOfCurrentSmallest][k])
{
//no point in searching further, the one we are looking at is already larger than the one we found.
break;
}
}
}
//here, we have found the actual smallest, let's do a swap
for(q=0;q<255;q++)
{
temp = arc5Strings[i][q];
arc5Strings[i][q] = arc5Strings[indexOfCurrentSmallest][q];
arc5Strings[indexOfCurrentSmallest][q] = temp;
}
}
I haven't tested this code, but it should be roughly what you're looking for. Basically, it compares ASCII values starting at the left, until it finds a difference, and stores the index for later swapping after comparing all 5 strings.
EDIT I've now tested the code above, and it works now.
First find each string length
int length[5];
for(i = 0, i < 5, i++){
length[i] = strlen(arc5Strings[i]);
}
Sort the lengths. Those with the same, compare the value of the first letter.
Thats it.
valter

Resources