c++sortingfractionsrational-number

How to sort an array of rational numbers in C++?


I want to sort an array of rational numbers of type integers. I have used the Bubble Sort algorithm. I am dividing numerator with denominator and then comparing two rational numbers on the basis of their float quotient value. But, I am not getting the right result.

Code for sorting:

void sort(rational arr[], int n) {
    int i, j;
    for (i = 0; i < n-1; i++)
        for (j = 0; j < n-i-1; j++)
            if (arr[j] > arr[j+1])
                swap(arr[j], arr[j+1]);
}

Code for Swapping:

void swap(rational &r1, rational &r2) {
       rational temp;
       temp.set(r1.getNum(),r1.getDenom());
       r1.set(r2.getNum(),r2.getDenom());
       r2.set(temp.getNum(),temp.getDenom());
}

Code for Comparing:

int operator>(const rational&r2) const {
        float n1 = (float)this->num/(float)this->denom;
        float n2 = (float)r2.num/(float)r2.denom;

        if(n1>n2) return 1;
        if(n1==n2) return 0;
        if(n1<n2) return -1;
}

Main

    int main(int argc, char** argv) {

    rational *arr;
    int n = 10;
    cout<<"\You may enter upto 10 relational numbers. How many?"<<endl;
    cin>> n;
    arr = new rational[n];

    fillArray(arr,n);
    cout<<"\nBefore sorting Array contains: "<<endl;
    displayArray(arr,n);
    cout<<"\nAfter sorting Array contains: "<<endl;
    sort(arr,n);
    displayArray(arr,n);
    return 0;
}

Current output: enter image description here

Expected Output:

enter image description here

It can be in ascending or descending order.

Thanks in advance.


Solution

  • The operator> method is supposed to return a boolean rather than an integer. It would be better written as something like:

    bool operator> (const rational &r2) const {
        return (float)num / denom > (float)r2.num / r2.denom;
    }
    

    By way of example, here's a complete program that shows your current behaviour:

    #include <iostream>
    
    class rational {
        int num, denom;
    public:
        void set(int n, int d) { num = n; denom = d; }
        int getNum() { return num; }
        int getDenom() { return denom; }
    
        int operator>(const rational &r2) const {
            float n1 = (float)num/(float)denom;
            float n2 = (float)r2.num/(float)r2.denom;
    
            if(n1>n2) return 1;
            if(n1==n2) return 0;
            if(n1<n2) return -1;
        }
    
    };
    
    void swap(rational &r1, rational &r2) {
        rational temp;
        temp.set(r1.getNum(),r1.getDenom());
        r1.set(r2.getNum(),r2.getDenom());
        r2.set(temp.getNum(),temp.getDenom());
    }
    
    void sort(rational arr[], int n) {
        int i, j;
        for (i = 0; i < n-1; i++)
            for (j = 0; j < n-i-1; j++)
                if (arr[j] > arr[j+1])
                    swap(arr[j], arr[j+1]);
    }
    
    void displayArray(const char *desc, rational *arr, size_t sz) {
        std::cout << desc;
        for (size_t idx = 0; idx < sz; ++idx) {
            std::cout << "  " << arr[idx].getNum() << "/" << arr[idx].getDenom();
        }
        std::cout << '\n';
    }
    

    If you compile and run that, you'll see:

    Before:  1/3  2/7  -1/4  3/11  5/8  1/2
     After:  1/2  5/8  3/11  -1/4  2/7  1/3
    

    which is basically the same as your output. However, using my suggested comparison operator produces the output:

    Before:  1/3  2/7  -1/4  3/11  5/8  1/2
     After:  -1/4  3/11  2/7  1/3  1/2  5/8
    

    which is correctly sorted, albeit in the opposite order from your expected output. Since you stated in the question that "it can be in ascending or descending order", I assume that's not a problem.


    You should also be aware that the range and/or precision of your rationals is likely to be different to standard floating point values.

    If you have to revert to floats for comparison, I'm not sure you gain that much from having rationals in the first place.

    Of course, it may be that it's okay to use floats just for sorting but rationals everywhere else. But it's something to keep in mind.