QuickSort not sorting properly - c

I have a this program to receive a struct, store it and then sort it. I have tried to use Shell Sort, but then I went for the Quick Sort Algorithm. However, when I try to print the array after sorting, it still returns it unsorted. Bear in mind im trying to sort it by 'num_aluno'.
CODE
typedef struct ALUNO
{
char primeiro_nome[15];
char segundo_nome[15];
int num_aluno;
float nota;
}ALUNO;
void swap(ALUNO* a, ALUNO* b)
{
ALUNO t=*a;
*a=*b;
*b=t;
}
int partition(ALUNO *studentList, int low, int high)
{
int pivot= studentList[high].num_aluno;
int i=(low-1);
int j;
for(j=low;j<=high-1;j++)
{
if(studentList[j].num_aluno<=pivot);
{
i++;
swap(&studentList[i], &studentList[j]);
}
}
swap(&studentList[i+1], &studentList[high]);
return(i+1);
}
void quickSort(ALUNO *studentList, int low, int high)
{
if(low<high)
{
int pi=partition(studentList, low, high);
quickSort(studentList, low, pi-1);
quickSort(studentList, pi+1, high);
}
}
int main()
{
ALUNO *studentList=NULL;
int currentPos, studentListSize=1;
//float grade_sum=0;
studentList=(ALUNO*)calloc(studentList, studentListSize*sizeof(ALUNO));
printf("Insira o numero de alunos \n");
scanf("%d", &studentListSize);
studentList=(ALUNO*)realloc(studentList, studentListSize*sizeof(ALUNO));
for(currentPos=0;currentPos<studentListSize;currentPos++)
{
newStudent(studentList, currentPos);
}
quickSort(studentList, 0, studentListSize);
for(currentPos=0;currentPos<studentListSize;currentPos++)
{
printStudent(studentList,currentPos);
}
free(studentList);
return 0;
}
Any help would be appreciated

The reason it doesn't sort the list is, i and j are always the same value in the partition function.
You should start j from high -1, not from low.
Also, you are not considering the values of studentList[i]. You must guarantee that it is larger than pivot, otherwise there may be a value which is smaller than the pivot, yet at the left part of the array.
Here, corrected it.
int partition(ALUNO*studentList, int low, int high)
{
int pivot = studentList[high].num_aluno;
int i=low ;
int j;
for(j=high-1;j>=i;)
{
while(studentList[i].num_aluno < pivot)
i++;
while(studentList[j].num_aluno > pivot)
j--;
if(i<=j){
swap(&studentList[i], &studentList[j]);
i++;
j--;
}
}
swap(&studentList[i], &studentList[high]);
return(i+1);
}
An additional advice in case you have not heard of it, do not choose the first or last values as pivots. Instead, use the median of three strategy.
Median of three strategy: Pick the first, middle and last elements in the unsorted array. Change their locations according to their values in a sorted manner. Then take the middle value and use it as a pivot. This way you are avoiding the worst time complexity(O(n^2)) of QuickSort.

Related

LCP array for Suffix Array

How to compute the LCP array for a suffix array? It doesn't have to be the most efficient. O(n log n) or O(n) will do. Something relatively easy to code if possible.
Here is a simple C++ implementation.
Longest common prefix(LCP) will be saved in lcp[MAX] array :)
char str[MAX];
int n,gap,sa[MAX],pos[MAX],tmp[MAX],lcp[MAX];
// sa stores the sorted index of the suffixes
// pos stores the serial number of a index in the sorted sequence
bool sufCmp(int i, int j)
{
if(pos[i]!=pos[j])
return pos[i]<pos[j];
i+=gap;
j+=gap;
return (i<n&&j<n)?pos[i]<pos[j]:i>j;
}
void buildSA()
{
n=strlen(str);
for(int i=0;i<n;i++)
sa[i]=i,pos[i]=str[i];
for(gap=1;;gap*=2)
{
sort(sa,sa+n,sufCmp);
for(int i=0;i<n-1;i++)
tmp[i+1]=tmp[i]+sufCmp(sa[i],sa[i+1]);
for(int i=0;i<n;i++)
pos[sa[i]]=tmp[i];
if(tmp[n-1]==n-1)
break;
}
}
void buildLCP()
{
for(int i=0,k=0;i<n;++i)
{
if(pos[i]==n-1)
lcp[pos[i]]=0;
else
{
for(int j=sa[pos[i]+1];str[i+k]==str[j+k];)
k++;
lcp[pos[i]]=k;
if(k)
k--;
}
}
}

Quicksort sorting issues

This might not be a conventional of doing quicksort.my first try at it.the numbers are not sorted in the way they should be.I have tried to sort a random list of numbers.However i am unable to identify the logical errors even after a strict checking.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int n;
int *expivot;
int *arr;
void quicksort();
void display();
int check();
main()
{
int i;
printf("to continue press 'a' always\n");
while(getch()=='a')
{
printf("Enter the length of list\n");
scanf("%d",&n);
time_t start,end;
double t;
start=clock();
arr=(int *)calloc(n,sizeof(int));
expivot=(int *)calloc(n,sizeof(int));
srand(time(NULL));
for(i=0;i<n;i++)
arr[i]=rand()%RAND_MAX + 1;
printf("\nelements inputted are:");
display();
quicksort();
end=clock();
t=(double)(end-start)/CLOCKS_PER_SEC;
printf("\n\nelements sorted are:");
display();
printf("\ntime take is %.15lf",t);
free(arr);
free(expivot);
}
}
void quicksort()
{
int low,high,temp;
int pivot=rand()%n;//generate random pivot
int store=pivot;
/*location of pivot might change due to swapping,so using store to store pivot location so as to add this to expivot list after running quickort once*/
int flag=1;
if(expivot[pivot]==1) // checks if it's an already used pivot
flag=0;
if(flag==1) //if the pivot is unused
{
low=pivot;
high=pivot;
while(low>0 && expivot[low]==0)
low--;
if(expivot[low]==1)//i
low++;
/*decrements low to a location where a value has been set permanently and then increase by 1,if nothing is set then decrements low to zero*/
/*increments high to a location where a value has been set permanently and then decrease by 1,if nothing is set then increments high to last index*/
while(high<n-1 && expivot[high]==0)
high++;
if(expivot[high]==1)
high--;
while(low<high)
{
if(arr[low]>=arr[pivot] && arr[high]<=arr[pivot])//checks swap possibilty
{
if(low==pivot) //if pivot is to be swapped store new location of pivot
store=high;
else if(high==pivot)
store=low;
temp=arr[low];
arr[low]=arr[high];
arr[high]=temp;
low++;
high--;
}
else
{
if(arr[low]<arr[pivot])
low++;
else if(arr[high]>arr[pivot])
high--;
}
}
expivot[store]=1;
/*final location of pivot,stores info that this location has a permanent value now
and cannot be used as a pivot*/
}
if(check()==1)
quicksort();
}
int check() //checks if there are any unused pivots
{
int i;
for(i=0;i<n;i++)
{
if(expivot[i]==0)
return 1;
}
return 0;
}
void display()
{
int i;
for(i=0;i<n;i++)
printf("%d ",arr[i]);
}
Your method is:
Randomly select a pivot from whole array;
From the pivot, spread a range to both direction, this range will be partitioned by the pivot;
All pivot will be cached in another array (item 5);
The range, mentioned in item 2 above, should apread as large as it can do, but: 1) should not beyond the range of whole array; 2) should not contain another pivot, if it does, stop and shrink one unit;
Partition the range by the pivot it spread from, then cache this pivot;
If all unit in the array has been selected as pivot, sorting is done. If not, repeat as above, over and over again.
There are three problems in your code:
1- "checd()"function should be:
int check() //checks if there are any unused pivots
{
int flag = 0;
int i;
for(i=0;i<n;i++)
{
if(expivot[i]==0)
flag = 1;
}
return flag;
}
You should check all member, see if they ALL satisfy your condition, but not one of them satisfy your condition.
2- While shrink the range, make sure the pivot is between "high" and "low" (equal is well). Keep tracking the index and value of the pivot. The while loop should be:
//"store" is not needed, change it to "pivot", even after this code block.
while(low<high)
{
if(arr[low]>=arr[pivot] && arr[high]<=arr[pivot])//checks swap possibilty
{
if(low==pivot) //if pivot is to be swapped store new location of pivot
pivot=high;
else if(high==pivot)
pivot=low;
temp=arr[low];
arr[low]=arr[high];
arr[high]=temp;
/////////////////////
if (low < pivot)
low++;
if (high > pivot)
high--;
/////////////////////
}
else
{
if(arr[low]<arr[pivot])
low++;
else if(arr[high]>arr[pivot])
high--;
}
}
3- Finally, once you get memory from calloc or malloc, check if it's NULL.
==================================
Additionally, you should make sure all unit in the array can be selected, because the random number in computer is mostly pseudo random number. So, maybe for a certain length, a particular unit cannot be chosen forever.
Quicksort is a Divide and Conquer algorithm. You cannot perform it without using stacks or recursion.
Edit: The function does use recursion (oops!). But this isn't quicksort. If your are changing the method of a standard sorting algorithm, then it is no more that algorithm.

Mergesort, weird behavior

Here's what I'm trying to do.
There are 3 arrays, cost[] node1[] and node2[].
These entires correspond to edges of a graph with node1[i],node2[i] and cost[i] specifying that there is an edge going from vertex node1[i] to node2[i] with an edge weight of cost[i].
I'm trying to sort these edges with respect to their weights, i.e sort the cost[] array using merge-sort. However whenever I'm, changing an entry in the cost[] array I also want to change the corresponding entries in the node1 and node2 array since even the nodes of the graph have to be modified. Ie if node1[]=1,2,3 and node2[]=2,3,1 cost[]={7 4 8} then after sorting the cost array the node1 and node2 should look like node1[]=2,1,3 node2[]=3,2,1. and cost[]=4,7,8
Here's my code.
#include<stdio.h>
#include<stdlib.h>
int merge_sort(int arr[],int low,int high,int node1[],int node2[])
{
int mid;
if(low<high) {
mid=(low+high)/2;
// Divide and Conquer
merge_sort(arr,low,mid,node1,node2);
merge_sort(arr,mid+1,high,node1,node2);
// Combine
merge(arr,low,mid,high,node1,node2);
}
return 0;
}
int merge(int arr[],int l,int m,int h,int node1[],int node2[])
{
int arr1[80000],arr2[80000]; // Two temporary arrays to
int arr3[70000],arr4[70000];
int arr5[70000],arr6[70000];
int n1,n2,i,j,k;
n1=m-l+1;
n2=h-m;
for(i=0; i<n1; i++)
{
arr1[i]=arr[l+i];
arr3[i]=node1[l+i];
arr5[i]=node2[l+i];
}
for(j=0; j<n2; j++)
{
arr2[j]=arr[m+j+1];
arr4[i]=node1[m+j+1];
arr6[i]=node2[m+j+1];
}
arr1[i]=99999; // To mark the end of each temporary array
arr2[j]=99999;
arr3[i]=99999;
arr4[j]=99999;
arr5[i]=99999;
arr6[j]=99999;
i=0;
j=0;
for(k=l; k<=h; k++) { //process of combining two sorted arrays
if(arr1[i]<=arr2[j])
{
arr[k]=arr1[i++];
//node1[k]=arr3[i++]; COMMENTED LINES!!!!!!!!!!!
//node2[k]=arr5[i++];
}
else
{
arr[k]=arr2[j++];
//node1[k]=arr4[j++]; COMMENTED LINES!!!!!!!!~!
//node2[k]=arr6[j++];
}
}
return(0);
}
int main(void)
{
int i,j,n,vert1,vert2,weight;
scanf("%d",&n);
int adjmat[n+1][n+1],cluster[n+1][n+1];
int *cost,*node1,*node2;
node1=malloc(sizeof(int)*1000000);
node2=malloc(sizeof(int)*1000000);
cost=malloc(sizeof(int)*1000000);
for(i=0;i<n+1;i++)
for(j=0;j<n+1;j++)
{
adjmat[i][j]=0;
cluster[i][j]=0;
}
for(i=1;i<n+1;i++)
cluster[i][0]=i;
for(i=1;i<(n+1)*(n+1);i++)
{
scanf("%d %d %d",&vert1,&vert2,&weight);
node1[i]=vert1;
node2[i]=vert2;
cost[i]=weight;
if(node1[i]==node1[i-1] && node2[i]==node2[i-1] && cost[i]==cost[i-1])
break;
// printf("%d %d %d\n",node1[i],node2[i],cost[i]);
adjmat[vert1][vert2]=weight;
adjmat[vert2][vert1]=weight;
}
printf("\n%d\n",i);
merge_sort(cost,1,124751,node1,node2);
for(j=1;j<i;j++)
printf("%d %d %d\n",node1[j],node2[j],cost[j]);
return(0);
}
Whenever I comment the lines in the merge function the code manages to sort the cost array. However whenever I un comment these lines somehow everything gets equated to 0. i.e all entires of the node1 node2 and cost arrays are 0. Could anyone tell me why this is happening? Thanks!
You probably have forgotten to take care of the side effect of the i++ operation. There is no need at all at that place to work with side effects, don't do that.

counting number of swaps in insertion sort

In the problem given here, i have to count total no. of swaps required while sorting an array using insertion sort.
here is my approach
#include <stdio.h>
int main()
{
int t, N, swaps, temp, i, j;
scanf("%d", &t);
while(t--){
scanf("%d", &N);
int arr[N];
swaps = 0;
for(i=0; i<N; ++i){
scanf("%d", &temp);
j=i;
while(j>0 && arr[j-1] > temp){
arr[j] = arr[j-1];
++swaps;
--j;
}
arr[j] = temp;
}
printf("%d\n", swaps);
}
return 0;
}
but, this soln is giving time limit exceeded.
How can i make it more fast?
and, what are the other better solutions of this problem?
this is a standard problem named inversion count
This can be solved using mergesort in O(n*lg(n)). Here is my code for counting the inversions
int a[200001];
long long int count;
void Merge(int p,int q,int r)
{
int n1,n2,i,j,k,li,ri;
n1=q-p+1;
n2=r-q;
int l[n1+1],rt[n2+1];
for(i=0;i<n1;i++)
l[i]=a[p+i];
for(i=0;i<n2;i++)
rt[i]=a[q+1+i];
l[n1]=LONG_MAX;
rt[n2]=LONG_MAX;
li=0;ri=0;
for(i=p;i<=r;i++)
{
if(l[li]<=rt[ri])
a[i]=l[li++];
else
{
a[i]=rt[ri++];
count+=n1-li;
}
}
}
void mergesort(int p,int r)
{
if(p<r)
{
int q=(p+r)/2;
mergesort(p,q);
mergesort(q+1,r);
Merge(p,q,r);
}
}
int main()
{
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
count=0;
mergesort(0,n-1);
printf("%lld\n",count);
}
Basically the problem of inversion count is to find the no. of pairs i and j where j>i such that a[i]>a[j]
To know the idea behind this you should know the basic merge sort algorithm
http://en.wikipedia.org/wiki/Merge_sort
Idea:
Use divide and conquer
divide: size of sequence n to two lists of size n/2
conquer: count recursively two lists
combine: this is a trick part (to do it in linear time)
combine use merge-and-count. Suppose the two lists are A, B. They are already sorted. Produce an output list L from A, B while also counting the number of inversions, (a,b) where a is-in A, b is-in B and a>b.
The idea is similar to "merge" in merge-sort. Merge two sorted lists into one output list, but we also count the inversion.
Everytime a_i is appended to the output, no new inversions are encountered, since a_i is smaller than everything left in list B. If b_j is appended to the output, then it is smaller than all the remaining items in A, we increase the number of count of inversions by the number of elements remaining in A.
This reminds me of a similar problem you may want to look at: http://www.spoj.pl/problems/YODANESS/
In your problem, you can't afford the time to swap everything in case there are many swaps required. (imagine if the input was in reverse order 9,8,7,6.. then you would have to swap everything with everything basically.
I think in your case, each number must be swapped with all the numbers to the left of it that are smaller than it.
I suggest you use a range tree http://en.wikipedia.org/wiki/Range_tree
The great thing about a range tree is each node can know how many nodes are to its left and to its right. You could ask the tree "how many numbers are there greater than 10" very efficiently and that's how many swaps you would have for a 9 say.
The trick is to build the range tree as you move from i=0 to i=N-1. At each point you can query the tree against the ith number before inserting the ith number into the range tree.
good luck!
I did the same code in c++, and it is getting accepted,it is taking time about 4.2 seconds on spoj(http://www.spoj.com/submit/CODESPTB/).
here is the code snippet:
//http://www.spoj.com/problems/CODESPTB/
//mandeep singh #msdeep14
#include<iostream>
using namespace std;
int insertionsort(int arr[], int s)
{
int current,i,j,count=0;
for(i=1;i<s;i++)
{
current=arr[i];
for(j=i-1;j>=0;j--)
{
if(current<arr[j])
{
arr[j+1]=arr[j];
count++;
}
else
break;
}
arr[j+1]=current;
}
return count;
}
int main()
{
int t,n,i,res;
int arr[100000];
cin>>t;
while(t--)
{
cin>>n;
for(i=0;i<n;i++)
{
cin>>arr[i];
}
res=insertionsort(arr,n);
cout<<res<<endl;
}
return 0;
}
#include < stdio.h >
int main() {
int N, swaps, temp[100], i, j;
scanf("%d", & N);
int arr[N];
swaps = 0;
for (i = 0; i < N; i++) {
scanf("%d", & temp[i]);
j = i;
while (j > 0 && arr[j - 1] > temp[i]) {
arr[j] = arr[j - 1];
++swaps;
--j;
}
arr[j] = temp[i];
}
printf("%d", swaps);
return 0;
}

Invalid array passing?

I made a merge sort function:
void mergeSort(int emotionCount[], int low, int high){
int i=0,k=0;
//I did this to see the value inside the array, and I always got a garbage value
//when i=0, and the first correct value when i=1. I made a for loop here to
//see the values in the array in debugging mode in netbean.
for (i=0;i<=high;i++){
}
if (low == high){
emotionCount[low]=emotionCount[low];
}else{
int mid = (low+high)/2;
mergeSort(emotionCount,low,mid);
mergeSort(emotionCount,mid+1,high);
merge(emotionCount, low,mid, high); }
}
void merge(int emotionCount[], int low,int mid, int high)
{
int temp[high-low+1];
int i=low,k=mid+1, j=high, n=0;
int comparing=emotionCount[k];
while (i<=mid || k<=high){
while (emotionCount[i]<comparing)
{
temp[n]=emotionCount[i];
i++;
n++;
}
comparing=emotionCount[i];
temp[n]=emotionCount[k];
k++;
i++;
n++;
while (emotionCount[k]<comparing){
temp[n]=emotionCount[k];
k++;
n++;
}
comparing=emotionCount[k];
temp[n]=emotionCount[i];
k++;
i++;
n++;
}
while (i<=mid)
{
temp[n]=emotionCount[i];
i++;
n++;
}
while (k<=high)
{
temp[n]=emotionCount[k];
k++;
n++;
}
while (low<=high)
{
emotionCount[low]=temp[i];
low++;
}
}
And in main, i pass an array:
int array[10] = {0,5,8,2,4,6,8,2,20,25};
//number 9 because the highest position is 9. After this, array[10] is supposed to be sorted.
mergeSort(array ,0, 9);
Well, the method was kinda long, but I want to implement it myself. Basically, I pass an array to the mergeSort function, and if it is not at its minimum size (which is 1), it will continue to pass that array. The thing which bugging me is, when I pass an array to it, the first value is always a garbage value (like an address value or something). Only after i=1, it will give the first value of the array. I don't get it. Also, everytime exiting a lower mergeSort function to continue on the higer ones, all the sorted values in the array become 0.
Edit: The k variable is just used to hold the array value, to see the array value when I'm in debugging mode. I removed the k variable in the mergeSort function to clear up the confusion.
Yet to read through your function, but at first glance the problem that stands out is the way you are calling the function.
It should be :
mergeSort(array, 0, 9);
If you use array[10], it means you're trying to pass in the 11th element of the array which is unfortunately out of bounds!
It looks like you're passing a value from inside the array instead of the array itself: shouldn't
mergeSort(array[10] ,0, 9);
be something like
mergeSort(array, 0, 0);
for (i=0;i<=high;i++){
int k=*(emotionCount+i);
}
if (low == high){
emotionCount[low]=emotionCount[low];
int k=emotionCount[low];
}else{
int mid = (low+high)/2;
mergeSort(emotionCount,low,mid);
int i=0;
for (i=low;i<=mid;i++){
int k=emotionCount[i];
}
mergeSort(emotionCount,mid+1,high);
for (i=mid+1;i<=high;i++){
int k=emotionCount[i];
}
merge(emotionCount, low,mid, high);
for (i=low;i<=high;i++){
int k=emotionCount[i];
}
}
You redeclare int k in all those blocks. I assume you want to assign a value to k instead so remove the leading "int". Just as in Java which you claim to be familiar with.
What do you want to do anyway? Even if you would use your globally declared k assigning all array elements in a loop doesn't make sense at all. Basically you would end up with k being equal to emotionCount[high].
Do you know that you can dereference array elements using the [] syntax?
k = emotionCount[i]
Is easier to read.
You use Netbeans which has a nice GDB frontend. I suggest that you set a few breakpoints, step through your code and try to understand what you implemented there.
I solved the problem. Corrected code:
void mergeSort(int emotionCount[], int low, int high){
int i=0,k=0;
if (low == high){
emotionCount[low]=emotionCount[low];
k=emotionCount[low];
}else{
int mid = (low+high)/2;
mergeSort(emotionCount,low,mid);
/*
int i=0;
printf("Lower half:");
for (i=low;i<=mid;i++){
k=emotionCount[i];
printf("%d ",k);
}
printf("\n");*/
mergeSort(emotionCount,mid+1,high);
/*
printf("Upper half:");
for (i=mid+1;i<=high;i++){
k=emotionCount[i];
printf("%d ",k);
}
printf("\n");*/
merge(emotionCount, low,mid, high);
//this is how I view the sorting process, along with other 2 above loops
/* printf("Merged:");
for (i=low;i<=high;i++){
k=emotionCount[i];
printf("%d ",k);
}
printf("\n\n");*/
}
}
void merge(int emotionCount[], int low,int mid, int high)
{
int temp[high-low+1],index;
for (index=0;index<high-low+1;index++)
{
temp[index]=0;
}
int i=low,k=mid+1, j=high, n=0;
int comparing=emotionCount[k],temp1;
while (i<=mid && k<=high){
while (emotionCount[i]<comparing && i<=mid)
{
temp[n]=emotionCount[i];
i++;
n++;
}
if (i<=mid){
comparing=emotionCount[i];
if (k<=high)
temp[n]=emotionCount[k];
else
temp[n]=comparing;
k++;
n++;
}
while (emotionCount[k]<comparing && k<=high){
temp[n]=emotionCount[k];
k++;
n++;
}
if (k<=high){
comparing=emotionCount[k];
if (i<=mid)
temp[n]=emotionCount[i];
else
temp[n]=comparing;
i++;
n++;
}
}
while (i<=mid)
{
temp[n]=emotionCount[i];
i++;
n++;
}
while (k<=high)
{
temp[n]=emotionCount[k];
k++;
n++;
}
i=0;
while (low<=high)
{
emotionCount[low]=temp[i];
low++;
i++;
}
}
The initial high value must be exactly array size - 1.

Resources