I have written code to compute the number of comparisons done in QuickSort.
The algorithm increases the count of comparisons by m-1 whenever a quicksort is performed on an array of length m (Since pivot will be compared with everything other than itself).
The choice of the pivot is always the first element of the array.
When I try to use it on an array of 10000 entries, it is giving me a wrong answer.
A correct answer is supposed to be 162085.
The link to the dataset is given below:
https://drive.google.com/file/d/0B0D_kFnzj_RrYm9NT0lrM3JfN2c/view?usp=sharing
The total comparisons are stored in x.
#include<stdio.h>
long long x=0;
int size=10000;
int A[10000];
int B[10000];
void quicksort(int A[],int begin,int end)
{
if(begin<end){
int i=begin;
int j=end;
int k;
int pivot=begin;
for(k=begin+1;k<=end;k++)
{
if(A[k]>A[pivot])
{
x++;
B[j]=A[k];
j--;
}
else
{
x++;
B[i]=A[k];
i++;
}
}
B[i]=A[pivot];
for(k=begin;k<=end;k++)
{
A[k]=B[k];
}
quicksort(A,begin,i-1);
quicksort(A,i+1,end);
}
else
{
if((end-begin)==1) x++;
}
}
int main()
{
FILE *myFile;
myFile = fopen("QuickSort.txt", "r");
int i;
for (i = 0; i < 10000; i++)
{
fscanf(myFile, "%d", &A[i]);
}
quicksort(A,0,size-1);
for(i=0;i<size;i++)
{
printf("%d\n",A[i]);
}
printf("%lld",x);
}
this part is wrong:
for(k=begin+1;k<=end;k++)
{
if(A[k]>A[pivot])
{
x++;
B[j]=A[k];
j--;
}
else
{
x++;
B[i]=A[k];
i++;
}
}
you don't have to go from begin till end. you only should go from begin till i>j.
see link: https://en.wikipedia.org/wiki/Quicksort
there the interesting lines are:
do
i := i + 1
while A[i] < pivot
do
j := j – 1
while A[j] > pivot
if i >= j then
return j
swap A[i] with A[j]
c / c++
i = begin;
j = end;
while(true)
{
while(i< end && A[i] < A[pivot])
{
i++;
}
while(j> begin && A[j] >= A[pivot])
{
j--;
}
if(i<j)
{
int temp = A[i]; //std::swap(A[i],A[j]);
A[i] = A[j];
A[j] = temp;
else
{
break;
}
}
In this code I don't use B because quicksort is an "inplace" algorithm and because of that we don't need to save the result into a different array
Related
I was trying to implement bubble sort in C. I've done so in this gist.
I implemented the algorithm laid out on Wikipedia's article for bubble sort, sort_bubble, and compared it to a reference implementation I found on github, bubble_sort:
typedef struct Bubble_Sort_Stats {
int num_swaps;
int num_steps;
} bubble_sort_stats_t;
bubble_sort_stats_t bubble_sort(int arr[], int n) {
bubble_sort_stats_t stats;
stats.num_swaps = 0;
stats.num_steps = 0;
int temp;
int i;
int j;
while (i < n) {
j = 0;
while (j < i) {
stats.num_steps++;
if (arr[j] > arr[i]) {
temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
stats.num_swaps++;
}
j++;
}
i++;
}
return stats;
}
bubble_sort_stats_t sort_bubble(int array[], int length_of_array) {
bubble_sort_stats_t stats;
stats.num_swaps = 0;
stats.num_steps = 0;
int n = length_of_array;
int new_n;
while (n >= 1) {
new_n = 0;
for (int i = 0; i < n - 1; i++) {
stats.num_steps++;
if (array[i] > array[i+1]) {
int l = array[i];
stats.num_swaps++;
new_n = i + 1;
array[i] = array[i + 1];
array[i + 1] = l;
}
}
n = new_n;
}
return stats;
}
#define BIG 10000
int main() {
int nums1[BIG], nums2[BIG];
for (int i = 0; i < BIG; i++) {
int newInt = rand() * BIG;;
nums1[i] = newInt;
nums2[i] = newInt;
}
long start, end;
bubble_sort_stats_t stats;
start = clock();
stats = bubble_sort(nums2, BIG);
end = clock();
printf("It took %ld ticks and %d steps to do %d swaps\n\n", end - start, stats.num_steps, stats.num_swaps);
start = clock();
stats = sort_bubble(nums1, BIG);
end = clock();
printf("It took %ld ticks and %d steps to do %d swaps\n\n", end - start, stats.num_steps, stats.num_swaps);
for (int i = 0; i < BIG; i++) {
if (nums1[i] != nums2[i]) {
printf("ERROR at position %d - nums1 value: %d, nums2 value: %d", i, nums1[i], nums2[i]);
}
if (i > 0) {
if (nums1[i - 1] > nums1[i]) {
printf("BAD SORT at position %d - nums1 value: %d", i, nums1[i]);
}
}
}
return 0;
}
Now when I run this program I get these results:
It took 125846 ticks and 49995000 steps to do 25035650 swaps
It took 212430 ticks and 49966144 steps to do 25035650 swaps
That is, the number of swaps is identical, and sort_bubble actually takes fewer steps, but it takes almost twice as long for this size of array!
My suspicion is that the difference has something to do with the control structure itself, the indices, something like that. But I don't really know enough about how the c compiler works to guess further, and I don't know how I would go about even determining this by debugging.
So I would like to know why but also how I could figure this out empirically.
Your bubble_sort isn't actually a bubble sort: it doesn't only compare adjacent pairs.
It is an insertion sort with the inner loop oddly reversed, which still works as intended. It can be rewritten as follows, without changing the number of steps or swaps.
bubble_sort_stats_t bubble_sort(int arr[], int n) {
bubble_sort_stats_t stats;
stats.num_swaps = 0;
stats.num_steps = 0;
for (int i = 1; i < n; i++) {
for (int j = i; j > 0; j--) {
stats.num_steps++;
if (arr[j-1] > arr[j]) {
int temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
stats.num_swaps++;
}
}
}
return stats;
}
To get a proper insertion sort from this, simply move the if condition into the inner loop, as follows.
bubble_sort_stats_t bubble_sort(int arr[], int n) {
bubble_sort_stats_t stats;
stats.num_swaps = 0;
stats.num_steps = 0;
for (int i = 1; i < n; i++) {
for (int j = i; j > 0 && arr[j-1] > arr[j]; j--) {
stats.num_steps++;
int temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
stats.num_swaps++;
}
}
return stats;
}
This way, you can see that the number of steps is actually equal to the number of swaps, and less than the number of steps of the actual bubble sort (sort_bubble).
I'm practicing the cracking the code interview on my spare time.
The question states: Is Unique: Implement an algorithm to determine if a string has all unique character. What if you cannot use additional data structures?
The solution I found is: https://github.com/careercup/CtCI-6th-Edition-cpp/blob/master/Ch%201.Arrays%20And%20Strings/1.Is%20Unique/1.%20Is_unique.cpp
My implementation is:
bool UniqueCharsHash(string word) {
map<char, bool> uniqueChar; //keyType, valueType
for (int i = 0; i < word.length(); i++) {
char letter = tolower(word[i]);
if (!uniqueChar[letter]) {
uniqueChar[letter] = true;
} else {
return false;
}
}
return true;
}
//O(n^2) run time using a two loops (1 outer and 1 inner)
bool UniqueCharNoDS(string word) {
for (int i = 0; i < word.length() - 1; i++) {
for (int j = i + 1; j < word.length(); j++) {
if (word[i] == word[j]) {
return false;
}
}
}
return true;
}
but in the hint portion of the book it states:
try a hash table
could a bit vector be useful
can you solve it in O(Nlogn) time
I was wondering in the 3 methods shown, are any of those NlogN time?
As has often been pointed out, this question is solvable in O(1) because the longest string made up of unique characters is 256 characters long.
So when/if your algorithm hits the 257th character, it can stop and report "no".
Even if you use the naive algorithm of searching each character in the prefix up to that point, there are a maximum of 255*128 comparisons before the limit is reached. (No adjustment to the algorithm is necessary; it must report "no" on the 257th character if there is one.)
The below code (in Java) will determine if a string has all unique character.
Time complexity --> O(n)
final static int LETTERS_LEN = 256;
public static boolean isUnique(String str){
int[] letters = new int[LETTERS_LEN];
for (int i = 0; i < str.length(); i++) {
letters[str.charAt(i)]++;
}
for (int i = 0; i < LETTERS_LEN; i++) {
if (letters[i] > 1) {
return false;
}
}
return true;
}
This code solves it in O(NlogN) time, it is a modification of merge sort
boolean isUnique(char[] arr){
return sort(arr,0,arr.length-1);
}
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
boolean merge(char arr[], int l, int m, int r)
{
// Find sizes of two subarrays to be merged
int n1 = m - l + 1;
int n2 = r - m;
/* Create temp arrays */
char L[] = new char [n1];
char R[] = new char [n2];
/*Copy data to temp arrays*/
for (int i=0; i<n1; ++i)
L[i] = arr[l + i];
for (int j=0; j<n2; ++j)
R[j] = arr[m + 1+ j];
/* Merge the temp arrays */
// Initial indexes of first and second subarrays
int i = 0, j = 0;
// Initial index of merged subarry array
int k = l;
while (i < n1 && j < n2)
{
if (L[i] < R[j])
{
arr[k] = L[i];
i++;
}
else if(L[i] > R[j])
{
arr[k] = R[j];
j++;
}
else{
return false;
}
k++;
}
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
/* Copy remaining elements of L[] if any */
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
return true;
}
// Main function that sorts arr[l..r] using
// merge()
boolean sort(char arr[], int l, int r)
{
if (l < r)
{
// Find the middle point
int m = (l+r)/2;
// Sort first and second halves
boolean left= sort(arr, l, m);
boolean right = sort(arr , m+1, r);
// Merge the sorted halves
return left&&right&&merge(arr, l, m, r);
}
return true;
}
An O(n) time could be used with the hint (#2) provided. Where you shift bits and flip if a letter has already been seen.
static boolean isUniqueNoStruct(String input) {
// Length check
if (input.length() > 256)
return false;
// Assuming only lowercase 32 bit characters
int checkVal = 0;
for (int i = 0; i < input.length(); i++) {
int bit = input.charAt(i) - 'a';
// If the bit at the index has been flipped return false
if ((checkVal & ( 1 << bit)) > 0) {
return false;
}
checkVal |= (1 << bit);
}
return true;
}
void main ()
{
int x[19]={0}, i=0, y=0, u=0, p;
while (i<=19)
{
scanf("%d",&x[i]);
i=i+1;
}
for (i=u;i<=19;i++)
{
if (x[y]!=x[i+1])
p=x[y];
else
{
u++;
y++;
}
}
printf("%d",p);
}
So I used this to check for duplicates & it should print non duplicates, but as you can see this works if all are duplicates but one, as in
x[0]=1 x[1]=1 x[3]=9 x[4]=1 ... x[19]=1;
prints
9
So how to print non duplicates ? Any help ?
This would be the easiest solution, simply nest an additional for-loop. However, this takes O(n^2). Depending on the size of the array, it could be beneficial to look at a fast sort.
void main() {
int x[4] = { 1, 3, 2, 1 };
size_t i, j;
for (i = 0; i < sizeof(x) / sizeof(int); i ++) {
// Note that we only have to go to the last value before i.
for (j = 0; j < i; j ++) {
// We break if the value is a duplicate.
if (x[i] == x[j])
break;
}
// Check if the inner loop was break'ed (j < i) or not (j == i).
if (j == i)
printf("Unique: %i\n", x[i]);
}
}
One more thing: only use sizeof(x) / sizeof(int) if the size of x is known during compilation. This is the case here, but don't use it with malloc.
One of the simplest ways is to sort the array to group the duplicates together. Then, as you go through the array you only print a number if its different from the number that came before.
// Print the unique elements of a sorted array:
for(int i=0; i<N; i++){
if (i-1 >= 0 && arr[i] == arr[i-1]) { continue; }
if (i+1 < N && arr[i] == arr[i+1]) { continue; }
printf("%d\n", arr[i]);
}
To sort the array you can use the qsort function
void main ()
{
int num[20]={0}, i=0, n=0, index_num=0, init_incr=0, unique=0, n_uniq=1, temp, check=0;
while (i<=19)
{
printf("%02d- ",i+1);
scanf("%d",&num[i]);
i=i+1;
}
for (index_num=0;index_num<19;index_num++)
{
for (n=init_incr+index_num;n<19;n++)
{
if (num[index_num]!=num[index_num+1] && num[index_num]!=num[index_num-1])
{
check++;
temp=num[index_num];
unique=temp;
for (;n_uniq<=check;n_uniq++)
printf("\tunique %02d = %d\n", n_uniq, unique);
break;
}
}
}
}
I want to implement heap sort. For the purpose, I went through this http://faculty.simpson.edu/lydia.sinapova/www/cmsc250/LN250_Tremblay/L06-QuickSort.htm#basic tutorial and wrote the following code:
#include <stdio.h>
int quick_sort(int a[],int first,int last);
int main()
{
int a[]= {12,3,4,23,1,7,9,34,89,45};
int i;
printf("Enter 10 integers: \n");
for ( i = 0 ; i < 10 ; i++ )
{
scanf("%d",&a[i]);
printf("\t%d\n",a[i]);
}
for ( i = 0 ; i < 10 ; i++ )
{
printf("\n%d ",a[i]);
}
quick_sort(a,0,9);
for ( i = 0 ; i < 10 ; i++ )
{
printf("%d ",a[i]);
}
return 0;
}
int quick_sort(int a[],int first,int last)
{
int i,j,pivot,temp ;
if ( first - last <= 1 && first - last >= -1 )
{
return 0;
}
else
{
i = first ;
j = last ;
pivot = a[(i+j) / 2 ] ;
while ( i != j )
{
while ( a[i] < pivot )
{
i++;
}
while( a[j] > pivot )
{
j--;
}
temp = a[i] ;
a[i] = a[j] ;
a[j] = temp ;
}
}
quick_sort(a,0,i-1);
quick_sort(a,j+1,9);
return 0;
}
While running it using gcc compiler I am getting segmentation fault. Please help me to solve it.
There are several thing that in the question's quick_sort() function that are a mystery to me. Not that they are wrong; it's just that the purpose of various manipulations escapes me.
After working on it for a while, here is my version:
void quick_sort(int *a, int first, int last)
{
int i,j,pivot,temp;
if(last <= 1)
return;
pivot = a[first + last/2];
j = first + last/2;
temp = a[first];
a[first] = a[j];
a[j] = temp;
j = first;
for(i = first+1; i < first+last; i++)
{
if(a[i] < pivot)
{
j++;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
temp = a[first];
a[first] = a[j];
a[j] = temp;
quick_sort(a, first, j-first);
quick_sort(a, j+1, first+last-j-1);
return;
}
Working spoiler testcase here.
I'd try:
quick_sort(a,first,i-1);
quick_sort(a,j+1,last);
Instead of:
quick_sort(a,0,i-1);
quick_sort(a,j+1,9);
It at least allows the sort to work for lists different than 10 values....
You also need to check if i != j after every change, so I think that's problematic in your code as well. Or at least use i than j and the while would NEVER end.
I am try to write a A recursive implementation, but it dont work. Can you help me to find mistake. I need just a recursive solution on C.
void findsum(int arr[],int i, int k){
if (k <= 0 || arr[i] > k) return;
if (arr[i] <= k) {
k -= arr[i];
if (k == 0) {
NSLog(#"Summ %d, %d",arr[i], arr[i]); return;
}
}
if (i == (25)) return;
for (int a=i ;a<25; a ++ ) {
findsum(arr, a, k);
}
}
int main()
{
int set[] = {18897109, 12828837, 9461105, 6371773, 5965343, 5946800, 5582170, 5564635, 5268860, 4552402, 4335391, 4296250, 4224851, 4192887, 3439809, 3279833, 3095313, 2812896, 2783243, 2710489, 2543482, 2356285, 2226009, 2149127, 2142508, 2134411};
int sum = 100000000;
int n = sizeof(set)/sizeof(set[0]);
for (int i = 0; i < n; i++) {
findsum(set, i, sum);
}
}
You code not stop because every time you assign i=0 by loop
for (i = 0 ;i<26; i ++ ) {
findsum(arr, i, k);
}
In findsum function.
So as per my suggestion you can make some changes as like
first in main
int main()
{
int set[] = {18897109, 12828837, 9461105, 6371773, 5965343, 5946800, 5582170, 5564635, 5268860, 4552402, 4335391, 4296250, 4224851, 4192887, 3439809, 3279833, 3095313, 2812896, 2783243, 2710489, 2543482, 2356285, 2226009, 2149127, 2142508, 2134411};
int sum = 100000000,i;
int n = sizeof(set)/sizeof(set[0]);
findsum(set, n, sum);
}
And second in findsum like
void findsum(int arr[],int i, int k)
{
if (k <= 0 || arr[i] > k) return;
if (arr[i] <= k)
{
k -= arr[i];
if (k == 0) {
NSLog(#"Summ %d, %d",arr[i], arr[i]); return;
}
}
if (i == 25) return;
findsum(arr, i, k);
}