Big-O of these two functions - algorithm

Can someone help me find the Big-O of these two functions:
int sum(int A[], int i, int n) {
if (n == 1)
return A[i];
return sum(A, i, n/2) + sum(A, i + n/2, (n+1)/2);
}
and the 'sort' function of:
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
void swapMin(int A[], const int& index) {
int indexMin = index;
for (int i = index-1; i >= 0; --i)
if (A[i] < A[indexMin])
indexMin = i;
swap(A[index], A[indexMin]);
}
void sort(int A[], int n) {
for (int i = n-1; i >= 0; --i)
swapMin(A, i);
}
I believe the first is O(1) and the second is O(n) but I'm not sure if that is correct.

For the first function, you can do this:
And then you can solve it using generating functions.
For the second one, you may use Sigma notation:

Related

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 a hash function to malfunction insertion sort

Below is the original pseudocode for Insertion Sort:
function INSERTIONSORT(A[0..n−1])
for i←1 to n−1 do
j←i−1
while j≥0 and A[j+1]<A[j] do
SWAP(A[j+1],A[j])
j←j−1
A company is using Insertion Sort inside one of their products. You are a cybersecurity expert that was hired by this company to assess any security flaws with their code. After a few tries, you managed to attack their Insertion Sort code and modify it in the following way:
function INSERTIONSORT(A[0..n−1])
for i←1 to n−1 do
j←i−1
while j≥0 and HASH(A,j+1) < HASH(A,j) do
SWAP(A[j+1],A[j])
j←j−1
In other words, instead of indexing the array as A[j] and A[j+1]inside the “while” condition, you now have a hash function that takes the array and a index as the arguments and return an integer. Your job is to implement specific hash functions that will cause the algorithm to malfunction in different ways.
a) Implement a hash function that causes Insertion Sort to keep the original array unchanged. Explain why your solution works.
b) Implement a hash function that causes Insertion Sort to always run in the worst case complexity, even if the resulting array does not end up getting sorted. Explain why your solution works.
c) Implement a hash function that causes Insertion Sort to sort the array in reverse. Explain why your solution works.
I think (a) and (b) is hash(A,j)=j and hash(A,j)=-j, but have no idea if that is correct and have no clue to c.
**Part a) Original array unchanged
#include <stdio.h>
int hash(int arr[], int i) {
return i;
}
void insertionSort(int arr[], int n) {
int i, j, temp;
for (i = 1 ; i <= n - 1; i++)
{
j = i-1;
while ( j >= 0 && hash(arr, j+1) < hash(arr, j))
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
j--;
}
}
}
int main()
{
int i;
int arr[] = {5, 6, 7, 3, 2 , 9, 4};
int n = sizeof(arr)/sizeof(arr[0]);
insertionSort(arr, n);
printf("Original array unchanged:\n");
for (i = 0; i <= n - 1; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}
Part b) Worst Case insertion sort
#include <stdio.h>
int hash(int arr[], int i) {
return -i;
}
void insertionSort(int arr[], int n) {
int i, j, temp;
for (i = 1 ; i <= n - 1; i++)
{
j = i-1;
while ( j >= 0 && hash(arr, j+1) < hash(arr, j))
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
j--;
}
}
}
int main()
{
int i;
int arr[] = {5, 6, 7, 3, 2 , 9, 4};
int n = sizeof(arr)/sizeof(arr[0]);
insertionSort(arr, n);
printf("In worst case(number of swaps maximum)\n");
for (i = 0; i <= n - 1; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}
Part c) Sorted in reverse order.**
#include <stdio.h>
int hash(int arr[], int i) {
return -arr[i];
}
void insertionSort(int arr[], int n) {
int i, j, temp;
for (i = 1 ; i <= n - 1; i++)
{
j = i-1;
while ( j >= 0 && hash(arr, j+1) < hash(arr, j))
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
j--;
}
}
}
int main()
{
int i;
int arr[] = {5, 6, 7, 3, 2 , 9, 4};
int n = sizeof(arr)/sizeof(arr[0]);
insertionSort(arr, n);
printf("Sorted in reverse order:\n");
for (i = 0; i <= n - 1; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}

Using heap sort, append an array elements

I have given an array int A[] = {12,10,9,2,11,8,14,3,5};
In this array, 1st 4 elements(from index 0 to index 3) follow max heap condition. But last 5 elements(index 4 to index 8) don't follow max heap condition. So, I have to write a code so that the whole array follow max heap condition.
I have given a function call max_heap_append(A,3,8); and I have to use it in my code to write the program. It is an assignment so I have to follow the instruction.
I have written this code bellow but when I run the program, nothing happens.
#include <stdio.h>
#include <stdlib.h>
void swap(int * a, int * b )
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void heapify( int A[], int q, int i)
{
int largest = i;
int l = 2 * i + 1 ;
int r = 2 * i + 2;
if( l < q && A[l] > A[largest])
{
largest = l;
}
if( r < q && A[r] > A[largest])
{
largest = r;
}
if( largest != i)
{
swap( &A[i] , &A[largest]);
heapify(A, q, largest);
}
}
void max_heap_append(int A[], int p , int q)
{
int i;
for( i = q / 2 -1; i >= 0; i--)
{
heapify( A , q , i);
}
// sort the heap
for( i = q; i>= 0; i--)
{
swap(&A[0] , &A[i]);
heapify(A, i, 0);
}
}
void printA(int A[], int q)
{
int i;
for( i = 0; i <= q; i++)
{
printf("%d", A[i]);
}
printf("%d\n");
}
int main()
{
int A[] = {12,10,9,2,11,8,14,3};
max_heap_append(A,3,8);
printf("Sorted: ");
printA(A, 8);
return 0;
}
Its not followed heapify from 0 to 3 index.. so u need to heapify all. there is some mistake. if your array size is 8 then u can not excess a[8], you can access a[0] to a[7]. so you need to iterate from 0 to 7.
Try with this:
#include <stdio.h>
#include <stdlib.h>
void swap(int * a, int * b )
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void heapify( int A[], int q, int i)
{
int largest = i;
int l = 2 * i + 1 ;
int r = 2 * i + 2;
if( l < q && A[l] > A[largest])
{
largest = l;
}
if( r < q && A[r] > A[largest])
{
largest = r;
}
if( largest != i)
{
swap( &A[i] , &A[largest]);
heapify(A, q, largest);
}
}
void max_heap_append(int A[], int p , int q)
{
int i;
for( i = q-1; i >= 0; i--)
{
heapify( A , q , i);
}
// sort the heap
for( i = q-1; i>= 0; i--)
{
swap(&A[0] , &A[i]);
heapify(A, i, 0);
}
}
void printA(int A[], int q)
{
int i;
for( i = 0; i < q; i++)
{
printf("%d ", A[i]);
}
printf("\n");
}
int main()
{
int A[] = {12,10,9,2,11,8,14,3};
max_heap_append(A,3,8);
printf("Sorted: ");
printA(A, 8);
return 0;
}
You have several problems in your code
printA
One is/can be indicated by the compiler, in printA :
printf("%d\n");
‘%d’ expects a matching ‘int’ argument, but there no no argument
It is easy to guess you just wanted to print a newline, so that line can be replaced by
putchar('\n');
Still in printA you print the numbers without a separator, the result is not usable, for instance do
printf("%d ", A[i]);
When I look at the call of printA in main the parameter n is the number of elements in A, so the end test of the for is invalid because you try to print a value out of the array, the loop must be :
for( i = 0; i < q; i++)
max_heap_append
in the second for the index i can value 0, in that case you swap the first element of the array with itself, that has no sense and the same for the call of heapify with the 2 last arguments valuing 0
When you call that function in main the parameter q receive the number of elements in the array, which is also the first value of i still in that second for and &A[i] is out of the array. You need to replace that line by
for( i = q-1; i> 0; i--)
If I do all these changes :
Compilation and execution :
bruno#bruno-XPS-8300:/tmp$ gcc -g -Wall h.c
bruno#bruno-XPS-8300:/tmp$ ./a.out
Sorted: 2 3 8 9 10 11 12 14
bruno#bruno-XPS-8300:/tmp$

Mergesort implementation is slow

I'am doing a report about different sorting algorithms in C++. What baffles me is that my mergesort seems to be slower than heapsort in both of the languages. What I've seen is that heapsort is supposed to be slower.
My mergesort sorts an unsorted array with size 100000 at a speed of 19.8 ms meanwhile heapsort sorts it at 9.7 ms. The code for my mergesort function in C++ is as follows:
void merge(int *array, int low, int mid, int high) {
int i, j, k;
int lowLength = mid - low + 1;
int highLength = high - mid;
int *lowArray = new int[lowLength];
int *highArray = new int[highLength];
for (i = 0; i < lowLength; i++)
lowArray[i] = array[low + i];
for (j = 0; j < highLength; j++)
highArray[j] = array[mid + 1 + j];
i = 0;
j = 0;
k = low;
while (i < lowLength && j < highLength) {
if (lowArray[i] <= highArray[j]) {
array[k] = lowArray[i];
i++;
} else {
array[k] = highArray[j];
j++;
}
k++;
}
while (i < lowLength) {
array[k] = lowArray[i];
i++;
k++;
}
while (j < highLength) {
array[k] = highArray[j];
j++;
k++;
}
}
void mergeSort(int *array, int low, int high) {
if (low < high) {
int mid = low + (high - low) / 2;
mergeSort(array, low, mid);
mergeSort(array, mid + 1, high);
merge(array, low, mid, high);
}
}
The example merge sort is doing allocation and copying of data in merge(), and both can be eliminated with a more efficient merge sort. A single allocation for the temp array can be done in a helper / entry function, and the copy is avoided by changing the direction of merge depending on level of recursion either by using two mutually recursive functions (as in example below) or with a boolean parameter.
Here is an example of a C++ top down merge sort that is reasonably optimized. A bottom up merge sort would be slightly faster, and on a system with 16 registers, a 4 way bottom merge sort a bit faster still, about as fast or faster than quick sort.
// prototypes
void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee);
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee);
void TopDownMerge(int a[], int b[], size_t ll, size_t rr, size_t ee);
void MergeSort(int a[], size_t n) // entry function
{
if(n < 2) // if size < 2 return
return;
int *b = new int[n];
TopDownSplitMergeAtoA(a, b, 0, n);
delete[] b;
}
void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee)
{
if((ee - ll) == 1) // if size == 1 return
return;
size_t rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoB(a, b, ll, rr);
TopDownSplitMergeAtoB(a, b, rr, ee);
TopDownMerge(b, a, ll, rr, ee); // merge b to a
}
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee)
{
if((ee - ll) == 1){ // if size == 1 copy a to b
b[ll] = a[ll];
return;
}
size_t rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoA(a, b, ll, rr);
TopDownSplitMergeAtoA(a, b, rr, ee);
TopDownMerge(a, b, ll, rr, ee); // merge a to b
}
void TopDownMerge(int a[], int b[], size_t ll, size_t rr, size_t ee)
{
size_t o = ll; // b[] index
size_t l = ll; // a[] left index
size_t r = rr; // a[] right index
while(1){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
while(r < ee) // else copy rest of right run
b[o++] = a[r++];
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
while(l < rr) // else copy rest of left run
b[o++] = a[l++];
break; // and return
}
}
}

Analyzing an exponential recursive function

I am trying to calculate the complexity of the following
exponential recursive function.
The isMember() and isNotComputed() functions reduce the number
of recursive calls.
The output of this code is a set of A[], B[] which are printed at the
initial part of recursive function call.
Would appreciate any inputs on developing a recursive relationship for this
problem which would lead to the analysis of this program.
Without the functions isMember(), isNotComputed() this code has the complexity of O(2^N). Empirically (with the above two functions) this code has a complexity of O(|N^2||L|). Where L is the number of recursive calls made, i.e. results generated.
I am trying to calculate the complexity of this code as accurate as possible, so that I can compare the efficiency of this with a set of other algorithms which are similar in nature.
void RecuriveCall(int A[], int ASize, short int B[], int BSize,
int y, short int level) {
int C[OBJECTSIZE];
short int D[ATTRIBUTESIZE];
int CSize, DSize;
PrintResult( A,ASize, B, BSize);
for (int j=y; j<n; j++) {
if (! isMember(j, B, BSize)) {
function1(C,CSize,A,ASize,j);
function2(D,DSize,C, CSize);
if (isNotComputed(B, BSize, D, DSize, j)) {
RecursiveCall(C, CSize,D, DSize, j+1, level+1);
}
}
}
}
// Complexity - O(log N) - Binary Search
bool isMember(int j,short int B[], int BSize) {
int first, mid, last;
first = 0;
last = BSize-1;
if (B[first] == j || B[last] == j) {
return true;
}
mid = (first+last)/2;
while (first <= last) {
if (j == B[mid]) {
return true;
}
else if (j < B[mid])
last = mid-1;
else
first = mid+1;
mid = (first+last)/2;
}
return false;
}
// complexity - O(N)
bool isNotComputed(short int B[], int BSize, short int D[], int DSize,int j) {
if (j==0) {
return true;
}
int r = 0;
while (r<BSize && B[r]<j && r<DSize && D[r]<j) {
if (B[r] != D[r]) {
return false;
}
r=r+1;
}
// Now we can check if either B[] or D[] has extra elements which are < j
if (r<BSize && r < DSize && B[r]>=j && D[r] >=j) {// we know it is okay
return true;
}
if (r==BSize && r==DSize) {
return true;
}
if (r==BSize && r<DSize && D[r] >=j) {
return true;
}
if (r==DSize && r<BSize && B[r] >=j) {
return true;
}
return false;
}
// Complexity - O(N)
void function1(int C[],int &CSize,int A[] ,int ASize,int j) {
int tsize = 0;
for (int r=0;r<ASize;r++)
if (I[A[r]][j]==1)
C[tsize++] = A[r];
CSize = tsize;
}
// Complexity - O(|N||G|) - G - number of objects
void function2(short int B[], int &BSize,int A[], int ASize) {
int i,j;
int c=0;
// Iterate through all attributes
for (j = 0; j < MAXATTRIBUTES; ++j) {
// Iterate through all objects
for (i = 0; i < ASize; ++i)
if (!I[A[i]][j])
break;
if (i == ASize)
B[c++] = j;
}
BSize = c;
}
void main() {
n = MAXATTRIBUTES;
for (int r=0; r<MAXOBJECTS; r++)
A[r] = r;
ASize = MAXOBJECTS;
function2(B, BSize, A, ASize);
RecursiveCall(A, ASize,B, BSize, 0, 0);
}
The answer presented by "mohamed ennahdi el idrissi" addresses how a recursive relationship can be developed.
How do you incorporate the functions isMember() and isNotComputed() functions into this. In essence these reduce the number of recursive calls made significantly. Is there a way of introducing a probabilistic function to represent them? i.e P(f(n))xRecCall(n-1). I have seen the complexity of some algorithms been computed e.g. as O(N^2.48). How do you come with such values?
I have tried to adapt the following recurrence relation to your code, see the steps below:
Where n = MAXATTRIBUTES (constant), and m = ASize.

Resources