Реализация объектно-ориентированных графов в С++

Мне нужно реализовать симуляцию WWW на С++ с использованием графов, где узлы — это веб-страницы, а направленные ребра — это URL-адреса.

В школе, на нашем уровне, мы еще начинаем с объектно-ориентированного программирования, поэтому они предложили реализовать с помощью списков смежности и матриц смежности, но мне они не нравятся, ибо они монстры памяти и очень ограничены.

Вопрос:
Можете ли вы предложить другую структуру данных (предпочтительно объектно-ориентированную), которая использует указатели (в качестве ребер) на другие узлы, и где я могу динамически генерировать столько ребер, сколько захочу???

Я прочитал это, но не нашел ничего полезного: Объектно-ориентированная реализация графа структуры данных


person Salim Mahboubi    schedule 15.04.2014    source источник
comment
А как насчет других связанных ссылок, появляющихся в разделе Полезные справа от вашего вопроса?   -  person πάντα ῥεῖ    schedule 16.04.2014
comment
Нет, большинство из них используют списки смежности или об ошибках, ничего о структуре, подобной той, которую я указал.   -  person Salim Mahboubi    schedule 16.04.2014
comment
"подобно тому, что я сказал" Тогда, возможно, пришло время добавить к вашему вопросу поясняющий пример кода того, что вы уже пробовали (пожалуйста, не публикуйте код в качестве комментария!) .   -  person πάντα ῥεῖ    schedule 16.04.2014
comment
Я редактировал свой ответ несколько раз, чтобы исправить/доработать пример кода, который я включил. Пожалуйста, примите ответ или уточните свой вопрос, потому что немного неясно, как на него ответить.   -  person M2tM    schedule 16.04.2014


Ответы (1)


Честно говоря, попытка представить это только в одной структуре данных окажется довольно неэффективной. На самом деле у вас есть меньший список регистраторов доменов, которые обеспечивают поиск. Что-то более точное, чем один тупой график, было бы:

#include <iostream>
#include <memory>
#include <map>
#include <vector>
#include <string>
#include <set>

class Webpage;
class Registrar : public std::enable_shared_from_this<Registrar> {
public:
    std::shared_ptr<Webpage> resolve(const std::string &url);
private:
    std::map<std::string, std::shared_ptr<Webpage>> pages;
};

class Webpage {
public:
    Webpage(std::shared_ptr<Registrar> registrar, const std::string &url) :
        registrar(registrar),
        url(url){
    }

    std::shared_ptr<Webpage> addLink(const std::string &url){
        links.push_back(url);
        return registrar->resolve(url);
    }

    std::vector<std::shared_ptr<Webpage>> resolvePageLinks(){
        std::vector<std::shared_ptr<Webpage>> pages;
        for (auto &linkUrl : links){
            pages.push_back(registrar->resolve(linkUrl));
        }
        return pages;
    }

    std::string getUrl() const{
        return url;
    }
private:
    std::string url;
    std::shared_ptr<Registrar> registrar;
    std::vector<std::string> links;
};

std::shared_ptr<Webpage> Registrar::resolve(const std::string &url){
    auto found = pages.find(url);
    if (found != pages.end()){
        return found->second;
    }
    else{
        auto webpage = std::make_shared<Webpage>(shared_from_this(), url);
        pages.insert({url, webpage});
        return webpage;
    }
}

void printPageHierarchy(std::shared_ptr<Webpage> current, int depth, std::set<std::shared_ptr<Webpage>> &visited){
    std::cout << std::string(3*depth, ' ');
    std::cout << current->getUrl() << std::endl;
    if (visited.find(current) == visited.end()){
        visited.insert(current);
        ++depth;
        for (auto page : current->resolvePageLinks()){
            printPageHierarchy(page, depth, visited);
        }
    }else{
        std::cout << std::string(3*depth, ' ');
        std::cout << "..." << std::endl;
    }
}

void printPageHierarchy(std::shared_ptr<Webpage> current){
    std::set<std::shared_ptr<Webpage>> visited;
    printPageHierarchy(current, 0, visited);
}

int main(){
    auto registrar = std::make_shared<Registrar>();
    auto site1 = registrar->resolve("site1.com");
    site1->addLink("site2.com");
    site1->addLink("site3.com")->addLink("site4.com")->addLink("site1.com");
    std::cout << "From site1.com:" << std::endl;    
    printPageHierarchy(site1);

    std::cout << "_____________\nFrom site3.com:" << std::endl;
    printPageHierarchy(registrar->resolve("site3.com"));
}

Это довольно упрощенно и, очевидно, минимально. Ваш вопрос делает немного неясным, каковы именно ваши требования на самом деле.

person M2tM    schedule 15.04.2014
comment
Я думаю, что это тот ответ, который мне нужен, но Codeblocks, использующий GNU GCC, не компилирует это - person Salim Mahboubi; 16.04.2014
comment
Он основан на C++11. Я могу скомпилировать его в Visual Studio, clang тоже должен его скомпилировать, и GCC 4.5+ тоже должен. - person M2tM; 16.04.2014
comment
Ах! Спасибо, я надеюсь, что вы не возражаете, что я держу ветку открытой, пока полностью не пойму и не скомпилирую это или другое предложение. Спасибо. - person Salim Mahboubi; 16.04.2014
comment
Пожалуйста, просто обновите снова, когда разберетесь. :) Я перепроверил, и решение (как оно сейчас на странице) действительно компилируется в MSVS 2013, и я не использую ничего нестандартного, поэтому оно также должно работать, пока включен C++11 ( у вас может быть старый компилятор или может отсутствовать флаг компиляции C++11). Не стесняйтесь спрашивать, если у вас есть дополнительные вопросы. Мой скайп Дервакор. - person M2tM; 16.04.2014
comment
Добавлен второй вызов printPageHeirarchy, чтобы показать печать с точки зрения site3.com. - person M2tM; 16.04.2014
comment
Наконец-то мне удалось скомпилировать С++ 11, теперь я прочитаю несколько курсов по этому поводу, чтобы понять ваш код, особенно это множество скобок. :p Большое спасибо. - person Salim Mahboubi; 16.04.2014
comment
Я бы порекомендовал язык программирования C++ Бьярна Страуструпа. stroustrup.com/4th.html - person M2tM; 16.04.2014
comment
Не делайте за других домашнее задание, пока в следующий раз они сами не приложат усилий... - person Marc Claesen; 16.04.2014
comment
@MarcClaesen Я сомневаюсь, что он сможет напрямую скопировать / вставить мой ответ в задание, не будучи обвиненным в плагиате, особенно если его другая работа не выглядит так. Понимая мой ответ достаточно, чтобы фактически применить концепции к его собственной реализации или чтобы он мог даже просто объяснить это, он узнал бы больше, чем первоначальная задача научила бы его в любом случае. Домашняя работа ради нее бессмысленна, важна учеба. - person M2tM; 16.04.2014
comment
Спасибо, что приняли. Как прошла твоя домашняя работа? - person M2tM; 02.05.2014