Perform Selection Sort On 2D Char Array - c

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

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");
}
}

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.

Transform an array to another array by shifting value to adjacent element

I am given 2 arrays, Input and Output Array. The goal is to transform the input array to output array by performing shifting of 1 value in a given step to its adjacent element. Eg: Input array is [0,0,8,0,0] and Output array is [2,0,4,0,2]. Here 1st step would be [0,1,7,0,0] and 2nd step would be [0,1,6,1,0] and so on.
What can be the algorithm to do this efficiently? I was thinking of performing BFS but then we have to do BFS from each element and this can be exponential. Can anyone suggest solution for this problem?
I think you can do this simply by scanning in each direction tracking the cumulative value (in that direction) in the current array and the desired output array and pushing values along ahead of you as necessary:
scan from the left looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the right
scan from the right looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the left
For your example the steps would be:
FWD:
[0,0,8,0,0]
[0,0,7,1,0]
[0,0,6,2,0]
[0,0,6,1,1]
[0,0,6,0,2]
REV:
[0,1,5,0,2]
[0,2,4,0,2]
[1,1,4,0,2]
[2,0,4,0,2]
i think BFS could actually work.
notice that n*O(n+m) = O(n^2+nm) and therefore not exponential.
also you could use: Floyd-Warshall algorithm and Johnson’s algorithm, with a weight of 1 for a "flat" graph, or even connect the vertices in a new way by their actual distance and potentially save some iterations.
hope it helped :)
void transform(int[] in, int[] out, int size)
{
int[] state = in.clone();
report(state);
while (true)
{
int minPressure = 0;
int indexOfMinPressure = 0;
int maxPressure = 0;
int indexOfMaxPressure = 0;
int pressureSum = 0;
for (int index = 0; index < size - 1; ++index)
{
int lhsDiff = state[index] - out[index];
int rhsDiff = state[index + 1] - out[index + 1];
int pressure = lhsDiff - rhsDiff;
if (pressure < minPressure)
{
minPressure = pressure;
indexOfMinPressure = index;
}
if (pressure > maxPressure)
{
maxPressure = pressure;
indexOfMaxPressure = index;
}
pressureSum += pressure;
}
if (minPressure == 0 && maxPressure == 0)
{
break;
}
boolean shiftLeft;
if (Math.abs(minPressure) > Math.abs(maxPressure))
{
shiftLeft = true;
}
else if (Math.abs(minPressure) < Math.abs(maxPressure))
{
shiftLeft = false;
}
else
{
shiftLeft = (pressureSum < 0);
}
if (shiftLeft)
{
++state[indexOfMinPressure];
--state[indexOfMinPressure + 1];
}
else
{
--state[indexOfMaxPressure];
++state[indexOfMaxPressure + 1];
}
report(state);
}
}
A simple greedy algorithm will work and do the job in minimum number of steps. The function returns the total numbers of steps required for the task.
int shift(std::vector<int>& a,std::vector<int>& b){
int n = a.size();
int sum1=0,sum2=0;
for (int i = 0; i < n; ++i){
sum1+=a[i];
sum2+=b[i];
}
if (sum1!=sum2)
{
return -1;
}
int operations=0;
int j=0;
for (int i = 0; i < n;)
{
if (a[i]<b[i])
{
while(j<n and a[j]==0){
j++;
}
if(a[j]<b[i]-a[i]){
operations+=(j-i)*a[j];
a[i]+=a[j];
a[j]=0;
}else{
operations+=(j-i)*(b[i]-a[i]);
a[j]-=(b[i]-a[i]);
a[i]=b[i];
}
}else if (a[i]>b[i])
{
a[i+1]+=(a[i]-b[i]);
operations+=(a[i]-b[i]);
a[i]=b[i];
}else{
i++;
}
}
return operations;
}
Here -1 is a special value meaning that given array cannot be converted to desired one.
Time Complexity: O(n).

UnExpected Results From 2 Sort Methods 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

Resources