Is it normal for quicksort to be inefficient when sorting a completely descending array? [duplicate] - algorithm

This question already has answers here:
Quick sort Worst case
(6 answers)
What is the worst case scenario for quicksort?
(6 answers)
Closed 4 years ago.
#include <iostream>
#include<stdio.h>
#include<fstream>
using namespace std;
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
int partition (int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j <= high- 1; j++)
{
if (arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
void quickSort(int arr[], int low, int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
int main()
{
int arr[100000];
int i;
ifstream fin;
int n = 20000;
fin.open("reverse20k.txt");
if(fin.is_open())
{
for(i=0;i<n;i++)
fin>>arr[i];
}
quickSort(arr, 0, n-1);
return 0;
}
It takes this about 1.25 seconds to sort a 20k purely descending array, while it takes merge sort only 0.05. Is quick sort just extremely inefficient when sorting descending arrays, or is there just something wrong with the algorithm?

Related

write a program that calculates the number of comparisons in binary insertion sorting?

I would like to know how I can write a program to calculate the number of comparison in binary insertion sorting
I tried to code the binary insertion program below, but I would like to know how I can calculate the overall comparisons made.
#include<iostream>
using namespace std;
int binarysearch (int a[], int sel, int high, int low){
int mid=(high+low)/2;
if(high<=low){
if(sel>a[high]){
return high+1;
}
else{
return high;
}
}
else{
if(sel==a[mid]){
return mid+1;
}
else if(sel>a[mid]){
return binarysearch( a, sel, high, mid+1);
}
else{
return binarysearch( a, sel, mid-1, low);
}
}}
void insertionsort(int a[], int n){
for(int i=1; i<n; i++){
int j=i-1;
int sel=a[i];
int loc=binarysearch(a,sel,j,0);
while(j>=loc){
a[j+1]=a[j];
j--;
}
a[j+1]=sel;
}
}
int main(){
int a[]= {1,6,2,5,3,4};
int n=sizeof(a)/sizeof(a[0]);
insertionsort(a,n);
cout<<"Sorted array is :";
for (int i = 0; i < n; i++)
cout<<a[i]<<"\t";
return 0;
}

Quick sort -- What am i doing wrong?

Trying to do Quick sort.
logic -> maintaining two variables to place pivot element at correct index. Taking 1st element as pivot. int i for RHS of pivot and Int j for LHS, if they cross each other then j is correct index for pivot.
#include<iostream>
using namespace std;
int partition(int arr[], int low, int high){
int pivot = arr[low];
int i = low+1;
int j = high;
while (i<j)
{
while(arr[i]<=pivot) i++;
while(arr[j]> pivot) j--;
if(i<j) {
swap(arr[i], arr[j]);
}
swap(arr[j], arr[low]);
return j;
}
}
void QuickSort(int arr[], int low , int high){
if(low >= high ) return;
if(high>low){
int pivotindx = partition(arr, low , high);
QuickSort(arr,low, pivotindx-1);
QuickSort( arr, pivotindx+1, high);
}
}
void printquicksort(int arr[] , int n){
cout << " Quick SORT IS HERE BROOOO " << endl;
for (int i = 0; i < n; i++)
{
cout << " " << arr[i] << " " ;
}
}
int main()
{
int arr []={3,4,5,1};
int n= sizeof (arr)/ sizeof (arr[0]);
QuickSort(arr,0,n-1);
printquicksort(arr,n);
return 0;
}
Using i and j for LHS and RHS is type of Hoare partition scheme. The code has a potential issue when using low for the pivot, the while(arr[i]<=pivot) i++; may never encounter an element > pivot and scan past the end of the array. For Hoare partition scheme, the pivot and elements equal to the pivot can end up anywhere, and the partition index separate elements <= pivot and elements >= pivot, so the index needs to be included in one of the recursive calls. Example of a post-increment and post-decrement version of Hoare with the partition code included in QuickSort:
void QuickSort(int *a, int lo, int hi)
{
int i, j;
int p, t;
if(lo >= hi)
return;
p = a[lo + (hi-lo)/2];
i = lo;
j = hi;
while (i <= j){
while (a[i] < p)i++;
while (a[j] > p)j--;
if (i > j)
break;
t = a[i]; // swap
a[i] = a[j];
a[j] = t;
i++;
j--;
}
QuickSort(a, lo, j);
QuickSort(a, i, hi);
}
Example of a classic pre-increment and pre-decrement version of Hoare with the partition code included in QuickSort:
void QuickSort(int a[], int lo, int hi)
{
if(lo >= hi)
return;
int p = a[lo+(hi-lo)/2];
int i = lo-1;
int j = hi+1;
int t;
while(1){
while (a[++i] < p);
while (a[--j] > p);
if(i >= j)
break;
t = a[i]; // swap
a[i] = a[j];
a[j] = t;
}
i = j++;
QuickSort(a, lo, i);
QuickSort(a, j, hi);
}

Find the missing number between [0, n] (n and numbers from 0 to n-1 are given by the user) using DAC

As a homework, I have to find the missing number from 0 to n using a divide and conquer (DAC) algorithm.
As an input, I get n-1 numbers from [0, n] and n.
I can easily do this with a quicksort and then just see which number is missing, but that would mean the complexity of my algorithm will be O(n*log n).
I'm wondering if there is any way I can do lower than that.
I was thinking that I might get the sum of the input (somehow) using DAC, and then the number missing will be n - sum. This would be O(n) complexity.
Is there any other way to get a complexity lower than O(n) (without using any space) and also, is my idea a good one? If not, can you give me other ideas for this problem, please?
Thanks.
Edit:
I know I should post another question, but I can post only once every 90 minutes (as I recall) and I want to finish this problem now if possible.
How can I calculate the sum of an array using DAC?
int DAC(int low, int high, int a[], int& s)
{
if (low <= high)
{
int pivot = (low + high)/2;
s += DAC(low, pivot - 1, a, s);
s += DAC(pivot+1, high, a, s);
return a[pivot];
}
}
for this call
cout << DAC(0, n-1, a, s);
Input:
7
1 2 3 4 5 6 7
I get 4 and I don't understand why. I didn't expect it to return only 4.
Edit 2:
I was getting call because I had to cout<<s, not DAC, I'm sorry.
Now I get 52 for the following code, with input: n=7, a=1 2 3 4 5 6 7
#include <iostream>
#include <algorithm>
using namespace std;
void citire(int& n, int a[])
{
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
}
int DAC(int low, int high, int a[], int& s)
{
if (low <= high)
{
int pivot = (low + high)/2;
s += DAC(low, pivot - 1, a, s);
s += DAC(pivot+1, high, a, s);
return a[pivot];
}
}
int main() {
int a[100], n, s = 0;
citire(n, a);
DAC(0, n-1, a, s);
cout << s;
return 0;
}
As sis modified internally, the function DAC doesn't have to return anything.
#include <iostream>
#include <algorithm>
void citire(int& n, int a[])
{
std::cin >> n;
for (int i = 0; i < n; i++)
{
std::cin >> a[i];
}
}
void DAC(int low, int high, int a[], int& s)
{
if (low <= high)
{
int pivot = (low + high)/2;
DAC(low, pivot - 1, a, s);
DAC(pivot+1, high, a, s);
s += a[pivot];
}
}
int main() {
int a[100], n, s = 0;
citire(n, a);
DAC(0, n-1, a, s);
std::cout << s << "\n";
return 0;
}
But std:accumulatewould be much simpler

Sorting with low memory size

What is the best way to sort a dictionary with 1Gbyte size(255 char for each word) with 2G of RAM?
I have already tried quicksort and didn't get the acceptable result.
This the quicksort code:
#include <iostream>
#include <fstream>
#include <cstring>
#define MAXL 4000000
using namespace std;
void swap(char *&ch1,char *&ch2)
{
char *temp = ch1;
ch1 = ch2;
ch2 = temp;
}
int partition (char **arr, int low, int high)
{
string pivot = arr[high]; // pivot
int i = (low - 1); // Index of smaller element
for (int j = low; j <= high- 1; j++)
{
// If current element is smaller than or
// equal to pivot
if (arr[j] <= pivot)
{
i++; // increment index of smaller element
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}
void quickSort(char **arr, int low, int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
int main()
{
fstream file("input.txt",ios::in|ios::out|ios::app);
fstream o("output.txt",ios::out);
char **arr = new char*[MAXL];
for(int i=0;i<MAXL;i++)
arr[i] = new char[255];
long long i=0;
while(file)
{
//words are sepearated by spcae
file.getline(arr[i],256,' ');
i++;
}
file.close();
quickSort(arr, 0, i-2);
for(long long j=0;j<i-1;j++)
{
o << arr[j] << "\n";
}
}
It takes more than 10 minutes to sort the mentioned list but it shouldn't take more than 20 seconds.
(MAXL is the number of words in the 1G file and input words are stored in a text file)
If you can't fit it all in memory, a file-based merge sort will work well.
In-place algorithms are your solution. Find more here:
As another example, many sorting algorithms rearrange arrays into sorted order in-place, including bubble sort, comb sort, selection sort, insertion sort, heapsort, and Shell sort. These algorithms require only a few pointers, so their space complexity is O(log n).

Can I partition the array in K sizes?

I am trying to implement the algorithm from this question: Need idea for solving this algorithm puzzle, but i am missing some edge case which is causing my code to go in infinite loop. I can fix it by doing some cosmetic change but it shows that i didn't understand the algorithm.
Can someone help me out, what i am missing?
#include <stdio.h>
#define max(a, b) (((a)>(b))?(a):(b));
int get_max(int *a, int i, int size)
{
if (i >= size)
return 0;
return max(a[i], get_max(a, i+1, size));
}
int get_sum(int *a, int i, int size)
{
if (i >= size)
return 0;
return a[i] + get_sum(a, i+1, size);
}
int get_partition(int *a, int size, int bound) {
int running_sum = 0;
int partitions = 0, i;
for (i=0;i<size;i++) {
if (a[i] + running_sum <= bound) {
running_sum += a[i];
} else {
running_sum = 0;
running_sum += a[i];
partitions++;
}
}
return partitions;
}
int foo(int *a, int size, int k)
{
int lower = get_max(a, 0, size);
int higher = get_sum(a, 0, size);
int partition;
while (lower < higher) {
int bound = (lower + (higher))/2;
partition = get_partition(a, size, bound);
printf("partition %d bound %d lower %d higher %d\n", partition, bound, lower, higher);
if (partition >= k)
lower = bound;
else
higher = bound;
}
return partition;
}
#define SIZE(a) sizeof(a)/sizeof(a[0])
int main(void) {
int a[] = {2, 3, 4, 5, 6};
printf("%d\n", foo(a, SIZE(a), 3));
return 0;
}
Output:
partition 1 bound 13 lower 6 higher 20
partition 2 bound 9 lower 6 higher 13
partition 3 bound 7 lower 6 higher 9
partition 3 bound 8 lower 7 higher 9
partition 3 bound 8 lower 8 higher 9
...last line keeps repeating.
You have couple of mistakes:
during the binary search, your while test should be while (lower+1 < higher) { and not while (lower < higher) {. You are entering infinite loop when lower = 8, higher = 9. At this stage, your bound would be (lower+higher)/2=8and you would update lower = bound which would not change anything.
at the end of foo you should return higher (not partitions) since your binary search invariant is that for having bound <= lower you can partition the array in more than k parts and forbound >= higher you can partition it in k or less.
your calculation of get_partition is wrong. You don't take into the account the last partition group since you only update partitions when you overflow running_sum. After the for-cycle you should have the statement :
if (running_sum > 0)
partitions++;
Putting it all together:
#include <stdio.h>
#define max(a, b) (((a)>(b))?(a):(b));
int get_max(int *a, int i, int size)
{
if (i >= size)
return 0;
return max(a[i], get_max(a, i+1, size));
}
int get_sum(int *a, int i, int size)
{
if (i >= size)
return 0;
return a[i] + get_sum(a, i+1, size);
}
int get_partition(int *a, int size, int bound) {
int running_sum = 0;
int partitions = 0, i;
for (i=0;i<size;i++) {
if (a[i] + running_sum <= bound) {
running_sum += a[i];
} else {
running_sum = 0;
running_sum += a[i];
partitions++;
}
}
if (running_sum > 0)
partitions++;
return partitions;
}
int foo(int *a, int size, int k)
{
int lower = get_max(a, 0, size);
int higher = get_sum(a, 0, size);
int partition;
while (lower+1 < higher) {
int bound = (lower + (higher))/2;
partition = get_partition(a, size, bound);
printf("partition %d bound %d lower %d higher %d\n", partition, bound, lower, higher);
if (partition > k)
lower = bound;
else
higher = bound;
}
printf("partition %dlower %d higher %d\n", partition, lower, higher);
return higher;
}
#define SIZE(a) sizeof(a)/sizeof(a[0])
int main(void) {
int a[] = {2, 3, 4, 5, 6};
printf("%d\n", foo(a, SIZE(a), 3));
return 0;
}

Resources