How can this c++ program be faster? [closed] - c++

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.

Related

Implementation of Bottom Up Merge Sort

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);
}

Complexity of function with array having even and odds numbers separate

So i have an array which has even and odds numbers in it.
I have to sort it with odd numbers first and then even numbers.
Here is my approach to it:
int key,val;
int odd = 0;
int index = 0;
for(int i=0;i<max;i++)
{
if(arr[i]%2!=0)
{
int temp = arr[index];
arr[index] = arr[i];
arr[i] = temp;
index++;
odd++;
}
}
First I separate even and odd numbers then I apply sorting to it.
For sorting I have this code:
for (int i=1; i<max;i++)
{
key=arr[i];
if(i<odd)
{
val = 0;
}
if(i>=odd)
{
val = odd;
}
for(int j=i; j>val && key < arr[j-1]; j--)
{
arr[j] = arr[j-1];
arr[j-1] = key;
}
}
The problem i am facing is this i cant find the complexity of the above sorting code.
Like insertion sort is applied to first odd numbers.
When they are done I skip that part and start sorting the even numbers.
Here is my approach for sorting if i have sorted array e.g: 3 5 7 9 2 6 10 12
complexity table
How all this works?
in first for loop i traverse through the loop and put all the odd numbers before the even numbers.
But since it doesnt sort them.
in next for loop which has insertion sort. I basically did is only like sorted only odd numbers first in array using if statement. Then when i == odd the nested for loop then doesnt go through all the odd numbers instead it only counts the even numbers and then sorts them.
I'm assuming you know the complexity of your partitioning (let's say A) and sorting algorithms (let's call this one B).
You first partition your n element array, then sort m element, and finally sort n - m elements. So the total complexity would be:
A(n) + B(m) + B(n - m)
Depending on what A and B actually are you should probably be able to simplify that further.
Edit: Btw, unless the goal of your code is to try and implement partitioning/sorting algorithms, I believe this is much clearer:
#include <algorithm>
#include <iterator>
template <class T>
void partition_and_sort (T & values) {
auto isOdd = [](auto const & e) { return e % 2 == 1; };
auto middle = std::partition(std::begin(values), std::end(values), isOdd);
std::sort(std::begin(values), middle);
std::sort(middle, std::end(values));
}
Complexity in this case is O(n) + 2 * O(n * log(n)) = O(n * log(n)).
Edit 2: I wrongly assumed std::partition keeps the relative order of elements. That's not the case. Fixed the code example.

Find The Longest Consecutive Subsequence Of Distinct Items In A Sequence [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
How do you find the longest row of different(!) elements in an array?
We have a matrix
Our task is to find a row in this matrix where is the longest row of different elements
For example
0 1 2 3 4 1 2 3
Should count 0 1 2 3 4 = 5 elements
Try to use Kadane's algorithm described here: Maximum Subarray Problem
Just replace sum operation with adding-to-set and find-in-set operations. So, you is able to create a O(n) algo.
This is my try:
#include <iostream>
#include <unordered_set>
using namespace std;
int main() {
int mas[] = {1,2,3,1,2,3,4,1,2};
size_t count = sizeof(mas)/sizeof(mas[0]);
size_t best = 0;
int best_index = 0;
unordered_set<int> unique;
for (int i = 0; i < count; i++) {
while (unique.find(mas[i]) != unique.end()) {
unique.erase(mas[i - unique.size()]);
}
unique.insert(mas[i]);
if (unique.size() > best) {
best = unique.size();
best_index = i - best + 1;
}
}
cout << "Index = " << best_index << " Length = " << best << endl;
}
Gives output:
Index = 3 Length = 4
Suppose you use two data structures:
a std::list of integers
a std::unordered_map mapping integers into iterators of the list
Now operate as follows. When you encounter the next integer, check if it is in the unordered map.
If it is, find the corresponding iterator in the list, and remove it and all items left of it (from both list and unordered map)
If it is not, add it to the list, and set the unordered map to point at it
Furthermore, at each step, track both the step index, and the size of the unordered map (or the list). Output the index of the largest size, at the end.
This algorithm is amortized expected linear time: although there might be a step that removes more than a single list item (from each of the data structures), each item enters and leaves them at most once.
Example
Here is an example of the two data structures at some step. The grey map references items in the blue linked list.
The distinct length is now 4. If 2 is now encountered, however, then it and the link(s) left of it (in this case 3) will be purged before it is added, and the length will be reduced to 3.
You can do this in O(n) using a caterpillar algorithm.
Head and Tail pointers begin in the same spot. You move the head along and add to a hash set if it isn't already there.
If the head can't move, move the tail. Remove the corresponding number from the hash set.
As you're going along, see if there's a new max length.
The head and tail are each at each location once, so it's O(n)
Try something like this:
const int len = 4;
int arr[len][len] = {{1, 2, 2, 2}, {3, 2, 3, 5}, {2, 4, 3, 6}, {1, 1, 1, 1}};
int max = -1, current = 1;
for (int i = 0; i < len; i++) {
for (int j = 1; j < len; j++) {
if (arr[i][j] != arr[i][j - 1]) {
current++;
} else {
if (current > max) {
max = current;
}
current = 1;
}
}
if (current > max) {
max = current;
}
current = 1;
}
// output max
It is not very elegant solution, but it works

Extract the n lowest sums from combinations of elements from m arrays for huge datasets

Let's say you have a number of unsorted arrays containing integers. Your job is to make sums of the arrays. The sums have to contain exactly one value from each array, i.e. (for 3 arrays)
sum = array1[2]+array2[12]+array3[4];
Goal: You should output the 20 combinations that generate the lowest possible sums.
The solution below is off-limits as the algorithm needs to be able to handle 10 arrays that can contain a huge number of integers. The following solution is way too slow for larger number of arrays:
//You already have int array1, array2 and array3
int top[20];
for(int i=0; i<20; i++)
top[i] = 1e99;
int sum = 0;
for(int i=0; i<array1.size(); i++) //One for loop per array is trouble for
for(int j=0; j<array2.size(); j++) //increasing numbers of arrays
for(int k=0; k<array3.size(); k++)
{
sum = array1[i] + array2[j] + array3[k];
if (sum < top[19])
swapFunction(sum, top); //Function that adds sum to top
//and sorts top in increasing order
}
printResults(top); // Outputs top 20 lowest sums in increasing order
What would you do to achieve correct results more efficiently (with a lower Big O notation)?
The answer can be found by considering how to find the absolute lowest sum, and how to find the 2nd lowest sum and so on.
As you only need 20 sums at most, you only need the lowest 20 values from each array at most. I would recommend using std::partial_sort for this.
The rest should be able to be accomplished with a priority_queue in which each element contains the current sum and the indicies of the arrays for this sum. Simply take each index of indicies and increase it by one, calculate the new sum and add that to the priority queue. The top most item of the queue should always be the one of the lowest sum. Remove the lowest sum, generate the next possibilities, and then repeat until you have enough answers.
Assuming that the number of answers needed is much less than Big O should be predominately be the efficiency of partial_sort (N + k*log(k)) * number of arrays
Here's some basic code to demonstrate the idea. There's very likely ways of improving on this. For example, I'm sure that with some work, you could avoid adding the same set of indicies multiple times, and there by eliminate the need for the do-while pop.
for (size_t i = 0; i < arrays.size(); i++)
{
auto b = arrays[i].begin();
partial_sort(b, b + numAnswers, arrays[i].end());
}
struct answer
{
answer(int s, vector<int> i)
: sum(s), indices(i)
{
}
int sum;
vector<int> indices;
bool operator <(const answer &o) const
{
return sum > o.sum;
}
};
auto getSum =[&arrays](const vector<int> &indices) {
auto retval = 0;
for (size_t i = 0; i < arrays.size(); i++)
{
retval += arrays[i][indices[i]];
}
return retval;
};
vector<int> initalIndices(arrays.size());
priority_queue<answer> q;
q.emplace(getSum(initalIndices), initalIndices );
for (auto i = 0; i < numAnswers; i++)
{
auto ans = q.top();
cout << ans.sum << endl;
do
{
q.pop();
} while (!q.empty() && q.top().indices == ans.indices);
for (size_t i = 0; i < ans.indices.size(); i++)
{
auto nextIndices = ans.indices;
nextIndices[i]++;
q.emplace(getSum(nextIndices), nextIndices);
}
}

Find the biggest 3 numbers in a vector

I'm trying to make a function to get the 3 biggest numbers in a vector. For example:
Numbers: 1 6 2 5 3 7 4
Result: 5 6 7
I figured I could sort them DESC, get the 3 numbers at the beggining, and after that resort them ASC, but that would be a waste of memory allocation and execution time. I know there is a simpler solution, but I can't figure it out. And another problem is, what if I have only two numbers...
BTW: I use as compiler BorlandC++ 3.1 (I know, very old, but that's what I'll use at the exam..)
Thanks guys.
LE: If anyone wants to know more about what I'm trying to accomplish, you can check the code:
#include<fstream.h>
#include<conio.h>
int v[1000], n;
ifstream f("bac.in");
void citire();
void afisare_a();
int ultima_cifra(int nr);
void sortare(int asc);
void main() {
clrscr();
citire();
sortare(2);
afisare_a();
getch();
}
void citire() {
f>>n;
for(int i = 0; i < n; i++)
f>>v[i];
f.close();
}
void afisare_a() {
for(int i = 0;i < n; i++)
if(ultima_cifra(v[i]) == 5)
cout<<v[i]<<" ";
}
int ultima_cifra(int nr) {
return nr - 10 * ( nr / 10 );
}
void sortare(int asc) {
int aux, s;
if(asc == 1)
do {
s = 0;
for(int i = 0; i < n-1; i++)
if(v[i] > v[i+1]) {
aux = v[i];
v[i] = v[i+1];
v[i+1] = aux;
s = 1;
}
} while( s == 1);
else
do {
s = 0;
for(int i = 0; i < n-1; i++)
if(v[i] < v[i+1]) {
aux = v[i];
v[i] = v[i+1];
v[i+1] = v[i];
s = 1;
}
} while(s == 1);
}
Citire = Read
Afisare = Display
Ultima Cifra = Last digit of number
Sortare = Bubble Sort
If you were using a modern compiler, you could use std::nth_element to find the top three. As is, you'll have to scan through the array keeping track of the three largest elements seen so far at any given time, and when you get to the end, those will be your answer.
For three elements that's a trivial thing to manage. If you had to do the N largest (or smallest) elements when N might be considerably larger, then you'd almost certainly want to use Hoare's select algorithm, just like std::nth_element does.
You could do this without needing to sort at all, it's doable in O(n) time with linear search and 3 variables keeping your 3 largest numbers (or indexes of your largest numbers if this vector won't change).
Why not just step through it once and keep track of the 3 highest digits encountered?
EDIT: The range for the input is important in how you want to keep track of the 3 highest digits.
Use std::partial_sort to descending sort the first c elements that you care about. It will run in linear time for a given number of desired elements (n log c) time.
If you can't use std::nth_element write your own selection function.
You can read about them here: http://en.wikipedia.org/wiki/Selection_algorithm#Selecting_k_smallest_or_largest_elements
Sort them normally and then iterate from the back using rbegin(), for as many as you wish to extract (no further than rend() of course).
sort will happen in place whether ASC or DESC by the way, so memory is not an issue since your container element is an int, thus has no encapsulated memory of its own to manage.
Yes sorting is good. A especially for long or variable length lists.
Why are you sorting it twice, though? The second sort might actually be very inefficient (depends on the algorithm in use). A reverse would be quicker, but why even do that? If you want them in ascending order at the end, then sort them into ascending order first ( and fetch the numbers from the end)
I think you have the choice between scanning the vector for the three largest elements or sorting it (either using sort in a vector or by copying it into an implicitly sorted container like a set).
If you can control the array filling maybe you could add the numbers ordered and then choose the first 3 (ie), otherwise you can use a binary tree to perform the search or just use a linear search as birryree says...
Thank #nevets1219 for pointing out that the code below only deals with positive numbers.
I haven't tested this code enough, but it's a start:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> nums;
nums.push_back(1);
nums.push_back(6);
nums.push_back(2);
nums.push_back(5);
nums.push_back(3);
nums.push_back(7);
nums.push_back(4);
int first = 0;
int second = 0;
int third = 0;
for (int i = 0; i < nums.size(); i++)
{
if (nums.at(i) > first)
{
third = second;
second = first;
first = nums.at(i);
}
else if (nums.at(i) > second)
{
third = second;
second = nums.at(i);
}
else if (nums.at(i) > third)
{
third = nums.at(i);
}
std::cout << "1st: " << first << " 2nd: " << second << " 3rd: " << third << std::endl;
}
return 0;
}
The following solution finds the three largest numbers in O(n) and preserves their relative order:
std::vector<int>::iterator p = std::max_element(vec.begin(), vec.end());
int x = *p;
*p = std::numeric_limits<int>::min();
std::vector<int>::iterator q = std::max_element(vec.begin(), vec.end());
int y = *q;
*q = std::numeric_limits<int>::min();
int z = *std::max_element(vec.begin(), vec.end());
*q = y; // restore original value
*p = x; // restore original value
A general solution for the top N elements of a vector:
Create an array or vector topElements of length N for your top N elements.
Initialise each element of topElements to the value of your first element in your vector.
Select the next element in the vector, or finish if no elements are left.
If the selected element is greater than topElements[0], replace topElements[0] with the value of the element. Otherwise, go to 3.
Starting with i = 0, swap topElements[i] with topElements[i + 1] if topElements[i] is greater than topElements[i + 1].
While i is less than N, increment i and go to 5.
Go to 3.
This should result in topElements containing your top N elements in reverse order of value - that is, the largest value is in topElements[N - 1].