2010-09-09 2 views
1

У меня есть следующая структура данных для хранения меридианов и параллелей.Модель данных, циклические ссылки

Каждая точка хранит картографические:
A] географические и пространственные координаты, картографические искажения и т.д.
B] указатель на север/юг/восток/запад узла.

Это позволяет хранить отношения между точками, в первую очередь, их принадлежность к меридиональном/параллельно ...

class Node2DCart 
{ 
    protected: 
      //Coordinates of the point 
      double lat; 
      double lon; 
      double lattrans; 
      double lontrans; 
      double x; 
      double y; 
..... 
      //Pointers to adjacent points in geographic network 
      Node2DCart *left; 
      Node2DCart *right; 
      Node2DCart *top; 
      Node2DCart *bottom; 
..... 
}; 

Структура данных для меридиональных магазинов долготы меридиана, начать точку и конечную точку меридиан и количество очков.

class Meridian 
{ 
    private: 
      unsigned int points_count; 
      double longitude; 
      Node2DCart *start; 
      Node2DCart *end; 
.... 
}; 

Все точки сохраняются в списке узлов:

typedef std::vector<Node2DCart*> TNodes2DCartList; 

class Node2DCartList 
{ 
    protected: 

      TNodes2DCartList nodes; 

    ... 
}; 

Но есть большая проблема написания конструктор копирования для Node2DList. Существует циклическая зависимость между Meridian/Parallel и Node2Dlist.

Копирующий конструктор использует std::map и заменяет старые точки и ссылки на новые, это не проблема реализации ... Однако указатели начинают/заканчиваются от класса Меридиан указывает на точки из старого Node2DList ... Конструктор экземпляра Node2DList должен уведомить все меридианы указали на старые точки Node2DList и изменили все указатели на новые точки Node2DList. Эта модель не позволяет этого.

Возможное решения будет добавление двух указателей, указывающих на меридиан и параллельную точку принадлежит:

class Node2DCart 
{ 
    protected: 
      //Coordinates of the point 
      double lat; 
      double lon; 
      double lattrans; 
      double lontrans; 
      double x; 
      double y; 
..... 
      //Pointers to adjacent points in geographic network 
      Node2DCart *left; 
      Node2DCart *right; 
      Node2DCart *top; 
      Node2DCart *bottom; 
..... 
      Meridian *m; 
      Parallel *p; 
}; 

Я боюсь, что эта предложенная модель не является хорошей. Есть еще велосипедные ссылки между двумя классами ... Кто-нибудь поможет мне улучшить его? Спасибо ...

+0

Когда вы говорите 'Node2DList', вы имеете в виду' TNodes2DCartList', ' Node2DCartList' или что-то еще? – luke

ответ

2

Помогло бы мне улучшить его?

В таких случаях я обычно прибегаю к чему-то вроде этого:

typedef int node_id_t; 
enum { NODE_NULL = 0 }; 
// or enum node_id_t { NODE_NULL=0 }; for strict typing. 

class Node2DCart 
{ 
    protected: 
      node_id_t id; // id of the node 
      //Coordinates of the point 
      double lat; 
      double lon; 
      double lattrans; 
      double lontrans; 
      double x; 
      double y; 
..... 
      //Pointers to adjacent points in geographic network 
      node_id_t left; 
      node_id_t right; 
      node_id_t top; 
      node_id_t bottom; 
..... 
}; 

class Meridian 
{ 
    private: 
      unsigned int points_count; 
      double longitude; 
      node_id_t start; 
      node_id_t end; 
.... 
}; 

/* ... */ 

std::vector<Node2DCart *> node_registry; 

// during initialization: 
node_registry.push_back(NULL); 
// to reserve 0th element to denote the NULL pointer 

Node2DCart * 
GetNode(node_id_t id) 
{ 
    // placeholder of the id range check 
    return node_registry[id]; 
}; 

node_id_t 
AddNode(Node2DCart *n) 
{ 
    node_registry.push_back(n); 
    return node_id_t(node_registry.size()-1); 
}; 

А затем с помощью цифровой node_id_t вместо Node2DCart *. Также можно добавить std::set (или , обновленный/протестированный в AddNode()), чтобы гарантировать, что все объекты Node2DCart уникальны и если не повторно использовать идентификатор существующего объекта.

По существу адресация схема, предоставляющая каждому узлу уникальный глобальный идентификатор. Не самое приятное/простое решение с глобальным контейнером, но помогло мне не раз. Особенно, чтобы избежать утечек памяти и обеспечить чистое уничтожение всей иерархии взаимозависимых объектов.

Вместо typedef int node_id_t также можно использовать struct node_id_t { int id; }; и операторы преобразования перегрузки для упрощения поиска идентификаторов узлов.

+0

+1 для схемы адресации, вот что я использовал в подобной ситуации. Что касается 'node_id_t', я могу только рекомендовать Boost.StrongTypedef: он создает новый тип со всеми характеристиками старого, но это НЕ неявно конвертируемо. Очень удобно. –

0

В моем мнении, решение, заменяющее указатели индексами в некоторых случаях, будет медленным.

  • Если мы не удалим точку, point_id будет представлять индекс его точки, например. узлов [poin_id], это нормально.

  • Но если мы удалим любую точку списка, point_id не будет представлять свой индекс в списке. Нам нужно будет использовать std :: find и получить point_id найденной точки. Это значительно уменьшает скорость кода ...

  • Если мы удалим любую точку, мы можем перестроить список точек, чтобы избежать проблем, упомянутых выше. Но нам не нужно забывать переиндексировать все начальные/конечные индексы Meridinans ... Но это занимает некоторое время и делает то же самое, что и конструктор копирования в вопросе. И я думаю, что влияет на данные некоторого класса другим классом, используя конструктор копирования представляет собой не очень подходящее предложение структуры данных ...