Старый 14.06.2013, 08:39   #1   
Registered User
 
Сообщений: 1,114
Регистрация: 23.06.2007
Возраст: 56

Hopkroft вне форума Не в сети
Post Нужен совет по коду(С++)

Народ, нужен совет.

Задача следующая.
Есть база данных, в которых храниться дерево.
Т.е. структура таблицы следующая

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 файла для наглядности
Миниатюры
Нажмите на изображение для увеличения
Название: то что было.JPG
Просмотров: 47
Размер:	16.6 Кб
ID:	2240549   Нажмите на изображение для увеличения
Название: то что нужно.JPG
Просмотров: 59
Размер:	7.4 Кб
ID:	2240550  

  Ответить с цитированием
Старый 20.06.2013, 10:10   #2   
Форумец
 
Аватар для MadFish
 
Сообщений: 340
Регистрация: 25.07.2002

MadFish вне форума Не в сети
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

Hopkroft вне форума Не в сети
MadFish, в принципе я говорил, с программером чей код дорабатываю. Он тоже солидарен, с тем что можно изменить стратегию хранения дерева.
Вы думаете в правильно направлении, т.к. скорее всего склоняетесь к этому методу Nested set model.
Проблема ещё в том, что много кода завязано, именно на хранении дерева со старой структурой, и мне не позволят тратить время на его переделку. Хотя я думаю сделать это как "домашнюю работу".
За алгоритм спасибо, попробую его доделать до рабочего состояния.
  Ответить с цитированием
Старый 20.06.2013, 13:54   #4   
Форумец
 
Аватар для MadFish
 
Сообщений: 340
Регистрация: 25.07.2002

MadFish вне форума Не в сети
Цитата:
Сообщение от Hopkroft Посмотреть сообщение
методу Nested set model
Точно!!! Спасибо. Пока писал, мучительно вспоминал как же правильно называется next child метод хранения дерева.
  Ответить с цитированием
Старый 20.06.2013, 14:22   #5   
Форумец
 
Аватар для Spectator
 
Сообщений: 39,872
Регистрация: 27.05.2003
Возраст: 46

Spectator вне форума Не в сети
Цитата:
Сообщение от Hopkroft Посмотреть сообщение
Вопрос:
1. Не будет ли лучшим решением, после загрузки дерева, вызывать
функцию которая скрывает пустые элементы?
2. И не слишком ли это говнокодерство, использовать каскадный вызов параметров по умолчанию?

P.S. в аттаче кинул 2 файла для наглядности
1. А что будет меняться чаще? содержимое дерева в базе, или желание скрыть пустые элементы?
2. Нет, совершенно штатная практика.
  Ответить с цитированием
Старый 20.06.2013, 14:30   #6   
Registered User
 
Сообщений: 1,114
Регистрация: 23.06.2007
Возраст: 56

Hopkroft вне форума Не в сети
Цитата:
Сообщение от Spectator Посмотреть сообщение
1. А что будет меняться чаще? содержимое дерева в базе, или желание скрыть пустые элементы?
2. Нет, совершенно штатная практика.
База будет своего рода справочники. Т.е. их заполнят один раз, и потом предполагается что меняться она будет редко.
Объясню, зачем понадобилось скрытие.
Программа это АРМ врача. А скрытие элементов нужно для того что-бы показывать только те материалы которые есть у врача в наличии.
Т.е. в идеале это будет типа, галочки, которая скрывает или показывает материалы.
А на данный момент, нужно что-бы просто отсутствующие элементы были скрыты. Но учитывая меняющиеся предпочтения нужно заложить маленькую возможность для реализации данной фичи.
  Ответить с цитированием
Старый 20.06.2013, 14:55   #7   
Кэп Улитка
 
Аватар для Yandex
 
Сообщений: 8,067
Регистрация: 04.05.2005
Возраст: 43

Yandex вне форума Не в сети
Hopkroft, может просто сделать материализованное представление/доп. таблицу, заложившись на некую максимальную глубину дерева, вида
Код:
Корень - Потомок - Потомок2 - ... -  Листовая вершина
?
Выборка по такой таблице, мне кажется, будет намного быстрее, чем каждый раз дерево собирать, да и код проще.
Правда, в случае, если дерево несбалансированное (подозреваю, что так оно и есть), то будет проблема с листьями.

Еще вариант.
Если DATA = количество, то в родительской вершине хранить сумму DATA дочерних.
  Ответить с цитированием
Старый 20.06.2013, 23:40   #8   
highly mean
 
Сообщений: 1,128
Регистрация: 26.05.2011
Возраст: 35

silly вне форума Не в сети
А кто-нибудь может пояснить, чем именно хорошо nested set для данной конкретной задачи? Необходимости быстро определять принадлежность узла к какой-то ветке я не вижу. Что-нибудь еще?

WHERE NOT (RIGHT - LEFT = 1 AND DATA = 0)?
  Ответить с цитированием
Старый 21.06.2013, 07:56   #9   
Форумец
 
Аватар для MadFish
 
Сообщений: 340
Регистрация: 25.07.2002

MadFish вне форума Не в сети
silly, рекурсия не нужна. Дерево можно выбрать простым селектом.
  Ответить с цитированием
Старый 21.06.2013, 10:16   #10   
highly mean
 
Сообщений: 1,128
Регистрация: 26.05.2011
Возраст: 35

silly вне форума Не в сети
Хм… Вот еще, фтыкание в гугл и википедию показывает, что альтернативным решением является использование рекурсивных CTE, то есть WITH RECURSIVE blah-blah SELECT blah. Которые (выражения), в свою очередь, реализованы в Firebird версий 2.1+. Что насчет этого подхода?
  Ответить с цитированием
Старый 21.06.2013, 11:54   #11   
Форумец
 
Аватар для MadFish
 
Сообщений: 340
Регистрация: 25.07.2002

MadFish вне форума Не в сети
silly, как вариант. я сразу говорил, что лучше всю выборку данных перенести на БД (хранимки, пакеты итп). У БД оптимизатор толще, больше удовольствия можно получить. FireBird не помню, а Оракла так вообще шикарно все оптимизирует...
  Ответить с цитированием
Старый 21.06.2013, 18:25   #12   
highly mean
 
Сообщений: 1,128
Регистрация: 26.05.2011
Возраст: 35

silly вне форума Не в сети
MadFish, понятно, спасибо.
  Ответить с цитированием
Старый 20.07.2013, 21:45   #13   
Registered User
 
Аватар для Спартак21
 
Сообщений: 402
Регистрация: 14.11.2007
Возраст: 37

Спартак21 вне форума Не в сети
...чего хочешь добиться:
1) красивая запись;
2) минимальный размер;
3) быстрое исполнение?
  Ответить с цитированием
Старый 21.07.2013, 14:01   #14   
Registered User
 
Сообщений: 1,114
Регистрация: 23.06.2007
Возраст: 56

Hopkroft вне форума Не в сети
Спартак21, ёлки-палки, да это всё в вопросе написано!
  Ответить с цитированием
Поиск в теме: 



Быстрый переход:

  Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Support by DrIQ & Netwind