Segment Tree to compute frequencies - arrays

Is there any way to use a Segment Tree structure to compute the frequency of a given value in an array?
Suppose there is an array A of size N, and every element A[i] of the array contains the value 0, 1 or 2. I want to perform the following operations:
Compute the amount of zeroes in any range [a,b] of the array
Increment (mod 3) every element in in any range [a,b] of the array
Example: If A = [0,1,0,2,0]:
Query[2,4] must return 1 , since there is one 0 in the range [2,4]
Increment[2,4] updates A to [0,2,1,0,0]
This looks really similar to the Range Sum Query problem, which can be solved using Segment Trees (in this case using Lazy Propagation because of range updates), but i had no success adapting my seg tree code to this problem, because if i store the values in the tree like in a normal RSQ, any parent node which contains the value "3" (for example) wouldn't mean nothing, since with this information i can't extract how much zeroes are present in this range.
Thanks in advance!
--
EDIT:
Segment Trees are binary tree structures that store intervals related to an array in its nodes. The leaf nodes store the actual array cells, and each parent node stores a function f(node->left, node->right) of its children. Segment Trees are commonly used to perform Range Sum Queries, in which we want to compute the sum of all elements in a range [a,b] of the array. In this case, the function computed by the parent nodes is the sum of the value in its children nodes. We want to use segtrees to solve the Range Sum Query problem because it allows to solve it in O(log n) (we only need to descend the tree until we find the nodes that are completely covered by our range query), much better than the naive O(n) algorithm.

Since actual array values are stored in the leaves (level L), let the nodes at level L - 1 store how many zeros they contain (which will be a value in the range [0, 2]). Other than that, everything is the same, the rest of the nodes will compute f(node->left, node->right) as node->left + node->right and the count of zeros will be propagated to the root.
After incrementing a range, if that range contained no zeros than nothing needs to be done. If however that range had zeros, then all those zeros will now be ones and the function value of current node (call it F) now becomes just zero. That change in the value now needs to be propagated upwards to the root, each time subtracting F from the function values.

This question can be easily solved using Square root decomposition
First create the new prefix sum array modulo each prefix sum by 3.
Divide the whole array into sqrt(n) blocks . Each block will have counts of number of 0's,1's and 2's. Also create one temporary array which will contain the sum to be added to the elements of the block
Here is the implementation in c++:
#include <bits/stdc++.h>
using namespace std;
#define si(a) scanf("%d",&a)
#define sll(a) scanf("%lld",&a)
#define sl(a) scanf("%ld",&a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%ld\n",a)
#define pll(a) printf("%lld\n",a)
#define sc(a) scanf("%c",&a)
#define pc(a) printf("%c",a)
#define ll long long
#define mod 1000000007
#define w while
#define pb push_back
#define mp make_pair
#define f first
#define s second
#define INF INT_MAX
#define fr(i,a,b) for(int i=a;i<=b;i++)
///////////////////////////////////////////////////////////////
struct block
{
int one;
int two;
int zero;
block()
{
one=two=zero=0;
}
};
ll a[100005],a1[100005];
ll sum[400];
int main()
{
int n,m;
cin>>n>>m;
string s;
cin>>s;
int N=(int)(sqrt(n));
struct block b[N+10];
for(int i=0;i<n;i++)
{
a[i]=s[i]-'0';
a[i]%=3;
a1[i]=a[i];
}
for(int i=1;i<n;i++)
a[i]=(a[i]+a[i-1])%3;
for(int i=0;i<n;i++)
{
if(a[i]==0)
b[i/N].zero++;
else if(a[i]==1)
b[i/N].one++;
else
b[i/N].two++;
}
w(m--)
{
int type;
si(type);
if(type==1)
{
int ind,x;
si(ind);
si(x);
x%=3;
ind--;
int diff=(x-a1[ind]+3)%3;
if(diff==1)
{
int st=ind/N;
int end=(n-1)/N;
int kl=(st+1)*N;
int hj=min(n,kl);
for(int i=st*N;i<hj;i++)
{
a[i]=(a[i]+sum[st])%3;
}
sum[st]=0;
for(int i=ind;i<hj;i++)
{
if(a[i]==0)
b[st].zero--;
else if(a[i]==1)
b[st].one--;
else
b[st].two--;
a[i]=(a[i]+diff)%3;
if(a[i]==0)
b[st].zero++;
else if(a[i]==1)
b[st].one++;
else
b[st].two++;
}
for(int i=st+1;i<=end;i++)
{
int yu=b[i].zero;
b[i].zero=b[i].two;
b[i].two=b[i].one;
b[i].one=yu;
sum[i]=(sum[i]+diff)%3;
}
}
else if(diff==2)
{
int st=ind/N;
int end=(n-1)/N;
int kl=(st+1)*N;
int hj=min(n,kl);
for(int i=st*N;i<hj;i++)
{
a[i]=(a[i]+sum[st])%3;
}
sum[st]=0;
for(int i=ind;i<hj;i++)
{
if(a[i]==0)
b[st].zero--;
else if(a[i]==1)
b[st].one--;
else
b[st].two--;
a[i]=(a[i]+diff)%3;
if(a[i]==0)
b[st].zero++;
else if(a[i]==1)
b[st].one++;
else
b[st].two++;
}
for(int i=st+1;i<=end;i++)
{
int yu=b[i].zero;
b[i].zero=b[i].one;
b[i].one=b[i].two;
b[i].two=yu;
sum[i]=(sum[i]+diff)%3;
}
}
a1[ind]=x%3;
}
else
{
int l,r;
ll x=0,y=0,z=0;
si(l);
si(r);
l--;
r--;
int st=l/N;
int end=r/N;
if(st==end)
{
for(int i=l;i<=r;i++)
{
ll op=(a[i]+sum[i/N])%3;
if(op==0)
x++;
else if(op==1)
y++;
else
z++;
}
}
else
{
for(int i=l;i<(st+1)*N;i++)
{
ll op=(a[i]+sum[i/N])%3;
if(op==0)
x++;
else if(op==1)
y++;
else
z++;
}
for(int i=end*N;i<=r;i++)
{
ll op=(a[i]+sum[i/N])%3;
if(op==0)
x++;
else if(op==1)
y++;
else
z++;
}
for(int i=st+1;i<=end-1;i++)
{
x+=b[i].zero;
y+=b[i].one;
z+=b[i].two;
}
}
ll temp=0;
if(l!=0)
{
temp=(a[l-1]+sum[(l-1)/N])%3;
}
ll ans=(x*(x-1))/2;
ans+=((y*(y-1))/2);
ans+=((z*(z-1))/2);
if(temp==0)
ans+=x;
else if(temp==1)
ans+=y;
else
ans+=z;
pll(ans);
}
}
return 0;
}

Related

Check repeated numbers on a matrix in C

How can I use repetitions to check if there aren't any repeated numbers on a n x n matrix?
Using two for's two times wouldn't let me check anything that does not share at least a line or a column
Example: (in the most simplified way possible):
int matrix[n][n];
/*matrix is filled*/
int current, isEqual;
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
current = matrix[i][j];
if (current == matrix[i][j+1])
{
isEqual=1;
}
else
{
isEqual=0;
}
}
}
for (int j=0; j<n; j++)
{
for (int i=0; i<n; i++)
{
current = matrix[i][j];
if (current == matrix[i+1][j])
{
isEqual=1;
}
else
{
isEqual=0;
}
}
}
I can't check numbers that don't share lines or columns.
First, think in a NxM matrix as if it were an array with length [N*M]. The only difference is how you access the elements (two fors instead of one, for example).
Then, a simple algorithm would be to iterate every element (first index), and for each one, iterate every other element (second index) to check if it's the same. It's easier to do with an array; in a matrix it's the same, maybe a bit more verbose and complex. But the algorithm is the same.
As a second phase, after you have implemented the basic algorithm, you can improve its performance starting the second index in the element after the first index. This way, you avoid checking the already seen elements multiple times. This algorithm improvement is slightly harder to do in a matrix, if you iterate it with 2 fors, as it's a bit harder to know what's the "next index" (you have a "compound" index, {i,j}).
One simple way to do this is to insert each number into a data structure that makes it easy to check for duplicates. This is sort of fun to do in C, and although the following is certainly not super efficient or production ready, it's (IMO) a nice little toy:
/* Check if any integer on the input stream is a dup */
#include <stdio.h>
#include <stdlib.h>
struct node { int data; struct node *child[2]; };
static struct node *
new_node(int data)
{
struct node *e = calloc(1, sizeof *e);
if( e == NULL ){
perror("calloc");
exit(EXIT_FAILURE);
}
e->data = data;
return e;
}
/*
* Insert a value into the tree. Return 1 if already present.
* Note that this tree needs to be rebalanced. In a real
* project, we would use existing libraries. For this toy
* it is not worth the work needed to properly rebalance the
* tree.
*/
int
insert(struct node **table, int data)
{
struct node *t = *table;
if( !t ){
*table = new_node(data);
return 0;
}
if( data == t->data ){
return 1;
}
return insert(&t->child[data < t->data], data);
}
int
main(void)
{
int rv, v;
struct node *table = NULL;
while( (rv = scanf("%d", &v)) == 1 ){
if( insert(&table, v) ){
fprintf(stderr, "%d is duplicated\n", v);
return EXIT_FAILURE;
}
}
if( rv != EOF ){
fprintf(stderr, "Invalid input\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
The basic approach is to loop through the nxn matrix and keeping a list of the numbers in it along with a count of the number of times each number is found in the nxn matrix.
The following is example source code for a 50 x 50 matrix. To extend this to an n x n matrix is fairly straightforward and I leave that as an exercise for you. You may need to do something such as using malloc() to create an arbitrary sized matrix. There are posts on that sort of thing.
I also do not specify how the data is put into the matrix in the first place. That is also up to you.
This is to just show a brute force approach for determining if there are duplicates in the matrix.
I've also taken the liberty of assuming the matrix elements are int but changing the type to something else should be straightforward. If the matrix elements are something other than a simple data value type such as int, long, etc. then the function findAndCount() will need changing for the equality comparison.
Here are the data structures I'm using.
typedef struct {
int nLength; // number of list elements in use
struct {
int iNumber; // number from an element of the nxn matrix
int iCount; // number of times this element was found in the matrix
} list[50 * 50];
} elementList;
elementList matrixList = {
0,
{0, 0}
};
int matrixThing[50][50];
next we need to loop through the matrix and with each element in the matrix to check if it is in the list. If it's not then add it. It does exist then increment the count.
for (unsigned short i = 0; i < 50; i++) {
for (unsigned short j = 0; j < 50; j++) {
findAndCount (matrixThing[i][j], &matrixList);
}
}
And then we need to define our function we use to check matrix values against the list.
void findAndCount (int matrixElement, elementList *matrixList)
{
for (int i = 0; i < matrixList->nLength; i++) {
if (matrixElement == matrixList->list[i].iNumber) {
matrixList->list[i].iCount++;
return;
}
}
// value not found in the list so we add it and set the initial count
// to one.
// we can then determine if there are any duplicates by checking the
// resulting list once we have processed all matrix elements to see
// if any count is greater than one.
// the initial check will be to see if the value of nLength is equal
// to the number of array elements in the matrix, n time n.
// so a 50 x 50 matrix should result in an nLength of 2500 if each
// element is unique.
matrixList->list[matrixList->nLength].iNumber = matrixElement;
matrixList->list[matrixList->nLength].iCount = 1;
matrixList->nLength++;
return;
}
Search algorithms
The above function, findAndCheck(), is a brute force search algorithm that searches through an unsorted list element by element until either the thing being searched for is found or the end of the list is reached.
If the list is sorted then you can use a binary search algorithm which is much quicker than a linear search. However you then run into the overhead needed to keep the list sorted using a sorting algorithm in order to use a binary search.
If you change the data structure used to store the list of found values to a data structure that maintains values in an ordered sequence, you can also cut down on the overhead of searching though there will also be an overhead of inserting new values into the data structure.
One such data structure is a tree and there are several types and algorithms to build a tree by inserting new items as well as searching a tree. See search tree which describes several different kinds of trees and searches.
So there is a kind of balancing between the effort to do searching versus the effort to add items to the data structure.
Here is an example that checks for duplicate values, the way want to do it.
Looping is slow, and we should use a hash set or a tree instead of using loops.
I assume you are not using C++, because the C++ standard library has build-in algorithms and data structures to do it efficiently.
#include <stdio.h>
/* Search the 'array' with the specified 'size' for the value 'key'
starting from 'offset' and return 1 if the value is found, otherwise 0 */
int find(int key, int* array, int size, int offset) {
for (int x = offset; x < size; ++x)
if (key == array[x])
return 1;
return 0;
}
/* Print duplicate values in a matrix */
int main(int argc, char *argv[]) {
int matrix[3][3] = { 1, 2, 3, 4, 3, 6, 2, 8, 2 };
int size = sizeof(matrix) / sizeof(matrix[0][0]);
int *ptr = (int*)matrix;
for (int x = 0; x < size; ++x) {
/* If we already checked the number, then don't check it again */
if (find(ptr[x], ptr, x, 0))
continue;
/* Check if the number repeats and show it in the console if it does */
if (find(ptr[x], ptr, size, x + 1))
printf("%d\n", ptr[x]);
}
return 0;
}
When you become better at C, you should find or implement a "hash set" or a "red-black tree", and use that instead.

exceeding 500000 with the method of Erastosthenes

i got a problem which i can't solve
I want to know all prime numbers below a given limit x. Allowing me to enter x and calculate the prime numbers using the method of Erastosthenes. Displaying the result on the screen and saving it to a text file.
Calculating the primenumbers below the x, printing them and saving them to a text file worked, the only problem i have is that x can't exceed 500000
could you guys help me?
#include <stdio.h>
#include <math.h>
void sieve(long x, int primes[]);
main()
{
long i;
long x=500000;
int v[x];
printf("give a x\n");
scanf("%d",&x);
FILE *fp;
fp = fopen("primes.txt", "w");
sieve(x, v);
for (i=0;i<x;i++)
{
if (v[i] == 1)
{
printf("\n%d",i);
fprintf(fp, "%d\n",i);
}
}
fclose(fp);
}
void sieve(long x, int primes[])
{
int i;
int j;
for (i=0;i<x;i++)
{
primes[i]=1; // we initialize the sieve list to all 1's (True)
primes[0]=0,primes[1]=0; // Set the first two numbers (0 and 1) to 0 (False)
}
for (i=2;i<sqrt(x);i++) // loop through all the numbers up to the sqrt(n)
{
for (j=i*i;j<x;j+=i) // mark off each factor of i by setting it to 0 (False)
{
primes[j] = 0;
}
}
}
You will be able to handle four times as many values by declaring char v [500000] instead of int v [100000].
You can handle eight times more values by declaring unsigned char v [500000] and using only a single bit for each prime number. This makes the code a bit more complicated.
You can handle twice as many values by having a sieve for odd numbers only. Since 2 is the only even prime number, there is no point keeping them in the sieve.
Since memory for local variables in a function is often quite limited, you can handle many more values by using a static array.
Allocating v as an array of int is wasteful, and making it a local array is risky, stack space being limited. If the array becomes large enough to exceed available stack space, the program will invoke undefined behaviour and likely crash.
While there are ways to improve the efficiency of the sieve by changing the sieve array to an array of bits containing only odd numbers or fewer numbers (6n-1 and 6n+1 is a good trick), you can still improve the efficiency of your simplistic approach by a factor of 10 with easy changes:
fix primes[0] and primes[1] outside the loop,
clear even offsets of prime except the first and only scan odd numbers,
use integer arithmetic for the outer loop limit,
ignore numbers that are already known to be composite,
only check off odd multiples of i.
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sieve(long x, unsigned char primes[]) {
long i, j;
for (i = 0; i < x; i++) {
primes[i] = i & 1;
}
primes[1] = 0;
primes[2] = 1;
/* loop through all odd numbers up to the sqrt(x) */
for (i = 3; (j = i * i) < x; i += 2) {
/* skip composite numbers */
if (primes[i] == 0)
continue;
/* mark each odd multiple of i as composite */
for (; j < x; j += i + i) {
primes[j] = 0;
}
}
}
int main(int argc, char *argv[]) {
long i, x, count;
int do_count = 0;
unsigned char *v;
if (argc > 1) {
x = strtol(argv[1], NULL, 0);
} else {
printf("enter x: ");
if (scanf("%ld", &x) != 1)
return 1;
}
if (x < 0) {
x = -x;
do_count = 1;
}
v = malloc(x);
if (v == NULL) {
printf("Not enough memory\n");
return 1;
}
sieve(x, v);
if (do_count) {
for (count = i = 0; i < x; i++) {
count += v[i];
}
printf("%ld\n", count);
} else {
for (i = 0; i < x; i++) {
if (v[i] == 1) {
printf("%ld\n", i);
}
}
}
free(v);
return 0;
}
I believe the problem you are having is allocating an array of int if more than 500000 elements on the stack. This is not an efficient way, to use an array where the element is the number and the value indicates whether it is prime or not. If you want to do this, at least use bool, not int as this should only be 1 byte, not 4.
Also notice this
for (i=0;i<x;i++)
{
primes[i]=1; // we initialize the sieve list to all 1's (True)
primes[0]=0,primes[1]=0; // Set the first two numbers (0 and 1) to 0 (False)
}
You are reassigning the first two elements in each loop. Take it out of the loop.
You are initializing x to be 500000, then creating an array with x elements, thus it will have 500000 elements. You are then reading in x. The array will not change size when the value of x changes - it is fixed at 500000 elements, the value of x when you created the array. You want something like this:
long x=500000;
printf("give a x\n");
scanf("%d",&x);
int *v = new int[x];
This fixes your fixed size array issue, and also gets it off the stack and into the heap which will allow you to allocate more space. It should work up to the limit of the memory you have available.

C: How to count the number of times a particular number occurs using an array

I have written a code which is meant to track the position of a randomly moving 'particle'. The idea is that it is meant to move one position at a time. The direction in which it moves is random. The problem I have is that I can track the number of times the 'particle' has been in a certain position except for a set of random numbers. I know that these random numbers are false because the numbers that are outputted are either too large or negative. I am new to programming and have a limited knowledge. Below is my code thus far. Any help would be greatly appreciated.
#include<stdio.h>
int randomInt(int max)
{
return (random(2)%max);
}
main()
{
int i;
int position=1,r=1; /*Position indicates the position of the particle
and r represents where the particle will move
next*/
int L=10,M=20;/*L is the number of sites and M is the number of hops*/
int seed,n,sum=0;
int frequency[position];
//setup the random seed generator
printf("\nEnter your value of seed\n");
scanf("%d",&seed);
srandom(seed);
printf("\nThe value of the seed is %d\n",seed);
for(i=0;i<M;i++) //This loops around the total number of loops.
{
printf("\nThe particle is at position %d\n",position);
n=randomInt(2);/*This chooses either the numbers 0 or 1 randomly */
frequency[position]=frequency[position]+1;
printf("This position has been visited %d times\n",frequency[position]);
/*Below represents the conditions which will determine the movement
of the particle*/
if(n==0)
{
r=1;
}
if(n==1)
{
r=-1;
}
position = position + r;
if(position==0)
{
position=L;
}
if(position==L+1)
{
position=1;
}
}
}
Not very clear, but here some fix to you prog:
#include<stdio.h>
#include <string.h>
int randomInt(int max)
{
return (random() % max);
}
main()
{
int i;
int position=1,r=1; /*Position indicates the position of the particle
and r represents where the particle will move
next*/
int L=10,M=20;/*L is the number of sites and M is the number of hops*/
int seed,n,sum=0;
int frequency[L];
memset(frequency, 0, sizeof(frequency));
//setup the random seed generator
printf("\nEnter your value of seed\n");
scanf("%d",&seed);
srandom(seed);
printf("\nThe value of the seed is %d\n",seed);
for(i=0;i<M;i++) //This loops around the total number of loops.
{
printf("\nThe particle is at position %d\n",position);
n = randomInt(2);/*This chooses either the numbers 0 or 1 randomly */
frequency[position]=frequency[position]+1;
printf("This position has been visited %d times\n",frequency[position]);
/*Below represents the conditions which will determine the movement
of the particle*/
if(n == 0)
{
r = 1;
}
if(n == 1)
{
r = -1;
}
position = position + r;
if(position < 0)
{
position = L - 1;
}
if(position >= L)
{
position = 0;
}
}
}
Two issues with your code :
The array frequency should be of length L
The array frequency should be initialized
One advice : change the tests, just in case you come back and wish to increment or decrement by more than 1.
Here is a code that is compiled by gcc main.c -o main
#include<stdio.h>
#include<stdlib.h>
int randomInt(int max)
{
return (rand()%max);
}
int main(int argc,char *argv[]){
int i;
int position=1,r=1; /*Position indicates the position of the particle
and r represents where the particle will move
next*/
int L=10,M=20;/*L is the number of sites and M is the number of hops*/
int seed,n,sum=0;
int frequency[L];
//initialization of frequency [can use memset()]
for(i=0;i<L;i++){
frequency[i]=0;
}
//setup the random seed generator
printf("\nEnter your value of seed\n");
scanf("%d",&seed);
srand(seed);
printf("\nThe value of the seed is %d\n",seed);
for(i=0;i<M;i++) //This loops around the total number of loops.
{
printf("\nThe particle is at position %d\n",position);
n=randomInt(2);/*This chooses either the numbers 0 or 1 randomly */
frequency[position]=frequency[position]+1;
printf("This position has been visited %d times\n",frequency[position]);
/*Below represents the conditions which will determine the movement
of the particle*/
if(n==0)
{
r=1;
}
if(n==1)
{
r=-1;
}
position = position + r;
if(position<0)
{
position=position+L;
}
if(position>L-1)
{
position=position-L;
}
}
return 0;
}
Beware of this use of rand(). According to the documentation of rand() about v1 = rand() % 100; :
Notice though that this modulo operation does not generate uniformly distributed random numbers in the span (since in most cases this operation makes lower numbers slightly more likely).
In particular, in your case, if RAND_MAX is even, the position will feature a light tendency to loop upwards...

How to find mode from an array

I have been trying to get this prototype for finding mode of an array to work but it is not returning the right thing, could someone please tell me what I am doing wrong.
int mode(int array[], int size)
{
int x;
int mode = 0;
int largest = 0;
for (x = 0; x < size; x++)
{
if (array[x] > largest)
{
largest = array[x];
mode = x;
}
}
return mode;
}
First of all if that's c++ Arrays are numbered from 0, so x should be 0 in the for. also x should be checked against < size. Other then that the code is good.
In the question you've mentioned that " prototype for finding mode of an array " ,but this program is intended to find the position of the largest number in an array, because
mode = x; // x is the value of i which in-turn is the position of element in the array
and the value of mode is returned. So the position of the largest element counting from the zero'th element's position is shown.
If you want a program to find the mode (element/number that occurs most often) in an array, here it is
#include <stdio.h>
int mode(int array[], int size);
int main()
{
int Num[100],size,ret_Val,i;
clrscr();
printf("Enter the size of the array\n");
scanf("%d",&size);
printf("%d ",size);
for(i=0;i<size;i++)
{
scanf("%d",&Num[i]);
}
ret_Val=mode(Num,size);
printf("Mode of the array is %d",ret_Val);
getch();
return 0;
}
int mode(int array[], int size)
{
int cntMde = 1;
int i;
int cnt = 1;
int num = array[0];
int mode = num;
for ( i=1; i<size; i++)
{
if (array[i] == num)
{
cnt++;
}
else
{
if (cnt > cntMde)
{
cntMde = cnt;
mode = num;
}
cnt = 1;
num = array[i];
}
}
return mode;
}
And the output is
Mode of the array is 44
I have analyzed four ways to calculate mode of the array:
If range of numbers in the array is small then use counting sort - O(N) time, (N) space but very efficient
Index elements in the array in hash table - O(N) time, O(N) space
Sort the array and then count successive equal elements - O(NlogN) time, O(1) space
Partially sort the array but skip partitions smaller than current candidate - O(NlogN) time, O(1) space but much more efficient than fully sorting the array because many partitions will be skipped
You can find source code for all four methods and performance comparison in this article: Finding Mode of an Array

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.

Resources