PDA

View Full Version : Don't understand qSort behaviour....



Qtonimo
2nd August 2012, 11:58
Hi, i want to use qSort to Sort a QList but I have some problems:

test.h


class Test
{
public:
int number;
QString name;

public:
Test(int number,QString name);
QString toString();

bool operator< (const Test& t) const;
};

test.cpp


Test::Test(int number, QString name):
number(number),
name(name)
{
}

QString Test::toString()
{
return "Test( " + QString::number(number) + " , " + name + ")";
}

bool Test::operator <(const Test& t) const
{
return this->number < t.number;
}


main.cpp


int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

QList<Test*> list;
list.append(new Test(10,"test1"));
list.append(new Test(6,"test2"));
list.append(new Test(8,"test3"));
list.append(new Test(100,"test4"));
list.append(new Test(1,"test5"));
list.append(new Test(5,"test6"));

for(int i = 0; i < list.size(); i++){
qDebug() << list.at(i)->toString();
}

qSort(list.begin(),list.end());
qDebug() << "sorted:";

for(int i = 0; i < list.size(); i++){
qDebug() << list.at(i)->toString();
}

return a.exec();
}


Output:
"Test( 6 , test2)"
"Test( 8 , test3)"
"Test( 100 , test4)"
"Test( 1 , test5)"
"Test( 5 , test6)"
sorted:
"Test( 100 , test4)"
"Test( 10 , test1)"
"Test( 6 , test2)"
"Test( 8 , test3)"
"Test( 1 , test5)"
"Test( 5 , test6)"

spirit
2nd August 2012, 12:15
because in this case pointers are compared, but not object itself.
so, there are to possibility to fix this:
1. populate a list with objects (not pointers)
2. create LessThen function and pass it to qSort


bool caseInsensitiveLessThan(const Test *s1, const Test *s2)
{
return *s1 < *s2;
}
...
qSort(list.begin(),list.end(), caseInsensitiveLessThan);
...

Qtonimo
2nd August 2012, 12:39
So I don't use qSort, I use my own sort function:



for( int size = list.size(); size > 1 ; size -= 1 )
{
for( int r = 1; r < size; r++ ) {
int l = r - 1;
if( list.at(l)->number > list.at(r)->number ) list.swap(l,r);
}
}

spirit
2nd August 2012, 12:42
why? why you're trying to reinvent the wheel? :) use second approach.

Qtonimo
2nd August 2012, 13:10
Because lessThan isn't a member of Test. The method has to be declared outside and is not encapsulated with my class Test :(

spirit
2nd August 2012, 13:12
So, what? :) In this case you'll get only 3 lines of code + tested and optimized qSort function...

Qtonimo
2nd August 2012, 13:15
;) ok you persuaded me to use the second approach.
It works very well.... ;)
thank u

yeye_olive
2nd August 2012, 13:26
@Qtonimo

It makes sense for comparison functions involving Test to be associated with Test (either as a Test method as you did, or as an external friend function as is commonly seen) because the comparison function needs to know the internal structure of Test objects. The situation is completely different for spirit's comparison function for Test* which only uses Test's external interface (in the form of Test::operator<(const Test &)). So, no, there is no breach of encapsulation in spirit's suggestion, which I urge you to follow instead of rolling out your own inefficient sorting algorithm.

Update: sorry, I missed your last reply.

spirit
2nd August 2012, 13:26
You are welcome. :)
btw, you can make lessThan static function in Test class and then use it in qSort like this:


class Test {
....
public:
static bool lessThan(Test *t1, Test *t2);
....
};
...
bool Test::lessThan(Test *t1, Test *t2)
{
return *t1 < *t2;
}
...
qSort(list.begin(),list.end(), &Test::lessThan);
...

amleto
2nd August 2012, 13:30
please, it is THAN, not then!

spirit
2nd August 2012, 13:33
hm? if ... then? come on!
then (http://www.collinsdictionary.com/dictionary/english/then?showCookiePolicy=true) vs than (http://www.collinsdictionary.com/dictionary/english/than?showCookiePolicy=true).

amleto
2nd August 2012, 16:00
less THAN!

spirit
2nd August 2012, 16:04
ok, note, next time use PM instead!