Если это ваш первый визит, рекомендуем почитать справку по форуму. Для размещения своих сообщений необходимо зарегистрироваться. Для просмотра сообщений выберите раздел. |
Нужен совет по коду(С++) |
Философия, технологии, алгоритмы! |
|
Опции темы |
14.06.2013, 08:39 | #1 |
Registered User
Сообщений: 1,114
Регистрация: 23.06.2007
Возраст: 56
Не в сети |
Нужен совет по коду(С++)
Народ, нужен совет.
Задача следующая. Есть база данных, в которых храниться дерево. Т.е. структура таблицы следующая ID - ключ PARENT ссылка на родительскую ноду CAPTION - заголовок DATA - данные Загружаю следующим образом. 1. Вызываю функцию, в которую передаю откуда я буду читать, и другие параметры. 2. Вызываю рекурсивную процедуру с ссылкой на корень, в который буду загружать. Вроде бы нечего, но появилось условие, если DATA равно 0 то значение показывать не надо. В результате код получился примерно следующим. Код:
void LoadNode(TVirtualNode *NodeParent, bool HideEmpty=false) ; //Процедура настройки дерева void LoadTree(TDataSet *FIBDataSet, TFName *FName, bool HideEmpty=false) { /* Код настраивает дерево в которое будем загружать */ LoadNode(NULL, HideEmpty); //Загрузка } //Процедура загрузки дерева void LoadNode(TVirtualNode *NodeParent, bool HideEmpty) { /* . . . Код добавления новой ноды в дерево . . . */ //Далее в процедуре загрузки стоит примерно следующий код if (HideEmpty) //включён режим скрытия пустых значений { if (IBDataSet->FieldByName(AdvFieldName2)->AsFloat) { //не пустые показываем, вместе с родителями TVirtualNode *SearchNode=Node->Parent; //Делаем видимыми всех невидимых предков while (SearchNode!=NULL && !VirtualStringTreeEx1->IsVisible[SearchNode]) { VirtualStringTreeEx1->IsVisible[SearchNode]=true; SearchNode=SearchNode->Parent; } } else { //нулевые значения скрываем VirtualStringTreeEx1->IsVisible[Node]=false; } } //Ну и так далее...Попутно вызывая эту функцию для загрузки других веток //.... LoadNode(Node,HideEmpty); //.... } 1. Не будет ли лучшим решением, после загрузки дерева, вызывать функцию которая скрывает пустые элементы? 2. И не слишком ли это говнокодерство, использовать каскадный вызов параметров по умолчанию? P.S. в аттаче кинул 2 файла для наглядности |
20.06.2013, 10:10 | #2 |
Форумец
Сообщений: 340
Регистрация: 25.07.2002
Не в сети |
1. два раза бегать по одному и томуже дереву? ИМХО не лучше.
2. ну да, малость криво, ну нечитаемо и без стакана не разберешься, но это объяснимо кривой структурой данных. Я бы, конечно, сделал не так. Все что ниже мое ИМХО 1 Перенес бы всю работу по выбору данных в БД. У нее оптимизатор больше вот пущай им и шевелит. (Правильно настроенные индексы и использования родных механизмов БД сделают выборку гораздо быстрее) 2 Изменил бы структуру дерева. Дерево с одной связью компактно, но работать с ним это алес. NEXT, CHILD структура дерева убирает огромное количество ненужных телодвижений. 3 Еесли уж мы зажаты в рамках задачи, и структурой данных, и необходимостью все делать на клиенте а не в БД то заради читаемости изменил бы алгоритм (твой вариант сложно читать, он работает задомнаперед, ты сначала скрываешь родителя, а потом если есть отображаемые дети включаешь обратно). Если я правильно понял твой код, то задача- вывести дерево скрыв пустые листья и ветки. //hideempty=true - переменная для выбора режима отображения //out AddTreeItem( in ) рекурсивная процедура добавления элемента в дерево //in - родитель //out - признак что были добавлены дети //{ // retvalue =false; // возвращаемое значение // Получить всех детей in // // для каждого малолетки // если (не скрывать пустые, или скрывать пустые но элемент не пустой) или (у элемента есть дети) // if ((!hideempty)||((hideempty)&&(DATA!=0))||(AddTreeI tem(...))) // { // отдать дите родителю; // retvalue=true; // } //return retvalue; //} // main (...) //{ // if (AddTreeItem( корень)) // добавить корень в дерево; //} Последний раз редактировалось MadFish; 20.06.2013 в 11:10. |
20.06.2013, 13:30 | #3 |
Registered User
Сообщений: 1,114
Регистрация: 23.06.2007
Возраст: 56
Не в сети |
MadFish, в принципе я говорил, с программером чей код дорабатываю. Он тоже солидарен, с тем что можно изменить стратегию хранения дерева.
Вы думаете в правильно направлении, т.к. скорее всего склоняетесь к этому методу Nested set model. Проблема ещё в том, что много кода завязано, именно на хранении дерева со старой структурой, и мне не позволят тратить время на его переделку. Хотя я думаю сделать это как "домашнюю работу". За алгоритм спасибо, попробую его доделать до рабочего состояния. |
20.06.2013, 14:22 | #5 | |
Форумец
Сообщений: 39,872
Регистрация: 27.05.2003
Возраст: 46
Не в сети |
Цитата:
2. Нет, совершенно штатная практика. |
|
20.06.2013, 14:30 | #6 | |
Registered User
Сообщений: 1,114
Регистрация: 23.06.2007
Возраст: 56
Не в сети |
Цитата:
Объясню, зачем понадобилось скрытие. Программа это АРМ врача. А скрытие элементов нужно для того что-бы показывать только те материалы которые есть у врача в наличии. Т.е. в идеале это будет типа, галочки, которая скрывает или показывает материалы. А на данный момент, нужно что-бы просто отсутствующие элементы были скрыты. Но учитывая меняющиеся предпочтения нужно заложить маленькую возможность для реализации данной фичи. |
|
20.06.2013, 14:55 | #7 |
Кэп Улитка
Сообщений: 8,067
Регистрация: 04.05.2005
Возраст: 43
Не в сети |
Hopkroft, может просто сделать материализованное представление/доп. таблицу, заложившись на некую максимальную глубину дерева, вида
Код:
Корень - Потомок - Потомок2 - ... - Листовая вершина Выборка по такой таблице, мне кажется, будет намного быстрее, чем каждый раз дерево собирать, да и код проще. Правда, в случае, если дерево несбалансированное (подозреваю, что так оно и есть), то будет проблема с листьями. Еще вариант. Если DATA = количество, то в родительской вершине хранить сумму DATA дочерних. |
20.06.2013, 23:40 | #8 |
highly mean
Сообщений: 1,128
Регистрация: 26.05.2011
Возраст: 35
Не в сети |
А кто-нибудь может пояснить, чем именно хорошо nested set для данной конкретной задачи? Необходимости быстро определять принадлежность узла к какой-то ветке я не вижу. Что-нибудь еще?
WHERE NOT (RIGHT - LEFT = 1 AND DATA = 0)? |
21.06.2013, 10:16 | #10 |
highly mean
Сообщений: 1,128
Регистрация: 26.05.2011
Возраст: 35
Не в сети |
Хм… Вот еще, фтыкание в гугл и википедию показывает, что альтернативным решением является использование рекурсивных CTE, то есть WITH RECURSIVE blah-blah SELECT blah. Которые (выражения), в свою очередь, реализованы в Firebird версий 2.1+. Что насчет этого подхода?
|
21.06.2013, 11:54 | #11 |
Форумец
Сообщений: 340
Регистрация: 25.07.2002
Не в сети |
silly, как вариант. я сразу говорил, что лучше всю выборку данных перенести на БД (хранимки, пакеты итп). У БД оптимизатор толще, больше удовольствия можно получить. FireBird не помню, а Оракла так вообще шикарно все оптимизирует...
|