我正在嘗試撰寫一些將在物件指標向量上執行二進制搜索的 C 代碼。作為參考,我的程式就像一個銀行賬戶系統,用戶可以在其中開設一個銀行賬戶并在所述銀行賬戶上進行存款/取款,這反過來又會創建一個新的交易物件,該物件被推回到交易指標物件串列中,如下所示:在 main.cpp 中:
else if (userCommand == "withdraw")
{
try
{
int index;
float amount;
time_t currentTime = time(nullptr); //gets current time
cout << "Please pick the account you wish to withdraw from starting from 1: " << endl;
cin >> index;
if (index > allAccounts.size() || index <= 0) throw InvalidIndexException(); //0 is not an option for any other command other than withdraw so we include it for the exception
cout << "Please give the amount of money you wish to withdraw: " << endl;
cin >> amount;
if (amount < 0) throw NegativeValue("Withdrawal");
allAccounts[index - 1]->withdraw(amount);
Transaction* accountTransaction = new Transaction("Withdrawal", currentTime, amount); //creates new Transaction object that will be passed into the account object
allAccounts[index - 1]->addTransaction(accountTransaction);
}
catch (ExceedOverDraftException)
{
cout << "Current account overdraft exceeded" << endl;
}
catch (NegativeWithdrawalException)
{
cout << "Savings account cannot go below 0" << endl;
}
catch (InvalidIndexException)
{
cout << "Index given does not exist" << endl;
}
catch (NegativeValue e)
{
cout << e.getMessage() << endl;
}
}
else if (userCommand == "deposit")
{
try
{
int index;
float amount;
time_t currentTime = time(nullptr);
cout << "Please pick the account you wish deposit to starting from 1: " << endl;
cin >> index;
if (index > allAccounts.size() || index <= 0) throw InvalidIndexException();
cout << "Please give the amount of money you wish to deposit: " << endl;
cin >> amount;
if (amount < 0) throw NegativeValue("Deposit");
allAccounts[index - 1]->deposit(amount);
Transaction* accountTransaction = new Transaction("Deposit", currentTime, amount);
allAccounts[index - 1]->addTransaction(accountTransaction);
}
catch (InvalidIndexException)
{
cout << "Index does not exist" << endl;
}
catch (NegativeValue e)
{
cout << e.getMessage() << endl;
}
}
else if (userCommand == "search")
{
try
{
int index;
float valueAnswer;
int transactionsSize;
cout << "Please say which account you wish to search transaction for starting from 1" << endl;
cin >> index;
if (index > allAccounts.size()) throw InvalidIndexException();
transactionsSize = allAccounts[index - 1]->getHistorySize();
cout << "Please state what value you wish to search for" << endl;
cin >> valueAnswer;
cout << allAccounts[index - 1]->search(valueAnswer, 0, transactionsSize - 1);
}
catch (InvalidIndexException)
{
cout << "Index given does not exist";
}
catch (TransactionNotFound e)
{
cout << e.getMessage();
}
}
在 account.cpp 中:
void Account::addTransaction(Transaction* t)
{
history.push_back(t); //as the vector is full of pointers the parameter must also be a pointer.
sort(history.begin(), history.end());
}
Transaction Account::search(float value, int start, int end) throw (TransactionNotFound) //search function is a binary search
{
if (start <= end)
{
for (int i = 0; i < history.size(); i )
{
cout << history[i]->getValue() << endl;
}
int mid = (start end) / 2; //midpoint of the vector
if (history[mid]->getValue() == value) return *history[mid];
else if (history[mid]->getValue() < value) return search(value, mid 1, end);
else if (history[mid]->getValue() > value) return search(value, start, mid - 1);
}
else throw TransactionNotFound(value); //if the array has been searched to the point that start has reached the end the transaction doesn't exist
}
如您所見,主要思想是每次進行新交易時,無論是呼叫存款還是取款,都會創建一個交易物件,然后將其添加到向量中,然后按升序排序。為了進行排序,我嘗試遵循使用結構物件而不是類物件(排序自定義物件的向量)的較舊堆疊溢位訊息中的指南,該訊息似乎在結構物件上使用 < 運算子的運算子多載,然后允許要排序的結構物件的向量,我嘗試在我的事務類中將其作為友元函式進行調整,如下所示:在 transaction.cpp 中:
bool operator <(const Transaction& t1, const Transaction& t2)
{
return (t1.value < t2.value); //checks if the next value in the vector is greater than the current value in the vector.
}
However, I have tested the sort method and it doesn't seem to be sorted the objects as I expect it to, in that it doesn't seem to be sorted the objects at all, causing my TransactionNotFound exception to be thrown. I'm genuinely not sure what I've done wrong, I'm assuming it is how I've done my operator overload, but I don't know what I need to do to fix it. Sorry if my code looks awful, I think I realised that my try and catch blocks could go outside the if statement. Also if there is any information about my code that might be needed please let me know, I'm new to stack overflow in general so I'm not sure if what I've included is needed or not. Any help people can give is really appreciated!
uj5u.com熱心網友回復:
除了許多設計缺陷之外,您還有幾個主要的語意錯誤。
第一,也是最重要的,以及為什么排序不起作用的原因:
您將指標存盤在std::vector“歷史記錄”中。但是在比較函式中,您比較參考,因此是值而不是指標。
因此,排序函式不會根據存盤在交易中的值進行排序,而是根據它們在記憶體中的地址進行排序,您不知道并且可能是隨機的(但不受您控制),
如果您一個接一個地創建一個事務,那么它們可能會以遞增的記憶體地址創建。然后std::sort什么都不做。但這純屬巧合。
因此,您需要更改自定義排序功能。為簡單起見,我將使用 Lambda。然后sort陳述句看起來像這樣:
std::sort(history.begin(), history.end(),
[](const Transaction* t1, const Transaction* t2) {return t1->value < t2->value; });
然后排序功能會做你想做的。
2、搜索功能執行錯誤。
遞回的停止條件不正確。必須是if (end < start)。mid的計算也是錯誤的。用一張紙畫一張圖,然后你就會看到它。正確的說法是:
int mid = start (end-start) / 2;
您始終需要添加新的起始值。否則你永遠無法到達區間的上半部分。
然后,一個非常重要的宣告。您不能依賴浮點型別的相等比較。因此,如果要使用貨幣進行計算,則不要使用浮點數或雙精度值。使用整數型別 * 100。
現在讓我們看一個最小的可重現示例:
#include <iostream>
#include <string>
#include <ctime>
#include <vector>
#include <algorithm>
struct Transaction {
std::string type{};
time_t time{};
int value{};
int getValue() { return value; }
};
struct Account {
std::vector<Transaction*> history{};
void addTransaction(Transaction* t) {
history.push_back(t);
std::sort(history.begin(), history.end(),
[](const Transaction* t1, const Transaction* t2) {return t1->value < t2->value; });
}
Transaction* search(float value) {
return bsearch(value, 0, history.size()-1);
}
Transaction* bsearch(float value, int start, int end)
{
for (unsigned int i = 0; i < history.size(); i ) {
// std::cout << history[i]->getValue() << '\n';
}
if (end < start) return nullptr;
int mid = start (end-start) / 2; //
if (history[mid]->getValue() == value)
return history[mid];
else if (history[mid]->getValue() < value) return bsearch(value, mid 1, end);
else return bsearch(value, start, mid - 1);
}
};
int main() {
Account account{};
// Add some demo transactions
account.addTransaction(new Transaction{ {},{},9 });
account.addTransaction(new Transaction{ {},{},8 });
account.addTransaction(new Transaction{ {},{},7 });
account.addTransaction(new Transaction{ {},{},6 });
account.addTransaction(new Transaction{ {},{},5 });
account.addTransaction(new Transaction{ {},{},4 });
account.addTransaction(new Transaction{ {},{},3 });
account.addTransaction(new Transaction{ {},{},2 });
account.addTransaction(new Transaction{ {},{},1 });
Transaction* searchResult{};
searchResult = account.search(4);
if (searchResult)
std::cout << "\nFound: " << searchResult->getValue() << '\n';
else
std::cout << "\nError: 4 not found\n\n";
searchResult = account.search(42);
if (searchResult)
std::cout << "\nFound: " << searchResult->getValue() << '\n';
else
std::cout << "\nError: 42 not found\n\n";
return 0;
}
所以,也許你明白了。
但現在,更重要。設計缺陷。
您正在使用大量例外。您可以像使用 if 陳述句一樣使用它們。
不要這樣做。對例外問題使用例外,而不是可以通過簡單的 if 陳述句處理的小問題。
您應該使用 C 和面向物件的編程。
“存款”和“取款”都是交易。因此,創建一個基類“Transaction”并從中派生一個類“Deposit”和一個類“Withdrawal”。
不要將原始指標用于擁有的記憶體,而是std::unique_ptr. 否則,您會造成大量記憶體泄漏。如果你寫new,那么,在某種程度上,你也需要寫delete。
或者使用智能指標,比如 unique_ptr。這將為您完成這項作業。
一般來說,一個好的提示是,始終進行設計,例如在一張紙上或然而,然后開始編程。
不管怎樣,請繼續你的好作業。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/392685.html
