I was trying to understand bubble sort. While implementing my own version of it for practicing, I implemented it in such a way:
public int[] sort(int[] nums) {
int x = 0;
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
System.out.println(++x);
if (nums[j] > nums[i]) {
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
}
}
return nums;
}
Notice how the inner loop goes from 0 to i.
When I googled this algorithm to find the conventional implementation, I found this implementation:
public int[] sortnew(int[] nums) {
int x = 0;
for (int i = 0; i < nums.length - 1; i++) {
for (int j = 0; j < nums.length - i - 1; j++) {
System.out.println(++x);
if (nums[j] > nums[j+1]) {
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
return nums;
}
Here i goes from 0 to array length - i - 1.
In both the cases the number of prints of 'x' are the same. This I believe indicates that the number of computations are same. Then what exactly is the difference between the two practically?
Thank you!
Related
The description of a task goes like this:
We have n numbers, and we have to find quantity of unique sums of all the pairs in the array.
For example:
3 2 5 6 3
The sums of all the pairs(non-repeated) are 5 9 8 6 8 7 5 11 9 8
Unique are 5 9 8 6 7 11
Therefore output is 6
I have come up with this really primitive, and time-consuming (meaning complexity) solution:
int n = 0;
cin >> n;
vector<int> vec(n);
for (int i = 0; i < n; i++)
{
cin >> vec[i];
}
vector<int> sum;
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
sum.push_back(vec[i] + vec[j]);
}
}
sort(sum.begin(), sum.end());
for (int i = 0; i < sum.size()-1;)
{
if (sum[i] == sum[i + 1]) sum.erase(sum.begin() + i);
else i++;
}
cout << endl << sum.size();
I feel like there could be a solution using Combinatorics or something easier. I have thought a lot and couldn't think of anything. So my request is if anyone can improve the solution.
As mentioned above what you need it is difficult to do this without computing the sum of all pairs, so I am not going to handle that, I am just going to advise about efficient data structures.
Analysis of your solution
Your code adds everything in advance O(n^2) then sorts O(n^2 log(n)), then remove duplicates. But since you are erasing from a vector, that ultimately has complexity linear with the number of elements to the end of the list. It means that the second loop will make the complexity of your algorithm O(n^4).
You can count the unique elements in a sorted array without removing
int count = 0;
for (int i = 0; i < sum.size()-1; ++i)
{
if (sum[i] != sum[i + 1]) ++count
}
This change alone makes your algorithm complexity O(n^2 log n).
Alternatives without sorting.
Here are alternatives that O(n^2) and storage depending on the range of the input values instead of the length of the vector (except for the last).
I am testing with 1000 elements smaller between 0 and 10000
vector<int> vec;
for(int i = 0; i < 1000; ++i){
vec.push_back(rand() % 10000);
}
Your implementation sum_pairs1(vec) (18 seconds)
int sum_pairs1(const vector<int> &vec){
vector<int> sum;
int n = vec.size();
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
sum.push_back(vec[i] + vec[j]);
}
}
sort(sum.begin(), sum.end());
for (int i = 0; i < sum.size()-1;)
{
if (sum[i] == sum[i + 1]) sum.erase(sum.begin() + i);
else i++;
}
return sum.size();
}
If you know the range for the sum of the values you can use a bitset, efficient use of memory sum_pairs2<20000>(vec) (0.016 second).
template<size_t N>
int sum_pairs2(const vector<int> &vec){
bitset<N> seen;
int n = vec.size();
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
seen[vec[i] + vec[j]] = true;
}
}
return seen.count();
}
If you know that the maximum sum is not so high (the vector is not very sparse), but you don't know at compilation time you can use a vector, you can keep track of minimum and maximum to allocate the minimum possible and also supporting negative values.
int sum_pairs2b(const vector<int> &vec){
int VMAX = vec[0];
int VMIN = vec[0]
for(auto v : vec){
if(VMAX < v) VMAX = v;
else if(VMIN > v) VMIN = v;
}
vector<bool> seen(2*(VMAX - VMIN) + 1);
int n = vec.size();
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
seen[vec[i] + vec[j] - 2*VMIN] = true;
}
}
int count = 0;
for(auto c : seen){
if(c) ++count;
}
return count;
}
And If you want a more general solution that works well with sparse data sum_pairs3<int>(vec) (0.097 second)
template<typename T>
int sum_pairs3(const vector<T> &vec){
unordered_set<T> seen;
int n = vec.size();
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
seen.insert(vec[i] + vec[j]);
}
}
return seen.size();
}
#include<bits/stdc++.h>
using namespace std;
int
main ()
{
int a[3] = { 3, 2, 1 }, i, j, t = 0, k = 0;
int m;
for (int i = 0; i < 2; i++)
{
m = a[i];
for (int j = i++; j < 3; j++)
{
if (m > a[j])
{
m = a[j];
k = j;
}
}
t = a[i];
a[i] = m;
a[k] = t;
}
for (int i = 0; i < 3; i++)
{
cout << a[i];
}
return 0;
}
You seem to want to implement an insertion sort algorithm by hand. For this task, you should consider using std::sort. I refactored your code such that it basically does the same thing as you wanted and included some tips to make the code more readable and easier to debug for you and others:
#include <algorithm> //only include necessary headers
#include <iostream>
//do not use "using namespace std"
int main ()
{
int a[3] = { 3, 2, 1 };
/*
Declare local variables at the first point they are used an as local as possible.
It is much easier to read, if a no longer necessary variables leaves scope.
*/
for (int i = 0; i < 2; i++) {
int min = a[i]; //use names that tell something about what you are doing
int bestIndex = i;
for (int j = i+1; j<3; j++) { //here was your major bug: i++ also increcments i
if (a[j] < min){
min = a[j];
bestIndex = j;
}
}
std::swap(a[i], a[bestIndex]);
//try to use standard algorithms as often as possible. They document your code, are optimized and easier to read.
}
for (int i = 0; i < 3; i++){
std::cout << a[i];
}
return 0;
}
Look at this:
for (int i = 0; i < 2; i++)
{
for (int j = i++; j < 3; j++)
{
}
}
On the first iteration of the outer loop:
i is 0.
Then the inner loop increments it to 1.
Then the outer loop increments it to 2.
Then the outer loop is done, after just one iteration.
You want i+1 in the inner loop, not i++.
#include<bits/stdc++.h>
using namespace std;
int main ()
{
int a[3] = { 3,2,1}, t = 0, k = 0;
int m=0;
bool flag_change =false;
for (int i = 0; i < 2; i++)
{
m = a[i];
for (int j = i+1; j < 3; j++)
{
if (m < a[j]) //changing sing (<>) sort by ascending/sort by descending order
{
m = a[j];
k = j;
flag_change = true;
}
}
if(flag_change)
{
t = a[i];
a[i] = m;
a[k] = t;
flag_change = false;
}
}
for (int i = 0; i < 3; i++)
{
cout << a[i];
}
return 0;
}
I'm done correct you code. Code is working.But it is not good implementation.
I have written this counting sort algorithm, but am not sure why it isn't working... Could anyone check and give me a few pointers on what to fix? Thanks!
#include <iostream>
using namespace std;
int main(){
int arr[10] = {1434, 1415, 1217, 4218, 3618, 176, 1021, 3785, 1891, 1522};
int C[4219];
for (int i = 0; i < 4219; ++i) {
C[i] = 0;
}
for (int j = 0; j < 10; ++j) {
C[arr[j]] = C[arr[j]] + 1;
}
for (int k = 10; k > 0; --k) {
C[k] = C[k] + C[k + 1];
}
int B[10];
for (int l = 0; l < 10; ++l) {
B[C[arr[l]] - 1] = arr[l];
C[arr[l]] = C[arr[l]] - 1;
}
for (int m = 0; m < 10; ++m) {
cout << B[m] << " ";
}
return 0;
}
The problem is in the third loop. You iterate only through 10 elements of the array C.
You had created small mistake in the code.....
#include <iostream>
using namespace std;
int main(){
int arr[10] = {1434, 1415, 1217, 4218, 3618, 176, 1021, 3785, 1891, 1522};
int C[4219];
for (int i = 0; i < 4219; ++i) {
C[i] = 0;
}
for (int j = 0; j < 10; ++j) {
C[arr[j]] = C[arr[j]] + 1;
}
for (int k = 1; k < 4219; ++k) { // mistake
C[k] = C[k] + C[k - 1];
}
int B[10];
for (int l = 9; l >=0; --l) { // suggestion
B[C[arr[l]] - 1] = arr[l];
C[arr[l]] = C[arr[l]] - 1;
}
for (int m = 0; m < 10; ++m) {
cout << B[m] << " ";
}
return 0;
}
Beside that I would like to give you one suggestion that in the loop traverse from right to left as it will maintain the stability of the sort..
Stability means suppose if array has two or more same element then in the stable sort,element which is before in unsorted array will occur first in sorted array.
I am trying to implement the Counting Sort in C++ without creating a function. This is the code that I've written so far, but the program doesn't return me any values. It doesn't give me any errors either. Therefore, what is wrong?
#include <iostream>
using namespace std;
int main()
{
int A[100], B[100], C[100], i, j, k = 0, n;
cin >> n;
for (i = 0; i < n; ++i)
{
cin >> A[i];
}
for (i = 0; i < n; ++i)
{
if (A[i] > k)
{
k = A[i];
}
}
for (i = 0; i < k + 1; ++i)
{
C[i] = 0;
}
for (j = 0; j < n; ++j)
{
C[A[j]]++;
}
for (i = 0; i < k; ++i)
{
C[i] += C[i - 1];
}
for (j = n; j > 0; --j)
{
B[C[A[j]]] = A[j];
C[A[j]] -= 1;
}
for (i = 0; i < n; ++i)
{
cout << B[i] << " ";
}
return 0;
}
It looks like you're on the right track. You take input into A, find the largest value you'll be dealing with and then make sure you zero out that many values in your C array. But that's when things start to go wrong. You then do:
for (i = 0; i < k; ++i)
{
C[i] += C[i - 1];
}
for (j = n; j > 0; --j)
{
B[C[A[j]]] = A[j];
C[A[j]] -= 1;
}
That first loop will always go out of bounds on the first iteration (C[i-1] when i=0 will be undefined behavior), but even if it didn't I'm not sure what you have in mind here. Or in the loop after that for that matter.
Instead, if I were you, I'd create an indx variable to keep track of which index I'm next going to insert a number to (how many numbers I've inserted so far), and then I'd loop over C and for each value in C, I'd loop that many times and insert that many values of that index. My explanation may sound a little wordy, but that'd look like:
int indx = 0;
for(int x = 0; x <= k; x++) {
for(int y = 0; y < C[x]; y++) {
B[indx++] = x;
}
}
If you replace the two loops above with this one, then everything should work as expected.
See a live example here: ideone
I'm trying to sort an array made of random numbers from 1 to 10 in an ascending order. I've come up with this function:
void Sort(int a[10], int n)
{
int j = 0;
for (int i = 0; i < n-1; i++)
{
j = i+1;
if (a[i] > a[j])
{
int aux = a[i];
a[i] = a[j];
a[j] = aux;
}
}
}
But when I try to output the array, the function doesn't seem to have worked:
Sort(array, 10);
cout<<endl;
for (int i = 0; i < 10; i++)
{
cout<<array[i]<<" ";
}
The algorithm in your Sort function is wrong. It doesn't sort at all.
Anyway, don't reinvent the wheel, better use std::sort as:
#include <algorithm>
std::sort(array, array+10);
As for your Sort function, which you want to implement using bubble-sort algorithm, possibly for learning purpose. the correct implementation is this:
void Sort(int *a, int n)
{
for (int i = 0; i < n ; i++)
{
for (int j = i + 1; j < n ; j++)
{
if (a[i] > a[j])
{
int aux = a[i];
a[i] = a[j];
a[j] = aux;
}
}
}
}
You are only making n swaps. You need an outer loop on sort (assuming it's bubble sort) so that you continue doing that until you stop doing swaps.
bool Sort(int a[10], int n)
{
bool swapped = false;
int j = 0;
for (int i = 0; i < n-1; i++)
{
j = i+1;
if (a[i] > a[j])
{
int aux = a[i];
a[i] = a[j];
a[j] = aux;
swapped = true;
}
}
return swapped;
}
int main(int argc, char** argv) {
int a[10] = {5,4,3,1,2,6,7,8,9,10};
while (Sort(a,10));
for (int i=0;i<10;++i) {
std::cout << a[i] << std::endl;
}
}
That only does one pass over the data, here is an example showing you what happens
8 7 9 2 3 4 5
After going through your function the result would be
7 8 2 3 4 5 9