Please Help me with this ! [ Sorting Arrays] - arrays

Hello Everyone I created an address book by using arrays !... Here I got a problem with sorting arrays of type String .... When I want to Sort a contacts It will just Sort the first names Without moving Second name and phone numb..... etc .. I have no clear Idea about Moving whole line to sort in the address book ! ... I mean moving [first name, surname, phone number, Email] at the same time to the next line !... here is my Code!
void sortRecords() {
ofstream Cfile;
Cfile.open("addressbook.txt", ios::in);
string temp;
for (int i=0; i<line()-1; ++i)
{
for (int j=0; j<line()-1-i; j++)
{
while (first_name[j]>first_name[j+1])
{
temp= first_name[j+1];
first_name[j+1]=first_name[j];
first_name[j]=temp;
}
}
}
for (int p=0; p<line();p++)
{
Cfile<<first_name[p]<<setw(10)<<sur_name[p]<<setw(10)<<phone_number[p]<<setw(10)<<email[p]<<endl;
}
Cfile.close();
}

The efficient way to do this is with a second (numerical) array of "indirection pointers" - which say "the item originally at i is now at j". Then you only have to swap these indices around; but when you're done, you can generate the sorted array by running down this index array just once and making a copy of the elements. This is usually a good way to do it when you are sorting "bunches of stuff".
Alternatively, you just move all the items to their new location; you will want to write a "swap" function to keep your code legible...
It is usually a good idea, when you want to keep a bunch of related items together in an array, to declare a structure. In your case, this structure might look like this:
typedef struct {
char first_name[32];
char last_name[32];
char phone_number[16];
} entry;
Then you can declare your phone book as
entry phoneBook[100];
which would create enough space for 100 phonebook entries.
Finally, when you go through the list of entries, you might modify your bubble sort like this (assuming that n = number of entries):
for ( int i=0; i < n - 1; i++ )
{
for ( int j = i; j < n; j++ )
{
if (strcmpi(entries[j].first_name, entries[j+1].first_name) > 0)
{
swap(entries, j, j+1);
}
}
}
And finally you would have a swap function like this:
void swap(entry* e, int i, int j) {
// swap all elements of e[i] and e[j]
entry temp;
strcpy(temp.first_name, e[i].first_name);
strcpy(temp.last_name, e[i].last_name);
strcpy(temp.phone_number, e[i].phone_number;
strcpy(e[i].first_name, e[j].first_name);
strcpy(e[i].last_name, e[j].last_name);
strcpy(e[i].phone_number, e[j].phone_number;
strcpy(e[j].first_name, temp.first_name);
strcpy(e[j].last_name, temp.last_name);
strcpy(e[j].phone_number, temp.phone_number;
}

Related

How to reduce the time complexity of seaching the same character in two different strings in C?

Input contains a
n
which indicated the total amount of the strings.
Then use scanf to scan those strings.
The task is that find out if two strings have the same characters.
If so,they are in the same group.
Two string belongs to same group if :
1.there exists a character that exist in both string.
2.there exists a character in both string A and B,
and there exists another character in both string B and C,
then A, B, C belong to same group.
for example
>>input
5
abbbb
a
c
ddca
fgg
Here "abbbb","a","c","ddca" are in the same group
and output the total numbers of groups
in this example is
2
Every characters in the strings only contains 'a'~'z'
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct str //'ini' is used to save the initial strings 'convert' recorded the characters converted to ascii code then -'a'
{
char ini[1001];
int convert[1001];
} STR;
STR a[2002];
int visited[2002];// record the index that has been traverse
int count;//record the total number of groups
int record[26];//there is 26 characters from'a'~'z'
int check(int index1,int index2)
{
int len_1=strlen(a[index1].ini);
int len_2=strlen(a[index2].ini);
for(int i=0; i<26; i++)//reset
{
record[i]=0;
}
for(int i=0; i<len_1; i++)//traverse the first string and recorded the characters in "record"array
{
record[a[index1].convert[i]]=1;
}
for(int i=0; i<len_2; i++)
{
if(record[a[index2].convert[i]]==1)//if they have same characters
{
return 1;
}
}
return 0;
}
void dfs(int now,int n)//now record index ,n record the total index
{
visited[now]=1;
for(int i=0; i<n; i++)
{
if(i==now) continue;
if(visited[i]==1) continue;
if(check(i,now))
{
dfs(i,n);
}
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%s",a[i].ini);
int len=strlen(a[i].ini);//recording the length of the input string
for(int j=0; j<len; j++) //convert every characters in the ini string to ascii then -'a', recording in 'convert' int array
{
char ch=a[i].ini[j];
a[i].convert[j]=ch-'a';
}
}
for(int i=0; i<n; i++)//dfs
{
if(visited[i]==0)
{
count++;
dfs(i,n);
}
}
printf("%d\n",count);
return 0;
}
I tried to use DFS to search it, and use every strings as a node
Is that any better way to reduce the time complexity?
Can it be more faster?
You iterate over each string 2 times (strlen + the for loop). That's rather inefficient.
When done looking through the string(s), there shouldn't be a need to search for anything, if you place the results in a sensible way.
Ideally keep track of the results from each string separately.
Something like this (naive implementation):
#define LETTERS 26
void str_common (const char* s1, const char* s2)
{
bool record1 [LETTERS]={false};
bool record2 [LETTERS]={false};
for(size_t i=0; s1[i]!='\0'; i++)
{
record1[s1[i]-'a']=true;
}
for(size_t i=0; s2[i]!='\0'; i++)
{
record2[s2[i]-'a']=true;
}
for(size_t i=0; i<LETTERS; i++)
{
if(record1[i] && record2[i])
{
putchar('a' + i);
}
}
}
This is naive code because it has no error handling and also assumes that all letters in the symbol table are adjacent, which C makes no guarantees for. Still it gives something to start with.
You can rewrite this function to only work with one string at a time and instead of printing, returning the record array to the caller. Comparing which letters that exists in your 3 different strings then becomes trivial, just change the if(record1[i] && record2[i]) check to contain as many strings and conditions as you need.
There is a place for some optimization. First, drop the convert arrays and replace it with bool usedLetters[256];. Fill it after reading each string with a simple loop over the string:
scanf("%s",a[i].ini);
for(int j=0; a[i].ini[j] != 0; j++) //scan the string till its end
{
unsigned char ch=a[i].ini[j]; // get a next character
a[i].usedLetters[ch] = true; // and note it's used
}
Then checking whether two strings share a letter requires a parallel scanning of both corresponding usedLetters[]:
int check(int index1,int index2)
{
bool *used1 = a[index1].usedLetters;
bool *used2 = a[index2].usedLetters;
for(int i=0; i < 256; i++) // iterate over all possible chars
{
if(used1[i] && used2[i]) // char(i) used in both strings?
return 1;
}
return 0;
}
However, the main cost is in your scanning routine. It's not DFS (unless you consider the whole set of strings as a full graph) – for each string visited you try to compare it to all strings in a set, then discarding those already visited. As a result, your routine performs up to N^2 iterations of a loop and (in a worst case of all strings disjoint) up to ~(N^2)/2 calls to check() (it will need to identify N one-string 'groups', each time checking a starting string against N/2 other strings on average).

Merge sort in array of structs

I have an array of structs, where each object is a student with a name and a grade, and I'm trying to merge sort this array (I want to sort them by grade in ascending order).
Here is the Student Struct:
struct Student
{
char grade[42];
char city[42];
};
grade is a char because I assign the grade value by getting an input from the user with fgets and sscanf.
I don't think it's necessary to put my whole code of the merge-sort algorithm but I want to share this part which I think might be problematic ?
int firstHalfSize = midElement - firstElement + 1;
int secondHalfSize = lastElement - midElement;
struct Student firstHalfArray[firstHalfSize];
struct Student secondHalfArray[secondHalfSize];
char *p;
char *s;
int index1 = 0;
int index2 = 0;
int mergedArrIndex = firstElement;
while (index1 < firstHalfSize && index2 < secondHalfSize)
{
if (strtol(firstHalfArray[index1].grade, &p, 10) <= strtol(secondHalfArray[index2].grade, &s, 10))
{
arr[mergedArrIndex] = firstHalfArray[index1];
index1++;
}
else
{
arr[mergedArrIndex] = secondHalfArray[index2];
index2++;
}
mergedArrIndex++;
}
the part where I sort the student object by comparing the grade is by converting the char grade into a long with strtol which I think I did good so it might not be a problem.
My problems is that I initialize my array of structs like the following:
struct Student students[5501];
and when I get a new input of the user I just add it into the array like the following:
struct Student aStudent;
int lineCounter = 0;
students[lineCounter] = aStudent;
and increase lineCounter by 1 every time I get a new input. (aStudent is changed when I get a new input)
Here I call the merge-sort function and get weird results:
mergeSort(students, 0, 5501); // 5501 is the size of the array
printArray(students, 5501);
Here is the printArray function created just to see if I get the grade in ascending order
void printArray(struct Student A[], int size)
{
char *p;
int i;
for (i=0; i < size; i++)
printf("%ld", strtol(A[i].grade, &p, 10));
}
but I keep getting that printed:
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
and I don't know why.
Also how can I do that If the user adds 3 students object in the array students
I only treat it as like an array of 3 elements and not an array of 5501 elements ?
Thanks! And sorry if it's a little long I really tried to be concise without having a loss of essential informations.
Since the user can input N numbers of students I recommend you to use a Linked List instead and put the node (struct Student) in his right position depending on the grade.
You can learn more about Linked Lists here.

C: How to sort a Struct by one of its element? Can't use pointers

How do I sort struct like this one:
typedef struct
{
int weight;
int price;
Color color;
Equip equip;
}Cars;
by one of it's attributes like price, or weight? Automobil array is previously declared.
I can't use pointers, and any other built-in function.
Cars automobil[5];
Cars mobilOne={};
for(i=0; i<5; i++)
{
if((i+1)==5)
{
break;
}else
{
if (automobil[i].weight> automobil[i+1].weight)
{
mobilOne = automobil[i];
automobil[i] = automobil[i+1];
automobil[i+1] = mobilOne;
}
}
}
I tried to do this, this way, but it does not do anything...
Also if someone could tell me, how can I pass a struct like this one into a function I would be really thankful!
OK, well first what you are trying to do is not quite as bad as some people might tell you as for small N bubble sort is still pretty fast. The following will do you and of course you need a double loop:
int main() {
Cars automobil[NC];
// Initialiase automobil here
for (int i = 0; i < NC - 1; ++i) {
int am = i;
for (int j = i+1; j < NC; ++j) {
if ( automobil[am].weight > automobil[j].weight )
am = j;
}
if ( am != i) {
Cars tmp = automobil[am];
automobil[am] = automobil[i];
automobil[i] = tmp;
}
}
for (int i = 0; i < NC; ++i)
printf("%d\n", automobil[i].weight);
}
Notice that we can copy structs but even here we try to do it as little as possible.
However, it's very easy to say "I'll never have more than ten cars" and then find you are trying to sort several thousand so I would urge you to learn and understand qsort():
int carsSort(const void *a, const void *b) {
return ((Cars *) a)->weight - ((Cars *) b)->weight;
}
int main() {
Cars automobil[NC];
// Initialiase automobil here
qsort(automobil, NC, sizeof *automobil, carsSort);
for (int i = 0; i < NC; ++i)
printf("%d\n", automobil[i].weight);
}
John
PS: in reply to "how do I pass the array to a function?" remember one of the many wise sayings of K&R: "When an array name is passed to a function, what is passed is the location of the beginning of the array".
Hence:
int carsSort(const void *a, const void *b) {
return ((Cars *) a)->weight - ((Cars *) b)->weight;
}
void sortThem(Cars autom[]) {
qsort(autom, NC, sizeof *autom, carsSort);
}
int main() {
Cars automobil[NC];
// Initialiase automobil here
sortThem(automobil);
for (int i = 0; i < NC; ++i)
printf("%d\n", automobil[i].weight);
}
Inside sortThem() "autom" is a variable whose value is the address of automobil[0].
Without going into implementation details here is a procedural algorithm for a bubble sort (not in C): Bubble Sort Algorithm. Note, as mentioned in comments, this bubble sort implementation uses nested loops.
One other item to keep in mind: In order to switch two objects, a third temporary object of the same type needs to be used. For example:
int temp
int arr1[]={2,5,7,2,9,1,8,0,5,2,1};
int count = sizeof(arr1)/sizeof(arr1[0])
for(int i = 0; i < count-1; i++ )
{
if(arr1[i]>arr1[i+1])
{
temp = arr1[i];
arr1[i] = arr1[i+1];
arr[i+1] = temp;
}
}
Because you are sorting on a single member of a collection of members, the assignment swapping routine will need to swap every member each time the condition for a swap exists, i.e. although determining if the swap condition exists only considers one member, swapping will include all members: weight, price, Color and Equip. And, if Color and Equip are of struct type (your post does not specify), then each member of these objects belonging to array elements being compared, will also need to be swapped.
You should look forward to eventually using pointers as this will significantly reduce the number of assignment statements needed to complete this sort.

Navigating 2D arrays by category?

Once again, I'd like to thank everyone for their prompt responses to my previous Gradebook question. I am now further along in the project, and have hit a (in my opinion) thornier problem.
The instructions call for me to create a function with this prototype:
int set_assignment_score(Gradebook *gb, char name[MAX_NAME_LEN], char a_name[], int score);
Once again, it will enter the Gradebook structure through the *gb pointer, but this time, it is meant to access the Scores array:
int scores[MAX_NUMBER_OF_STUDENTS][MAX_NUMBER_OF_ASSIGNMENTS]
... and deposit the "score" integer inside a specific cell for further use. The two Char parameters are important, because later on I will need to retrieve each specific integer from the Scores array and match it up with its precise name and a_name in a print_gradebook function.
I would love to share what code I have so far, but the fact of the matter is that I barely know where to start. I think that the key, however, is knowing how to navigate an integer array using char name and char a_name in place of the usual [i] and [j].
Any suggestions, advice, mockery, or requests for clarification are welcome. Please.
Here is the Gradebook structure:
typedef struct gradebook {
int number_of_students;
Students students[MAX_NUMBER_OF_STUDENTS];
int number_of_assignments;
char assignment_names[MAX_NUMBER_OF_ASSIGNMENTS][MAX_NAME_LEN + 1];
int scores[MAX_NUMBER_OF_STUDENTS][MAX_NUMBER_OF_ASSIGNMENTS];
} Gradebook;
EDIT: Thanks, everyone! Combining your advice, I came up with this:
int set_assignment_score(Gradebook *gb, const char name[MAX_NAME_LEN], const char a_name[], int score) {
int i, j;
for(i=0; i< MAX_NUMBER_OF_STUDENTS; i++) {
if(strcmp(gb->students[i].name, name) == 0) {
for(j=0; j< MAX_NUMBER_OF_ASSIGNMENTS; j++) {
if(strcmp(gb->assignment_names[j], a_name) == 0) {
gb->scores[i][j] = score;
}
}
}
}
printf("%d\n", gb->scores[i][j]);
return 1;
}
I suspect it's a lot clumsier than it needs to be, but it gets the job done. Funnily enough, the printf function I put in to test it doesn't provide the result I want (I guess I'm printing the address or something?), but the actual function does.
Yes, that's the general idea. The reason the printf doesn't work is because the loops continue running after you've found the matching student name and assignment name. So after the loops are done, you've lost the values of i and j. In fact, after the loops are done, i==MAX_NUMBER_OF_STUDENTS and j==MAX_NUMBER_OF_ASSIGNMENTS.
To keep the values of i and j, you should break from the loop when you find the matching name. (I also added some error checking to handle the case where one or both of the names aren't found.)
int set_assignment_score(Gradebook *gb, const char name[MAX_NAME_LEN], const char a_name[], int score)
{
int i, j;
for(i=0; i< MAX_NUMBER_OF_STUDENTS; i++)
if(strcmp(gb->students[i].name, name) == 0)
break;
for(j=0; j< MAX_NUMBER_OF_ASSIGNMENTS; j++)
if(strcmp(gb->assignment_names[j], a_name) == 0)
break;
if ( i == MAX_NUMBER_OF_STUDENTS || j == MAX_NUMBER_OF_ASSIGNMENTS )
{
printf( "unable to set score (i=%d, j=%d)\n", i, j );
return 0;
}
gb->scores[i][j] = score;
printf("%d\n", gb->scores[i][j]);
return 1;
}

function should take two arguments , an array and the size of the array

I need help with the following please:
define a function that returns the population of the smallest city
(popolation wise) in an array of cities. the function should take two
arguments: an array of cities and the length of the array.
this is my code:
struct city
{
char name[20];
int pop;
};
int func1(struct city cities[], int i) // these are the arguments
{
for(i=0; i<2; i++)
{
cities[i].pop;
}
cities[0].pop=2500;
cities[1].pop=3000;
return cities[0].pop;
}
I just want this to work, but it dosnt compile and dosnt give errors ether.
There are few errors in your code.
For instance, you can't find the array size by looping in the array. It only works for "string" because they have a end character '\0'.
The size of the array, as you mentionned is passed on the second argument of your function.
So what you want to do is, I suppose :
int func1(struct city cities[], size_t i) // these are the arguments
{
if (i == 0)
return 0;
int min = cities[0].pop;
for(size_t j=1; j < i; ++j)
{
min = cities[i].pop < min ? cities[i].pop : min;
}
return min;
}
Regards.

Resources