Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Хитрое бинарное дерево...

Ответить
Настройки темы
C/C++ - Хитрое бинарное дерево...

Аватара для ManHack

Старожил


Сообщения: 361
Благодарности: 6

Профиль | Отправить PM | Цитировать


Здравствуйте!
Мне нужно построить двоичное дерево на Си.
В узлах дерева хранится ключ - массив из символов (строка) и данные - указатель однонаправленный список.
В узлах списка хранится ключ - массив из символов (строка) и данные - указатель на однонаправленный список №2 (ещё один).
В узлах списка №2 хранится число и... всё
На Паскале я такое деревце закодить могу, а на Сях запутался... TT____TT Помогите пожалуйста распутаться.
Всего-то деревце, к узлам которого привязаны списки, к узлам которых привязаны списки...
Интересуют именно особенности написания кода для такой задачи на Си.

Отправлено: 22:27, 05-05-2010

 

Аватара для ManHack

Старожил


Сообщения: 361
Благодарности: 6

Профиль | Отправить PM | Цитировать


Код: Выделить весь код
void AddToTree(struct tNode *ptr, char[] identName) {
    int cond;
    if (рtr == NULL) {  /* слово встречается впервые */
        ptr = talloc(); /* создается новый узел */
        ptr->name = strdup(identName);  /* заталкиваем строку */
        ... /* А вот здесь надо инициализировать новый список, привязанный к этой вершине и затолкнуть в него первый элемент. Как? */
        ptr->left = ptr->right = NULL; /* завершаем инициализацию новой вершины дерева путём установления указателей на её потомков в нули */
    } else if ((cond = strcmp(identName, ptr->name)) == 0)  /* это слово уже встречалось */
        ... /* Значит, для этой вершины уже есть список хотя бы с одним элементом => нужно затолкнуть в него ещё один */
    else if (cond < 0)        /* меньше корня левого поддерева */
        ptr->left = AddToTree(ptr->left, identName);
    else                      /* больше корня правого поддерева */
        ptr->right = AddToTree(ptr->right, identName);
    return ptr;
}
Помогите восполнить пробелы.
Хотя тут, наверно, можно ещё красивее написать, чем пугающие условия вида " if ((cond = strcmp(identName, ptr->name)) == 0) ", подскажите как..

Код: Выделить весь код
void TraverseTree(struct tnode *ptr) {
    if (ptr != NULL) {
        treeprint(ptr->left);
        // Печать: сначала identName, потом элемент из первого списка и все элементы из 2-го списка, которые к нему привязаны, потом ещё один из 1-го и все, которые из егонного 2-го и т.д.
        treeprint(ptr->right);
    }
}
Аналогичный вопрос.

Отправлено: 23:30, 05-05-2010 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Ветеран


Сообщения: 3320
Благодарности: 916

Профиль | Отправить PM | Цитировать


ManHack, например так
Код: Выделить весь код
if ((cond = strcmp(identName, ptr->name)) == 0) -> if (!(cond = strcmp(identName, ptr->name)))
if (ptr != NULL) -> if (ptr)
Это сообщение посчитали полезным следующие участники:

Отправлено: 01:23, 06-05-2010 | #3


Аватара для ManHack

Старожил


Сообщения: 361
Благодарности: 6

Профиль | Отправить PM | Цитировать


А когда и где проводить инициализацию списков? Они ведь разные для каждой вершины дерева.

Отправлено: 20:39, 06-05-2010 | #4

pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Если можно использовать стандартную библиотеку C++:
Код: Выделить весь код
#include <string>
#include <map>
using namespace std;

// если я правильно понял, должно быть так:
// поиск по дереву ключ=строка(уникальная) ->
//    список из пар <строка, список чисел> ->
//       добавляем, удаляем всякую фигню, но не делаем быстрого поиска

// список чисел
typedef vector<int> number_list_type;
// список пар строка-number_list_type
typedef list<pair<string, number_list_type> > number_w_key_list_type;
// дерево для поиска по ключу
typedef map<string, number_w_key_list_type> key_list_by_str_type;

// эта переменная содержит нужную структуру (по идее задача уже выполнена)
key_list_by_str_type key_list_by_str;

// как ей пользоваться?
// заполняем
static const char s1[] = "s1";
static const int i1[] = {1, 2, 3, 4};
static const char s2[] = "s2";
static const int i2[] = {5, 6};
static const char s3[] = "s3";
static const int i3[] = {7, 8, 9};
static const char s4[] = "s4";
static const int i4[] = {10};

void add_str(number_w_key_list_type& result, char const* str, int const* first, unsigned count)
{
	// добавляем пустой список, потом заполняем его доюавлением массива в конец
	copy(first, first+count, back_inserter<number_list_type>(
		*result.insert(result.end(), make_pair(string(s1), number_list_type())));
}

// это место можно очень хорошо свернуть в один цикл

add_str(key_list_by_str["key1"], s1, i1, sizeof(i1)/sizeof(i1[0]));
add_str(key_list_by_str["key1"], s2, i2, sizeof(i2)/sizeof(i2[0]));
add_str(key_list_by_str["key1"], s3, i3, sizeof(i3)/sizeof(i3[0]));
add_str(key_list_by_str["key2"], s4, i4, sizeof(i4)/sizeof(i4[0]));
key_list_by_str["key4"]; // пустой
теперь вопрос: какая физическая постановка задачи? мне эта структура кажется громоздкой и неудобной. Есть ещё куча замечательных шаблонов, например multimap, который позволяет хранить в сортированном дереве дубли. Поясни смысли задачи, может подскажу более удобную структуру. Если внутри тоже надо поиск по строке, то можно сделать map<string, multimap<string, int> > или map<string, map<string, vector<int> > >. В последнем случае работа с такой структурой напоминает работу с массивом
Код: Выделить весь код
map<string, map<string, vector<int> > > my_data;
my_data["outer key"]["inner key"].push_back(10);
единственное неудобство - это operator[] добавляет элемент, если такой не найден. А чтобы не добавлять, нужно делать сложнее:
Код: Выделить весь код
map<string, map<string, vector<int> > >::iterator found_outer;
map<string, vector<int> >::iterator found_inner;

if (my_data.end()!=(found_outer=my_data.find("outer key")) &&
	found_outer->second.end()!=(found_inner=found_outer->second.find("inner key")))
{
	// работа с найденным вектором
	// found_inner->second - это LVALUE vector<int>
	cout << "{";

	vector<int>::iterator
		out_first = found_inner->second.begin(),
		out_last  = found_inner->second.end();

	if (out_first!=out_last)
	{
		if (out_first!=--out_last) copy(out_first, out_last, ostream_iterator<char>(cout, ", "));
		cout << out_last;
	}

	cout << "}";

}
else
{
	cout << "- not found -";
}

cout << "\n";

Последний раз редактировалось pva, 08-05-2010 в 12:48. Причина: орфографические ошибки в коде


Отправлено: 12:44, 08-05-2010 | #5


Аватара для ManHack

Старожил


Сообщения: 361
Благодарности: 6

Профиль | Отправить PM | Цитировать


Библиотеки C++ использовать нельзя, даже стандартные. Пишется на чистом Си. Сишные библиотеки подключать можно (например так: #include <stdlib.h>) , но не более того.
Задача такова:
На вход программе подаётся входной поток из файлов (пользователь задаёт маску типа *.txt, по которой ищутся файлы в папке с программой с помощью FindFirst и FindNext).
В выходной файл он должна записать перечень идентификаторов из файлов входного потока в лексикографическом порядке (понятно, что в процессе чтения файлов создаётся структура [в человеческом смысле слова] хранения идентификаторов и только когда последний файл прочитан до конца эта структура выводится... ). Причём, к каждому идентификатору, записанному в выходной файл дописываются имена файлов, в которых он хранится (без повторений: если 2 одинаковых идент-ра в одном файле, то имя файла выводится единожды) и для каждого файла выводится список строк, в которых встречается данный идентификатор (с повторениями).
Под идентификатором понимаете любое слово не длиннее MAX_IDENT_LENGTH (условно, 31 символ) и состоящее из букв и цифр, начинающееся обязательно с буквы и не совпадающее с зарезервированными словами языка (не Си, другого ).
Если будет предложение получше, чем дерево со списками со списками, то буду очень признателен ^^"
Списки - потому, что ограничивать их длину (как делается в случае массива) считается неправомочным.

Отправлено: 18:33, 11-05-2010 | #6


Аватара для ManHack

Старожил


Сообщения: 361
Благодарности: 6

Профиль | Отправить PM | Цитировать


Написал так:

TREE.H:
Код: Выделить весь код
/* ’ҐЄгй*п Ї®§ЁжЁп ў Ёб室*®¬ ⥪б⥠(location.h) */
#ifndef TREE
#define TREE

#include "scan.h"

#define MAX_FILENAME_LENGTH 255
#define LIST_SIZE 10000

typedef char tKey[NAMELEN];
typedef char tFileName[MAX_FILENAME_LENGTH];
//typedef ListOfFiles tData;

struct tNode {
   tKey name;
   struct tListOfFilesItem* file[LIST_SIZE];
   //tData addresses;
   struct tNode* left;
   struct tNode* right;
   //constructor
   //tNode() {
   //   left = right = 0;
   //}
};

struct tListOfFilesItem {
	tFileName name;
	struct tListOfLinesItem* line;
	//struct tListOfLinesItem line[LIST_SIZE];
	//struct tListOfLinesItem line;
	//struct tListOfFilesItem* next;
}

struct tListOfFiles {
	struct tListOfFilesItem* first;
	struct tListOfFilesItem* last;
}

struct tListOfLinesItem {
	int line;
	//struct tListOfLinesItem* next;
}

struct tListOfLinesItem {
	struct tListOfLinesItem* first;
	struct tListOfLinesItem* last;
}*/

/* <---LIST---> */
/*
struct ListOfFiles {
	char fileName[MAX_FILENAME_LENGTH];
	struct ListOfLines* strings;
	struct ListOfFiles* next;
};

struct ListOfLines {
	int lineNumber;
	struct ListOfLines* next;
};

typedef struct list_el item;

void main() {
   item * curr, * head;
   int i;

   head = NULL;

   for(i=1;i<=10;i++) {
      curr = (item *)malloc(sizeof(item));
      curr->val = i;
      curr->next = head;
      head = curr;
   }

   curr = head;

   while(curr) {
      printf("%d\n", curr->val);
      curr = curr->next ;
   }
}
*/
/* <---/LIST---> */

/*void InitTree(void);
void AddToTree(void);
void TraverseTree(void);*/

//extern int Line;     /*Ќ®¬Ґа бва®ЄЁ          */
//extern int Pos;      /*Ќ®¬Ґа бЁ¬ў®«* ў бва®ЄҐ*/
//extern int LexPos;   /*Џ®§ЁжЁп **з*«* «ҐЄбҐ¬л*/
//extern char* Path;   /*Џгвм Є д*©«г          */

#endif
TREE.C:
Код: Выделить весь код
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "tree.h"

#define TRUE      1
#define FALSE     0

char ResetError = TRUE;
char* Message = "”*©« *Ґ ®вЄалв";
int Ch = chEOT;

static FILE *f;

void InitTree(struct tNode*) {
	struct tNode *root;
    root = NULL;
}

void InitFileList(struct tListOfFiles *FileList) {
	FileList->first = NULL;
	FileList->last = NULL;
}

void InitLineList(struct tListOfLines *LineList) {
	LineList->first = NULL;
	LineList->last = NULL;
}

//void PushLine(struct tListOfLinesItem) {
//
//}

//void PushFile(struct tListOfFilesItem) {
//
//}

void AddToLineList(struct tListOfFiles Queue, int Line) {
	struct tListOfLinesItem *ptr
	ptr = talloc(); 
	ptr->line = Line;
	ptr->next = NULL;
	if (Queue.first == NULL) {
		Queue.first = ptr; 
		Queue.last = ptr;
	} else {
		Queue.last.next = ptr;
		Queue.last = ptr;
	}
}

void AddToFileList(struct tListOfFiles Queue, char* Path, int Line) {
	struct tListOfFilesItem *ptr
	ptr = talloc(); 
	ptr->name = strdup(Path);
	ptr->next = NULL;
	if (Queue.first == NULL) {
		Queue.first = ptr; 
		Queue.last = ptr;
	} else {
		Queue.last.next = ptr;
		Queue.last = ptr;
	}
	
	/*int i = 0;
	while (file[i] != NULL && i <= LIST_SIZE) {
		i++;
	}
	FileList.file[i] = path;*/
}

void AddToTree(struct tNode *ptr, char[] identName) {
	int cond;
    if (рtr == NULL) {  /* слово встречается впервые */
        ptr = talloc(); /* создается новый узел, эквив. new(ptr) в Паскале */
        ptr->name = strdup(identName); /* ptr^.name := identName */
        //ptr->count = 1;
		//InitFileList(struct tListOfFilesItem *FileList);
		AddToFileList(Path, Line);
        ptr->left = ptr->right = NULL;
	} else if ((cond = strcmp(identName, ptr->name)) < 0) {
		AddToTree(ptr->left, identName);
	} else if ((cond = strcmp(identName, ptr->name)) < 0) {
		AddToTree(ptr->right, identName);
	}

	//} else if ((cond = strcmp(identName, ptr->name)) == 0) 
    //    ptr->count++;           /* это слово уже встречалось */
    //else if (cond < 0)        /* меньше корня левого поддерева */
    //    ptr->left = AddToTree(ptr->left, identName);
    //else                      /* больше корня правого поддерева */
    //    ptr->right = AddToTree(ptr->right, identName);
    
	return ptr;
}

/*void TraverseTree(struct tnode *ptr) {
    if (ptr != NULL) {
        treeprint(ptr->left);
        // Печать: идент - файлы - строки
		//printf("%4d %s\n", ptr->count, ptr->word);
        treeprint(ptr->right);
    }
}*/
Но возникают ошибкаи:
Цитата:
1>Compiling...
1>TREE.C
1>d:\obercompiler3\tree.h(34) : error C2236: unexpected 'struct' 'tListOfFiles'. Did you forget a ';'?
1>d:\obercompiler3\tree.h(34) : error C2059: syntax error : '{'
1>d:\obercompiler3\tree.h(44) : error C2011: 'tListOfLinesItem' : 'struct' type redefinition
1> d:\obercompiler3\tree.h(39) : see declaration of 'tListOfLinesItem'
1>Build log was saved at "file://d:\OberCompiler3\OberonCompiler\OberonCompiler\Debug\BuildLog.htm"
1>OberonCompiler - 3 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Вероятно, я запутался с Сишными ссылками.
Там вместо нормальных паскалевских птичек употребляются * и &, причёт * могут применяться как к типу, так и к переменной/константе (вроде) и при этом ставиться либо слева от её имени, либо справа (что должно быть немаловажно, а что значит, если * стоит слева? а справа в каких случаях ставится?)
Читал Кернигана-Ритчи, не распутался
Помогите пожалуйста.

Отправлено: 23:05, 12-05-2010 | #7


Аватара для ManHack

Старожил


Сообщения: 361
Благодарности: 6

Профиль | Отправить PM | Цитировать


Не понимаю ошибки:
Код: Выделить весь код
1>Linking...
1>SCAN.obj : error LNK2005: _tree already defined in O.obj
1>TREE.obj : error LNK2005: _tree already defined in O.obj
1>D:\OberCompiler3\OberonCompiler\Debug\OberonCompiler.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Build log was saved at "file://d:\OberCompiler3\OberonCompiler\OberonCompiler\Debug\BuildLog.htm"
1>OberonCompiler - 3 error(s), 8 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
В TREE.H:
Код: Выделить весь код
...
typedef struct tNode* TREE;
extern TREE tree = NULL;

struct tNode {
...
tree больше нигде не объявлен.
В SCAN.H и TREE.H, естественно, прописано #include.h
Как исправить и убрать эти дурацкие ошибки линковки?

Отправлено: 02:00, 14-05-2010 | #8

pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Цитата ManHack:
Как исправить и убрать эти дурацкие ошибки линковки? »
во всех *.h сделай extern TREE tree;
в одном из *.cpp сделай TREE tree=NULL;

Отправлено: 17:14, 15-05-2010 | #9



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Хитрое бинарное дерево...

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Интерфейс - Дерево папок с плюсиком leshiy_odessa Microsoft Windows 7 0 29-10-2009 21:15
Прочее - DIR-300 хитрое подключение YaroslavT Сетевое оборудование 8 24-10-2009 04:03
Дерево ссылок с неограниченным числом вложений rizz Вебмастеру 3 30-08-2009 09:42
Прописать бинарное значение в реестр buhanov Microsoft Windows NT/2000/2003 3 10-05-2007 10:14
дерево каталогов slaine Вебмастеру 8 26-02-2006 20:45




 
Переход