c++xmlvectorbubble-sort

Vector Sorting Using Bubble Sorting Algorithm


I'm new to programming and currently working on an app to assist with managing my home budget. All the data is stored in an XML file. To sort vectors by date, I've implemented a bubble sort algorithm. However, I'm encountering issues with incorrect results. Could someone please provide guidance on identifying the mistake?

#include <iostream>
#include <vector>
#include <string>
#include "Markup.h"

using namespace std;

class income{
    int userId;
    int amount;
    int itemId;
    string item;
    string date;
    public:
    void setUserId(int i) {userId = i;}
    void setAmount(int a) {amount = a;}
    void setItemId(int i ) {itemId = i;} // Corrected function name
    void setDate(string d) {date = d;}
    void setItem(string i) {item = i;}

    int getUserId()   {return userId;}
    int getAmount()   {return amount;}
    int getItemId()  {return itemId;}
    string getItem() {return item;}
    string getDate()  {return date;}
};

bool returnOlderDate(string date1,string date2) {

    int year1 = stoi(date1.substr(0,2));
    int month1 = stoi(date1.substr(3,2)); // Corrected substring indices
    int day1 = stoi(date1.substr(6,2));   // Corrected substring indices

    int year2 = stoi(date2.substr(0,2));
    int month2 = stoi(date2.substr(3,2)); // Corrected substring indices
    int day2 = stoi(date2.substr(6,2));   // Corrected substring indices

    if (year1 != year2) {
        return year1 < year2;
    }
    if (month1 != month2) {
        return month1 < month2;
    }
    return day1 < day2;
}
void sortVector(vector <income> &incomes) {

    int n = incomes.size();

    for (int i = 0; i < n - 1; ++i) {
        for (int j = 0; j < n - i - 1; ++j) {
            if (returnOlderDate(incomes[j].getDate(), incomes[j + 1].getDate())) {

                swap(incomes[j], incomes[j + 1]);
            } else {

            }
        }
    }
}

vector <income> LoadIncome() {

    CMarkup xml;

    vector <income> incomes;
    bool fileExists = xml.Load("income.xml");

    if(!fileExists) {
        cout << "Empty File" << endl;
        return incomes;
    }

    xml.ResetPos();
    xml.FindElem();
    xml.IntoElem();

    while(xml.FindElem()) {
        income newIncome; // Create a new income object
        xml.FindChildElem("userId");// userId
        newIncome.setUserId(stoi(xml.GetChildData())); // Use newIncome instead of income
        xml.FindChildElem("itemId");
        newIncome.setItemId(stoi(xml.GetChildData())); // Use newIncome instead of income
        xml.FindChildElem("amount");
        newIncome.setAmount(stoi(xml.GetChildData())); // Use newIncome instead of income
        xml.FindChildElem("item");
        newIncome.setItem(xml.GetChildData()); // Use newIncome instead of income
        xml.FindChildElem("date");
        newIncome.setDate(xml.GetChildData()); // Use newIncome instead of income
        incomes.push_back(newIncome); // Push newIncome into the vector
    }

    return incomes;
}

void showIncomes(vector <income>& incomes) { // Corrected function declaration

    for(auto i : incomes) {
        cout << "date: " << i.getDate() << endl;
    }
}

int main()
{
    vector <income> incomes; // Corrected vector declaration
    incomes = LoadIncome();

    sortVector(incomes);// Added to show sorted incomes
    showIncomes(incomes);



    return 0;
}

XMl File

<Income>
<income>
<userId>1878039312</userId>
<incomeId>1877999744</incomeId>
<amount>23</amount>
<item>23</item>
<date>02-05-2024</date>
</income>
<income>
<userId>1878039312</userId>
<incomeId>1877999744</incomeId>
<amount>1243</amount>
<item>1243</item>
<date>01-06-2024</date>
</income>
<income>
<userId>1878039312</userId>
<incomeId>1877999744</incomeId>
<amount>1243</amount>
<item>1243</item>
<date>02-03-2023</date>
</income>
<income>
<userId>1878039312</userId>
<incomeId>1877999744</incomeId>
<amount>1243</amount>
<item>1243</item>
<date>28-05-2024</date>
</income>

Solution

  • The problem is how you parse date strings. The function returnOlderDate assumes that the dates are given in YY-MM-DD format, as can be seen from this code:

        int year1 = stoi(date1.substr(0,2));
        int month1 = stoi(date1.substr(3,2));
        int day1 = stoi(date1.substr(6,2));
    

    ...while your actual input data (XML) is formatted in DD-MM-YYYY format, as for example can be seen here:

        <date>28-05-2024</date>
    

    and here:

        xml.FindChildElem("date");
        newIncome.setDate(xml.GetChildData());
    

    The correction is straightforward. Also, you could rely on string comparison instead of converting each date part to a number. I would however use a helper function to avoid the code repetition you have in returnOlderDate, like so:

    string DD_MM_YYYYtoYYYYMMDD(string date) {
        return date.substr(6,4) + date.substr(3,2) + date.substr(0,2);
    }
    
    bool returnOlderDate(string date1, string date2) {
        return DD_MM_YYYYtoYYYYMMDD(date1) < DD_MM_YYYYtoYYYYMMDD(date2);
    }
    

    Not a problem, but I find the name returnOlderDate misleading, as this function does not return the older date. It returns a boolean that indicates whether the first date comes chronologically before the second date. So maybe rename this function to something like isDateLessThan.