std :: sort使用函数作为比较器,不工作?

时间:2012-03-20 23:04:52

标签: c++ stl

我无法理解为什么它没有按照DirObj的时间/大小对矢量进行排序....我正在努力解决的代码的相关部分就在下面,但我也把这个项目的完整代码(3个文件)放在那个下面。

编辑:我应该澄清一下,它似乎确实会移动,但最终结果不是有序或反向排序的,而且似乎与我试图排序的属性无关。

相关部分:

sortBy() {
    std::sort(v.begin(), v.end(), byTime);
    std::cout << "Sorted by time:" << std::endl;
    for (it = v.begin(); it != v.end(); ++it) {
        std::cout << **it;
    }
    std::sort(v.begin(), v.end(), bySize);
    std::cout << "Sorted by size:" << std::endl;
    for (it = v.begin(); it != v.end(); ++it) {
        std::cout << **it;
        delete *it;
    }
}

bool byTime(DirObj * x, DirObj * y) {
    return ( ((x->getStat()).st_size) < ((y->getStat()).st_size) );
}

bool bySize(DirObj * x, DirObj * y) {
    return ( ((x->getStat()).st_atime) < ((y->getStat()).st_atime) );
}

Traversal.cpp

/* A file traversal program for the Unix filesystem. */
/* Allows the user to select one of the following options:
    depth-first-order (stack)
    breadth-first-order (queue)
    Sort by size */

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include "DirObj.h"
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>

void printUsage();
void breadthFirst(const std::string);
void depthFirstR(const std::string);
void depthFirstNR(const std::string);
void sortBy(const std::string);
bool byTime(DirObj *, DirObj *);
bool bySize(DirObj *, DirObj *);

int main(int argc, char **argv) {
    std::string buffer;
    int cnt;

    /* input validation, check for too few arguments */
    if (argc < 3) {
        printUsage();
        return 1;
    }

    /* get directory pathname */
    buffer = argv[2];
    buffer.append("/");


    /* check for options */
    if (strcmp(argv[1], "-a") == 0) {
        breadthFirst(buffer);
        std::cout << std::endl << "Recursive depth-first traversal of " << buffer << ":" << std::endl;
        depthFirstR(buffer);
        depthFirstNR(buffer);
        sortBy(buffer);
    }
    else if (strcmp(argv[1], "-b") == 0) {
        breadthFirst(buffer);
    }
    else if (strcmp(argv[1], "-d") == 0) {
        std::cout << std::endl << "Recursive depth-first traversal of " << buffer << ":" << std::endl;
        depthFirstR(buffer);
        depthFirstNR(buffer);
    }
    else if (strcmp(argv[1], "-s") == 0) {
        sortBy(buffer);
    }
    else {
        printUsage();
        return 1;
    }

    std::cout << std::endl << "DONE. All requested traversals were successful." << std::endl;   

    return 0;
}

void printUsage() {
        printf("Usage: ./dirTraverse <mode> <directory pathname>\n");
        printf("   Modes:\n");
        printf("   -a   All traversals\n");
        printf("   -b   Breadth-first\n");
        printf("   -d   Depth-first\n");
        printf("   -s   Sort by size\n");
        printf("   -t   Sort by time\n");
        return;
}

/* uses a queue */
void breadthFirst(const std::string b) {
    std::cout << std::endl << "Breadth-first traversal of " << b << ":" << std::endl;

    struct dirent *d;
    DIR *dir;
    struct stat stat_b;
    std::string buffer;
    buffer = b;

    std::queue<DirObj *> q;
    DirObj * o;

    /* open the initial directory */
    dir = opendir(buffer.c_str());
    if (!dir) {
        std::cout << "Could not open " << buffer << "." << std::endl;
    }
    else {
        /* push all directory entries onto queue */
        while ((d = readdir(dir))) {
            q.push(new DirObj(d, buffer));
        }
        // closedir(dir);
    }

    /* dequeue each directory entry and print */
    while (!q.empty()) {
        o = q.front();
        q.pop();
        std::cout << *o;
        d = o->getEntry();
        stat_b = o->getStat();
        /* if the entry is a directory (but not . or ..) */
        if (S_ISDIR(stat_b.st_mode) && (strcmp(d->d_name, "..") != 0) && (strcmp(d->d_name, ".") != 0)) {
            buffer = o->getPath();
            buffer.append(d->d_name);
            /* open directory */
            dir = opendir(buffer.c_str());
            if (!dir) {
                std::cout << "Could not open " << buffer << "." << std::endl;
            }
            else {
                /* push all directory entries onto queue */
                buffer.append("/");
                while ((d = readdir(dir))) {
                    q.push(new DirObj(d, buffer));
                }
                // closedir(dir);
            }

        }
        delete o;

    }
}

/* recursive, works, very basic */
void depthFirstR(const std::string b) {    
    struct dirent *d;
    DIR *dir;
    struct stat stat_b;
    std::string buffer = b;
    int l = buffer.length();

    /* open initial directory */
    dir = opendir(buffer.c_str());
    if (!dir) {
        std::cout << "Could not open " << buffer << "." << std::endl;
    }
    else {
        /* while there are directory entries, read the next one and print it */
        while ((d = readdir(dir))) {
            buffer.append(d->d_name);
            stat(buffer.c_str(), &stat_b);
            std::cout << buffer << " : {inode=" << d->d_ino << ", size=" << stat_b.st_size << ", time=" << stat_b.st_atime << "}" << std::endl;
            /* if the directory entry is a directory, recursively traverse it */
            if (S_ISDIR(stat_b.st_mode) && (strcmp(d->d_name, "..") != 0) && (strcmp(d->d_name, ".") != 0)) {
                buffer.append("/");
                depthFirstR(buffer);
            }
            buffer = buffer.substr(0, l);
        }
        // closedir(dir);
    }
}

/* non-recursive, uses an explicit stack of DirObj to keep track of paths associated with dirents */
void depthFirstNR(const std::string b) {
    std::cout << std::endl << "Non-recursive depth-first traversal of " << b << ":" << std::endl;

    struct dirent *d;
    DIR *dir;
    struct stat stat_b;
    std::string buffer = b;

    DirObj *o;
    std::stack<DirObj *> s;    

    /* open the initial directory */
    dir = opendir(buffer.c_str());
    if (!dir) {
        std::cout << "Could not open " << buffer << "." << std::endl;
    }
    else {
        /* push all directory entries onto stack */
        while ((d = readdir(dir))) {
            s.push(new DirObj(d, buffer));
        }
        // closedir(dir);
    }

    /* pop each directory entry off stack and print */
    while (!s.empty()) {
        o = s.top();
        s.pop();
        std::cout << *o;
        d = o->getEntry();
        stat_b = o->getStat();
        /* if the entry is a directory (but not . or ..) */
        if (S_ISDIR(stat_b.st_mode) && (strcmp(d->d_name, "..") != 0) && (strcmp(d->d_name, ".") != 0)) {
            /* open directory */
            buffer = o->getPath();
            buffer.append(d->d_name);
            dir = opendir(buffer.c_str());
            if (!dir) {
                std::cout << "Could not open " << buffer << "." << std::endl;
            }
            else {
                /* push all directory entries onto stack */
                buffer.append("/");
                while ((d = readdir(dir))) {
                    s.push(new DirObj(d, buffer));
                }
                // closedir(dir);
            }
        }
        delete o;
    }
}


void sortBy(const std::string b) {
    std::cout << std::endl << "Sorted by size/time traversal of " << b << ":" << std::endl;

    struct dirent *d;
    DIR *dir;
    struct stat stat_b;
    std::string buffer = b;

    DirObj * o;
    std::stack<DirObj *> s;
    std::vector<DirObj *> v;  

    /* open the initial directory */
    dir = opendir(buffer.c_str());
    if (!dir) {
        std::cout << "Could not open " << buffer << "." << std::endl;
    }
    else {
        /* push all directory entries onto stack */
        while ((d = readdir(dir))) {
            s.push(new DirObj(d, buffer));
        }
        // closedir(dir);
    }

    /* pop each directory entry off stack and print */
    while (!s.empty()) {
        o = s.top();
        s.pop();
        v.push_back(o);
        d = o->getEntry();
        stat_b = o->getStat();
        /* if the entry is a directory (but not . or ..) */
        if (S_ISDIR(stat_b.st_mode) && (strcmp(d->d_name, "..") != 0) && (strcmp(d->d_name, ".") != 0)) {
            /* open directory */
            buffer = o->getPath();
            buffer.append(d->d_name);
            dir = opendir(buffer.c_str());
            if (!dir) {
                std::cout << "Could not open " << buffer << "." << std::endl;
            }
            else {
                /* push all directory entries onto stack */
                buffer.append("/");
                while ((d = readdir(dir))) {
                    s.push(new DirObj(d, buffer));
                }
                // closedir(dir);
            }
        }
    }

    std::vector<DirObj *>::iterator it;
    std::sort(v.begin(), v.end(), byTime);
    std::cout << "Sorted by time:" << std::endl;
    for (it = v.begin(); it != v.end(); ++it) {
        std::cout << **it;
    }
    std::sort(v.begin(), v.end(), bySize);
    std::cout << "Sorted by size:" << std::endl;
    for (it = v.begin(); it != v.end(); ++it) {
        std::cout << **it;
        delete *it;
    }
}

bool byTime(DirObj * x, DirObj * y) {
    return ( ((x->getStat()).st_size) < ((y->getStat()).st_size) );
}

bool bySize(DirObj * x, DirObj * y) {
    return ( ((x->getStat()).st_atime) < ((y->getStat()).st_atime) );
}

DirObj.h

    #include <string>
    #include <iostream>
    #include <sys/types.h>
    #include <dirent.h>
    #include <sys/stat.h>
    #include <unistd.h>

class DirObj {

    friend std::ostream& operator<< (std::ostream &out, DirObj &obj);

    private:
        dirent * entry;
        std::string path;
        struct stat stat_b;

    public:
        DirObj(dirent * e, const std::string p);
        DirObj();
        ~DirObj();
        DirObj(const DirObj &rhs);
        DirObj& operator=(const DirObj &rhs);
        std::string getPath() const;
        dirent * getEntry() const;
        struct stat getStat() const;
};

DirObj.cpp

#include "DirObj.h"

DirObj::DirObj(dirent * e = 0, const std::string p = "\0") {
    entry = e;
    path = p;
    std::string buffer = path;
    buffer.append(entry->d_name);
    stat(buffer.c_str(), &stat_b);
}

DirObj::DirObj() {
    entry = 0;
    path = "\0";
}

DirObj::~DirObj() {

}

DirObj::DirObj(const DirObj &rhs) {
    this->entry = rhs.entry;
    this->path = rhs.path;
    this->stat_b = rhs.stat_b;
}

DirObj& DirObj::operator=(const DirObj &rhs) {
    this->entry = rhs.entry;
    this->path = rhs.path;
    this->stat_b = rhs.stat_b;
    return *this;
}

std::string DirObj::getPath() const {
    return path;
}

dirent * DirObj::getEntry() const {
    return entry;
}

struct stat DirObj::getStat() const {
    return stat_b;
}

std::ostream& operator<< (std::ostream &out, DirObj &obj) {
    out << obj.path << (obj.entry)->d_name << ": {inode=" << (obj.entry)->d_ino << ", size=" << (obj.stat_b).st_size << ", time=" << (obj.stat_b).st_atime << "}" << std::endl;
    return out;
}

1 个答案:

答案 0 :(得分:1)

您应该按时间和bySize交换两个函数的名称(混合属性以进行排序)。修正版:

bool byTime(DirObj * x, DirObj * y) {
    return ( ((x->getStat()).st_atime) < ((y->getStat()).st_atime) );
}

bool bySize(DirObj * x, DirObj * y) {
    return ( ((x->getStat()).st_size) < ((y->getStat()).st_size) );
}