I've learned that Merge Sort is a sorting algorithm which follows the principle of Divide and Conquer and it have average time complexity as n(log n).
Here I've divided the array of size n in sub array (initializing with length 2) and conquered it by sorting the sub arrays. Then we proceed the range with multiple of 2 until it's less than length of the array (i.e. 2,4,8,....i where i<length of array).
When it exceeds length of array then function returns the sorted array.
I have used two functions to implement Merge Sort:
Merge Sort (To Produce Sub Array)
If length of array is less than range return array.
Recursion and increasing the range exponentially.
Insertion Sort (To Sort Sub Array)
Sort the element within the range using Insertion Sort. I've chosen insertion sort because it's more efficient than bubble sort and selection sort.
The program works fine and I would like to know whether I've understand the concept of merge sort and implemented it correctly?
//C++ Code
#include<iostream>
// Print
void print(int *arr, int length);
// To Sort the sub array
void insertion_sort(int *arr, int low, int high)
{
for(int i = high; (i-1)>=low; i--)
{
if (arr[i] < arr [i-1])
{
int temp = arr[i];
arr[i] = arr[i-1];
arr[i-1] = temp;
}
}
}
int *merge_sort(int* arr, int length, int index = 2)
{
if (length <= index) // Terminating Condition
{
return arr;
}
// The range is defined by index.
/*
If array has 8 elements: ********
It will sort array until it's range within the length of array.
1st call 2*1 elements max: ** ** ** ** // 2 set as default argument
2nd call 2*2 elements max: **** ****
3rd call 2*3 elements max: ********
Returns Array
*/
// The range is defined by index.
for(int i=0; (i+index)<length; i+=index)
{
// Divide and Sort
insertion_sort(arr, i, i+index);
}
// The range will increase in multiple of 2 (i.e. 2,4,8,....i where i<length of array)
return merge_sort(arr, length, index*2);
}
int main()
{
int length;
std::cout<<"Length of Array: ";
std::cin>>length;
int arr[length];
for(int i=0; i<length; i++)
{
std::cout<<"Enter element "<<i+1<<" : ";
std::cin>>arr[i];
}
int *result = merge_sort(arr, length);
print(result, length);
return 0;
}
void print(int *arr, int length)
{
std::cout<<"Sorted Array: ";
for(int i=0; i<length; i++)
{
std::cout<<arr[i]<<" ";
}
std::cout<<"\n";
}
A pure bottom up merge sort divides an array of n elements into n runs of size 1, then each pass merges even and odd runs. Link to wiki example:
https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation
As suggested in the Wiki example comments, the direction of merge can be changed with each pass. To end up with sorted data in the original array, calculate the number of passes needed, and if the number of passes is odd, compare and swap (if needed) pairs of elements in place to create runs of size 2, then do the merge sort passes.
For a hybrid insertion + merge sort, do the same calculation for the number of passes, and if the number of passes is odd, set initial run size to 32 elements, otherwise, set initial run size to 64 elements. Do a single pass using insertion sort to sort the initial runs, then switch to merge sort.
Simple example code to get pass count (for 32 bit build, assumes n <= 2^31):
size_t GetPassCount(size_t n) // return # passes
{
size_t i = 0;
for(size_t s = 1; s < n; s <<= 1)
i += 1;
return(i);
}
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Here is the link for the program: http://gpe.acm-icpc.tw/domjudge2/pct/showproblemtab.php?probid=10527&cid=5.
Here is the work I have done so far :
First, I created a function that will sort the array which is ord(a, j) in the code below.
The variable j is the size of the array that will increment every time the user input a number.
To compute the median, I have two cases.
1) if the size of the array is even, then I subtract the size of the array by 1 and divide it by 2, then the result will be the index of the sorted array plus the next element of the sorted array divided by 2 to find the median.
For example : an array of {1,3,6,2,7,8} elements. I will sort the array first which will give : {1,2,3,6,7,8} then the median will be (3+6)/2 = 4.
2) if the size of the array is odd, then I subtract the size of the sorted array by 1 and divide it by 2, the result is the index of the median.
For example : an array of {1,3,7,2,5} elements. I will sort the array first which will give : {1,2,3,5,7} then the median is 3.
int* ord(int A[], int n) // function to sort the array
{
for(int i = 0; i < n; i++)
{
for(int v = 0; v < n -1; v++)
{
if(A[v] > A[v+1])
{
swap(A[v], A[v+1]);
}
}
}
return A;
}
int main()
{
int a[N], x, j = 0, c;
while(cin >> x)
{
j++; // This is the size of the array
a[j-1]=x;
// Below is the algorithm for finding the median
if (j == 1) // if the array contains only one value, I just output the value
{
cout << a[0] << endl;
}
else // if it contains more than one value then I compute the median
{
ord(a, j); //sorted array
if (j % 2 == 0) // first case is when the size of the array is even
{
// First I subtract the size of the array by 1 and divide it by 2, then c will be the index of the sorted array plus the next element of the sorted array divided by 2 to find the median
c = (j-1) / 2;
cout << (a[c] + a[c+1]) / 2 << endl;
}
else // second case when the size of the array is odd
{
// First I subtract the size of the array by 1 and divide it by 2, c will be the index of the median
c = j-1;
cout << a[c / 2] << endl;
}
}
}
}
Use a std::vector to hold your ints. Then use std::sort on it. If you have to write your own sort, try to implement a quicksort or a mergsort.
This is a fast sort via a vector and std::sort.
int array_size = 8;
int myints[] = {32,71,12,45,26,80,53,33};
std::vector<int> myvector (myints, myints+array_size);
std::sort (myvector.begin(), myvector.end());
If you need to read up about faster sort algorithms:
https://en.wikipedia.org/wiki/Quicksort
https://en.wikipedia.org/wiki/Merge_sort
The general idea is to do some kind of presorting for parts of the array and then sort everything. This make the runtime log(n)n instead of nn. This is a major speed up, even more the bigger the numbers rise. Example:
log(1024)*1024 = 10*1024 = 10.240 Operations.
1024*1024 ~ 1.000.000 Operations <- 100 times slower
log(1.000.000)*1.000.000 = 20*1.000.000 = 20.000.000 Operations.
1.000.000*1.000.000 = 1.000.000.000.000 Operations <- 50.000 times slower
I think you are doing it wrong.
first of all you should not call the sorting function inside loop, it does the same work every time, and increasing time. It will be enough to call it once after the end of the while loop. This will drastically speed up your program.
Also inside while loop you have first incremented the value of j then you have assigned
a[j-1] = x;
you should first assign
a[j] = x;
and then j++;
because
a[j-1] = x; // here j-1 will take some fraction of milliseconds to calc [j-1].
Hope your program will speed up.
#include <iostream>
using namespace std;
void moveToKthSmallest(int a[], int size, int k);
int main() {
int theArray[17] = {42, 5, 412, 56, 14, 98, 488, 4882, 24, 4, 9, 67, 9424, 2, 1, 3, 5};
int num;
cout << "Move to the kth smallest number in the array (size of 17): " << endl;
cin >> num;
moveToKthSmallest(theArray, 17, num);
return 0;
}
void moveToKthSmallest(int a[], int size, int k) {
int pivot = size / 2;
int pivotValue = a[pivot];
int index1 = 0, index2 = 0;
int s1[size], s2[size]; //not sure about this
for (int i = 0; i < size; i++) {
if (a[i] < pivotValue) {
s1[index1] = a[i];
index1++;
}
else {
s2[index2] = a[i];
index2++;
}
}
int s1Size = index1; //problem?
int s2Size = index2; //problem?
if (s1Size == k - 1) {
cout << pivotValue;
}
else if (s1Size > (k - 1)) {
moveToKthSmallest(s1, s1Size, k);
}
else if (s1Size < (k - 1)) {
moveToKthSmallest(s2, s2Size, k - (s1Size - 1));
}
}
I ask the user to input a number (greater than or equal to 0 or less than or equal to 17) and the program should output the kth smallest number in the already generated array.
The above is my attempt but it crashes whenever I run it. I think it has something to do with the declaration of the arrays s1 and s2 in the function and possibly the size values generated from index1 and index2. I've tried using vectors and dynamic arrays but I keep getting error messages in my compiler such as "error: cannot convert 'std::vector**' to 'int*' for argument '1' to 'void moveToKthSmallest" ... to be quite honest, I'm not quite sure what that means.
Am I missing something obvious here?
The first point of order is that this is tagged C++ and not C. Therefore, instead of an int a[] and an int size, you should be using a straightforward std::vector<int>.
Now, with that out of the way, in your example, you're iterating over the entire array each time you recurse.
The second point of order, I don't understand why recursion is even needed here. The answer can be found with a single iteration over your array.
The most simplest way of doing that is to use a second array, let's say std::vector<int> smallest, then iterate over your std::vector<int> a just once.
When iterating over each element:
if smallest.size() is already k, and the current value is larger than the last value in smallest, then proceed to the next value in a, otherwise remove the last value in smallest.
at this point, smallest.size() is always less than k, therefore add the current value in a to the smallest in a manner that keeps the smallest array in sorted order.
At the end of the iteration, the last value in the smallest vector is the kth smallest value in your original vector.
If you would like to know the position of the kth smallest value, this is just a minor modification to the above algorithm, by tracking the position in the smallest vector, rather than the value.
This seems to be a much simpler, straightforward solution, then a complicated recursion-based approach with a confusing pivoting operation. Also, your pivoting example requires the original array to be modified, while my approach does not, and can be used with a const std::vector<int>, even.
P.S. It's not really necessary to keep smallest in sorted order. With a slight modification to the algorithm, smallest can remain unsorted. The homework assignment here is to adjust this algorithm to not require smallest to remain in sorted order.
I am trying to make a flow chart for my recursive quick sort. I have got so far but not sure if right.
I am trying to show the detail in just a simple flowchart without any code in the flowchart.
This is what I have made so far but I am not sure it is right. What I am trying to find is that how and when does a quick sort know that it has been sorted. Then I can alter the text in the decision box in the flowchart to make more sense.
Here is my code with commenting if of any relevance.
#include <iostream>
using namespace std;
//this variable is the size of the array (amount of numbers in sort)
int const SIZE = 5;
// This function swaps two numbers, arguments for these 2 numbers
void swap(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
// This function prints an array, Arguments for the array to be printed and number of elements in array
void PrintArray(int* array, int n)
{
int i;
for( i = 0; i < n; i++) cout<<array[i]<<',';
}
// This function splits the array around the pivot
// Arguments; array to be split, pivot to be returned, first element and last element
int SplitArray(int* array, int pivot, int startIndex, int endIndex)
{
int leftBoundary = startIndex;
int rightBoundary = endIndex;
//shuffle pivot until both the boundaries meet
while(leftBoundary < rightBoundary)
{
//keep moving until a lesser element is found or until the leftBoundary is reached
while( pivot < array[rightBoundary]
&& rightBoundary > leftBoundary)
{
//shift left through the split section
rightBoundary--;
}
swap(array[leftBoundary], array[rightBoundary]);
//keep moving through the array until a greater or equal element is found or until the section end is reached
while( pivot >= array[leftBoundary]
&& leftBoundary < rightBoundary)
{
//shift right through the split section
leftBoundary++;
}
swap(array[rightBoundary], array[leftBoundary]);
}
//returns the split point of the array because the left and right boundary are equal
return leftBoundary;
}
//This function quicksorts the data with arguments for array and its first and last element
void QuickSort(int* array, int startIndex, int endIndex)
{
//set the pivot as the start of split array
int pivot = array[startIndex];
int splitPoint;
//if they are equal then there is only one element and the sorting has finished
if(endIndex > startIndex)
{
//gets the position of the pivot and sets data in that position to pivot variable
splitPoint = SplitArray(array, pivot, startIndex, endIndex);
array[splitPoint] = pivot;
//**RECURSION - Quick sort first half of the array (left of pivot point)
QuickSort(array, startIndex, splitPoint-1);
//**RECURSION - Quick sort second half of the array (right of pivot point)
QuickSort(array, splitPoint+1, endIndex);
}
}
//beggining of main program, makes use of the functions declared before this
int main()
{
int array[SIZE];
//input unsorted array elements
cout << "This program demonstrates a quick sort using a recursive algorithm" << endl;
for(int i = 0; i < SIZE; i++)
{
cout<<"Enter an integer : ";
cin>>array[i];
}
//output the unsorted list
cout<<endl<<"The list you input is : "<<endl;
PrintArray(array, SIZE);
//sort array from first to last element and output the sorted list
QuickSort(array,0,SIZE - 1);
cout<<endl<<"The list has been sorted, now it is : "<<endl;
PrintArray(array,SIZE);
//refresh the input stream and
cin.sync();
cin.get();
}
Here I have written code for finding median of two sorted arrays:
#include<iostream>
using namespace std;
#define L 5
#define M 6
const int N=L+M;
int A[1000];//define 1 indexed aarray
int B[1000];
int max(int c,int d){
return (c>=d)?c:d;
}
int min(int c,int d)
{
return (c<=d)?c:d;
}
void read(){
cout<<" enter A array "<<endl;
for (int i=1;i<=L;i++)
cin>>A[i];
cout<<endl;
cout<<"enter B array "<<endl;
for (int i=1;i<=M;i++)
cin>>B[i];
cout<<endl;
}
int median(int a[],int b[],int left,int right){
if (left>right) {
return median(b,a,max(1,(N/2)-L),min(M,N/2));
}
int i=int(left+right)/2;
int j=int(N/2)+i;
if((j==0 || a[i]>b[j]) && (j==M || a[i]<=b[j+1])){
return a[i];
}
else
{
if((j==0 || a[i]>b[j]) &&(j!=M && a[i]>b[j+1]))
return median(a,b,left,i-1);
}
return median(a,b,i+1,right);
}
int main(){
return 0;
}
My question is what could be left and right values? It is from introduction to algorithms, I just don't understand what are values of left and right variables?
I have defined left and right as 1 and N and tested with following arrays:
3 5 7 9 11 13
1 2 4 8 10
Answer is 13, which is not correct sure, what is wrong?
The homework problem you cited in a comment has what looks to be a pretty good explanation of left and right, including the starting values for them:
Let the default values for left and right be such that calling
MEDIAN-SEARCH(A,B) is equivalent to
MEDIAN-SEARCH(A[1 ..l],B[1 ..m],max(1,ceil(n/2) - m),min(l,ceil(n/2)))
The invariant in MEDIAN-SEARCH(A,B) is that the median is always in
either A[left ..right] or B. This is true for the initial call because
A and B are sorted, so by the definition of median it must be between
max(1,ceil(n/2) - m) and min(l,ceil(n/2)), inclusive. It is also true
the recursive calls on lines 8 and 9, since the algorithm only
eliminates parts of the array that cannot be the median by the
definition of median. The recursive call on line 2 also preserves the
invariant since if left > right the median must be in B between the
new left and right values.
If you work through the algorithm on paper with small arrays, it should become more clear what's going on. The algorithm converges in only a few steps if your arrays are smaller than a total of say 16 elements, so it should be quite workable on paper.
Please consider the following
std::cout << "enter all number separated by a space ending with 'q'"
<< std::endl;
std::vector<int> v(
(std::istream_iterator<int>(std::cin)),
std::istream_iterator<int>());
std::sort(v.begin(), v.end());
std::cout << "median value is: "
<< std::advance(v.begin(), v.size()/2);
<< std::endl;
Here is the code for finding the median of two sorted arrays of unequal length using the merge method of mergesort
package FindMedianBetween2SortedArrays;
import java.util.Scanner;
public class UsingMergeMethodOfMergeSort {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
try{
System.out.println("Enter the number of elements in the first SORTED array");
int n = in.nextInt();
int[] array1 = new int[n];
System.out.println("Enter the elements of the first SORTED array");
for(int i=0;i<n;i++)
array1[i]=in.nextInt();
System.out.println("Enter the number of elements in the second SORTED array");
int m = in.nextInt();
int[] array2 = new int[m];
System.out.println("Enter the elements of the second SORTED array");
for(int i=0;i<m;i++)
array2[i]=in.nextInt();
System.out.println("Median of the two SORTED arrays is: "+findMedianUsingMergeOfMergeSort(array1,array2));
}
finally{
in.close();
}
}
private static int findMedianUsingMergeOfMergeSort(int[] a, int[] b) {
/* a1 array and a2 array can be of different lengths.
For Example:
1.
a1.length = 3
a2.length = 6
totalElements = 3+6=9 (odd number)
2.
a1.length = 4
a2.length = 4
totalElements = 4+4=8 (even number)
*/
int totalElements = a.length+b.length; // totalElements is the addition of the individual array lengths
int currentMedian = 0;
int prevMedian = 0;
int i=0; // Index for traversing array1
int j=0; // Index for traversing array2
for(int k=0;k<totalElements;k++){ // k is index for traversing the totalElements of array1 and array2
/*NOTE: In this entire for loop, the "if", "else" and "else if" is VERY IMP. DONOT interchange among them*/
// if array1 is exhausted
if(i==a.length)
currentMedian=b[j++]; // elements of the second array would be considered
// if array2 is exhausted
else if(j==b.length)
currentMedian=a[i++]; // elements of the first array would be considered
else if(a[i]<b[j])
currentMedian=a[i++];
else //(b[j]<=a[i]) // this condition is ONLY "else" and not "if" OR "else if"
currentMedian=b[j++];
if(k==totalElements/2) // we reached the middle of the totalElements where the median of the combined arrays is found
break;
prevMedian = currentMedian;
}
// if the totalElements are odd
if(totalElements%2!=0)
return currentMedian;
else
return (prevMedian+currentMedian)/2;
}
}
/*
Analysis:
Time Complexity = Linear Time, O((m+n)/2)
Space Complexity = O(1)
*/
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
double median;
for(int i = 0; i<nums2.size();++i){
nums1.push_back(nums2[i]);
};
sort(nums1.begin(),nums1.end());
if(nums1.size()%2 == 0){
median = (double)(nums1[(nums1.size()/2)-1] + nums1[nums1.size()/2])/2;
}else{
if(nums1.size() == 1) median = nums1[0];
median = nums1[((nums1.size()/2) + (nums1.size()%2)) - 1];
}
return median;
};
};
I am trying to improve my C++ by creating a program that will take a large amount of numbers between 1 and 10^6. The buckets that will store the numbers in each pass is an array of nodes (where node is a struct I created containing a value and a next node attribute).
After sorting the numbers into buckets according to the least significant value, I have the end of one bucket point to the beginning of another bucket (so that I can quickly get the numbers being stored without disrupting the order). My code has no errors (either compile or runtime), but I've hit a wall regarding how I am going to solve the remaining 6 iterations (since I know the range of numbers).
The problem that I'm having is that initially the numbers were supplied to the radixSort function in the form of a int array. After the first iteration of the sorting, the numbers are now stored in the array of structs. Is there any way that I could rework my code so that I have just one for loop for the 7 iterations, or will I need one for loop that will run once, and another loop below it that will run 6 times before returning the completely sorted list?
#include <iostream>
#include <math.h>
using namespace std;
struct node
{
int value;
node *next;
};
//The 10 buckets to store the intermediary results of every sort
node *bucket[10];
//This serves as the array of pointers to the front of every linked list
node *ptr[10];
//This serves as the array of pointer to the end of every linked list
node *end[10];
node *linkedpointer;
node *item;
node *temp;
void append(int value, int n)
{
node *temp;
item=new node;
item->value=value;
item->next=NULL;
end[n]=item;
if(bucket[n]->next==NULL)
{
cout << "Bucket " << n << " is empty" <<endl;
bucket[n]->next=item;
ptr[n]=item;
}
else
{
cout << "Bucket " << n << " is not empty" <<endl;
temp=bucket[n];
while(temp->next!=NULL){
temp=temp->next;
}
temp->next=item;
}
}
bool isBucketEmpty(int n){
if(bucket[n]->next!=NULL)
return false;
else
return true;
}
//print the contents of all buckets in order
void printBucket(){
temp=bucket[0]->next;
int i=0;
while(i<10){
if(temp==NULL){
i++;
temp=bucket[i]->next;
}
else break;
}
linkedpointer=temp;
while(temp!=NULL){
cout << temp->value <<endl;
temp=temp->next;
}
}
void radixSort(int *list, int length){
int i,j,k,l;
int x;
for(i=0;i<10;i++){
bucket[i]=new node;
ptr[i]=new node;
ptr[i]->next=NULL;
end[i]=new node;
}
linkedpointer=new node;
//Perform radix sort
for(i=0;i<1;i++){
for(j=0;j<length;j++){
x=(int)(*(list+j)/pow(10,i))%10;
append(*(list+j),x);
printBucket(x);
}//End of insertion loop
k=0,l=1;
//Linking loop: Link end of one linked list to the front of another
for(j=0;j<9;j++){
if(isBucketEmpty(k))
k++;
if(isBucketEmpty(l) && l!=9)
l++;
if(!isBucketEmpty(k) && !isBucketEmpty(l)){
end[k]->next=ptr[l];
k++;
if(l!=9) l++;
}
}//End of linking for loop
cout << "Print results" <<endl;
printBucket();
for(j=0;j<10;j++)
bucket[i]->next=NULL;
cout << "End of iteration" <<endl;
}//End of radix sort loop
}
int main(){
int testcases,i,input;
cin >> testcases;
int list[testcases];
int *ptr=&list[0];
for(i=0;i<testcases;i++){
cin>>list[i];
}
radixSort(ptr,testcases);
return 0;
}
I think you're severely overcomplicating your solution. You can implement radix using the single array received in the input, with the buckets in each step represented by an array of indices that mark the starting index of each bucket in the input array.
In fact, you could even do it recursively:
// Sort 'size' number of integers starting at 'input' according to the 'digit'th digit
// For the parameter 'digit', 0 denotes the least significant digit and increases as significance does
void radixSort(int* input, int size, int digit)
{
if (size == 0)
return;
int[10] buckets; // assuming decimal numbers
// Sort the array in place while keeping track of bucket starting indices.
// If bucket[i] is meant to be empty (no numbers with i at the specified digit),
// then let bucket[i+1] = bucket[i]
for (int i = 0; i < 10; ++i)
{
radixSort(input + buckets[i], buckets[i+1] - buckets[i], digit+1);
}
}
Of course buckets[i+1] - buckets[i] will cause a buffer overflow when i is 9, but I omitted the extra check or readability's sake; I trust you know how to handle that.
With that, you just have to call radixSort(testcases, sizeof(testcases) / sizeof(testcases[0]), 0) and your array should be sorted.
To speed up the process with better memory management, create a matrix for the counts that get converted into indices by making a single pass over the array. Allocate a second temp array the same size as the original array, and radix sort between the two arrays until the array is sorted. If an odd number of radix sort passes is performed, then the temp array will need to be copied back to the original array at the end.
To further speed up the process, use base 256 instead of base 10 for the radix sort. This only takes 1 scan pass to create the matrix and 4 radix sort passes to do the sort. Example code:
typedef unsigned int uint32_t;
uint32_t * RadixSort(uint32_t * a, size_t count)
{
size_t mIndex[4][256] = {0}; // count / index matrix
uint32_t * b = new uint32_t [COUNT]; // allocate temp array
size_t i,j,m,n;
uint32_t u;
for(i = 0; i < count; i++){ // generate histograms
u = a[i];
for(j = 0; j < 4; j++){
mIndex[j][(size_t)(u & 0xff)]++;
u >>= 8;
}
}
for(j = 0; j < 4; j++){ // convert to indices
m = 0;
for(i = 0; i < 256; i++){
n = mIndex[j][i];
mIndex[j][i] = m;
m += n;
}
}
for(j = 0; j < 4; j++){ // radix sort
for(i = 0; i < count; i++){ // sort by current lsb
u = a[i];
m = (size_t)(u>>(j<<3))&0xff;
b[mIndex[j][m]++] = u;
}
std::swap(a, b); // swap ptrs
}
delete[] b;
return(a);
}
Since your values are ints in the range of 0 ... 1,000,000
You can create a int array of of size 1,000,001, and do the whole thing in two passes
Init the second array to all zeros.
Make a pass through your input array, and use the value as a subscript
to increment the value in the second array.
Once you do that then the second pass is easy.
walk through the second array, and each element tells you how many times that
number appeared in the original array. Use that information to repopulate
your input array.