Консультация № 186030
15.05.2012, 14:44
83.51 руб.
21.05.2012, 00:50
0 37 1
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос:

Помогите, пожалуйста, написать программу, работающую с деревом, вариант задания номер 3:



Очень прошу помощи!

Заранее спасибо,

с уважением,
Иван.

PS Вопрос уже задавался

Обсуждение

Неизвестный
22.05.2012, 14:06
общий
22.05.2012, 14:32
Адресаты:
Вот вроде бы программа для двоичного дерева

[code h=200]#include <stdio.h>

typedef enum { red, green, blue, orange, yellow, indigo, violet, brown, white, black } node_t;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
struct TreeNode {
node_t info;
struct TreeNode* left;
struct TreeNode* right;
};

typedef struct TreeNode* tree_t;

tree_t create_tree(node_t info);

void print_info(tree_t root);
void print_node(tree_t root, int a_level);

int add_node(tree_t a_root, node_t info);

int delete_node(tree_t* a_ptree, node_t info);

//#include "tree.h"
#include <stdlib.h>

tree_t create_tree(node_t info) {
tree_t resuleft = malloc(sizeof(struct TreeNode));
resuleft->info = info;
resuleft->left = NULL;
resuleft->right = NULL;
return resuleft;
}

void print_enum(node_t a){
if(a == 0) printf("red");
if(a == 1) printf("green");
if(a == 2) printf("blue");
if(a == 3) printf("orange");
if(a == 4) printf("yellow");
if(a == 5) printf("indigo");
if(a == 6) printf("violet");
if(a == 7) printf("brown");
if(a == 8) printf("white");
if(a == 9) printf("black");
}

void print_info(tree_t root) {
if (root != NULL) {
printf("%d",root->info);
/**/
//print_enum(root->info);
if(!root->right && !root->left) printf("*");
printf("\n");
}
}

void print_node(tree_t root, int a_level) {
if (root != NULL) {
int i = 0;
print_node(root->right, a_level + 1);
for (; i < a_level; i++) {
printf("===");
}
print_info(root);
print_node(root->left, a_level + 1);
}
}

int add_node(tree_t a_root, node_t info) {
if (a_root == NULL) {
return -1;
}
if (a_root->info > info) {
if (a_root->left == NULL) {
a_root->left = create_tree(info);
return 1;
} else {
return add_node(a_root->left, info);
}
}
else if (a_root->info < info) {
if (a_root->right == NULL) {
a_root->right = create_tree(info);
return 1;
} else {
return add_node(a_root->right, info);
}
}
else if (a_root->info == info) {
return 1;
}
return 0;
}

int delete_node(tree_t* a_ptree, node_t info) {
if (a_ptree == NULL) {
return -1;
}
if (*a_ptree == NULL) {
return 0;
}
if ((*a_ptree)->info == info) {
/*Found the node to remove.*/
tree_t target = *a_ptree;
if (target->right == NULL) {
*a_ptree = target->left;
free(target);
return 1;
}
if (target->left == NULL) {
*a_ptree = target->right;
free(target);
return 1;
}
tree_t replacer_parent = target->left;
tree_t replacer = target->left->right;
if (replacer == NULL) {
*a_ptree = replacer_parent;
replacer_parent->right = target->right;
free(target);
return 1;
} else {
while (replacer->right != NULL) {
replacer_parent = replacer;
replacer = replacer_parent->right;
}
replacer_parent->right = replacer->left;
replacer->left = target->left;
replacer->right = target->right;
*a_ptree = replacer;
free(target);
return 1;
}
}
if ((*a_ptree)->info < info) {
/*Delete node in right subtree*/
return delete_node(&((*a_ptree)->right), info);
}
if ((*a_ptree)->info > info) {
/*Delete node in left subtree*/
return delete_node(&((*a_ptree)->left), info);
}
return -1;
}

int min_l=0;
node_t min_v=red;

void find(tree_t root, int level)
{
if(!root) return;

find(root->left, level + 1);
find(root->right, level + 1);
if(!root->left && !root->right && (min_l==0 || min_l>level)){
min_l=level;
min_v=root->info;
}
}

int main(){
tree_t T;
int mode=0, color;
T = create_tree(indigo);


add_node(T, white);
add_node(T, violet);
add_node(T, brown);

add_node(T, black);
add_node(T, yellow);
add_node(T, orange);
add_node(T, blue);



while(mode!=4){
printf("Tree:\n");
print_node(T, 0);
printf("\nMode:\n0 - create tree\n1 - add node\n2 - delete node\n3 - min height leaf\n4 - exit\n\nColor:\n0 red, 1 green, 2 blue, 3 orange, 4 yellow, 5 indigo, 6 violet, 7 brown, 8 white, 9 black\n\nEnter <mode> <color>\n");
scanf("%d",&mode);
if(mode != 3 && mode != 4) scanf("%d",&color);
if(color > 9 || color < 0) {printf("ERROR COLOR"); exit;}
if(mode==0) T=create_tree(color);
if(mode==1) add_node(T, color);
if(mode==2) delete_node(&T, color);
if(mode==3) {
min_l=0;
min_v=red;
find(T,1);
printf("Min leaf: ");
print_enum(min_v);
printf("\n");
}
}
exit;
}[/code]
давно
Посетитель
7438
7205
22.05.2012, 14:31
общий
Если ограничимся десятью цветами, этого хватит?
Если да, то сейчас подправлю... Думаю, через, примерно, часик будет готово...
Плюс комментарии написать...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
22.05.2012, 17:37
общий
это ответ
Здравствуйте, Барс Иван!
Вот, что у меня получилось.
Комментариев достаточно, думаю, разберетесь...
[codeh=200]#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>

//первый элемент nocolor нужен для поиска родителя-корня
typedef enum { nocolor, red, green, blue, orange, yellow, indigo, violet, brown, white, black } node_t;

struct Node
{
node_t Color; //цвет
Node *Son; //указатель на первого сына
Node *Brother; //указатель на слеующего брата
};

Node * Root = NULL; //корень дерева

void AddElement();
void DelElement();
void OutTree();
void CalcMinDepth();
void Exit();
int GetNum();
node_t GetColor(bool);

//преобразование enum в строку
char* GetColorString(node_t color)
{
switch (color)
{
case nocolor:
return "корень или братья корня";
case red:
return "красный";
case green:
return "зеленый";
case blue:
return "голубой";
case orange:
return "оранжевый";
case yellow:
return "желтый";
case indigo:
return "индиго";
case violet:
return "фиолетовый";
case brown:
return "коричневый";
case white:
return "белый";
case black:
return "черный";
default:
return "неизвестный"; //на всякий случай
}
}

char *mesMain[] = //сообщения меню
{
"Включить новый элемент",
"Удалить элемент",
"Вывести дерево",
"Найти лист с минимальной глубиной",
"Выход"
};

//количество пунктов меню
int MesMainCount = sizeof( mesMain ) / sizeof( mesMain[0] );

//функции отработки пунктов меню
void ( *funcMain[] )() = {AddElement, DelElement, OutTree, CalcMinDepth, Exit};


//создание нового узла, возвращает указатель на этот элемент
Node* CreateNode(node_t Color)
{
Node * node = (Node*)malloc(sizeof(Node));
node->Color = Color; //цвет
node->Son = NULL; //без детей
node->Brother = NULL; //и брата нет
return node;
}

//рекурентный поиск узла с аданным цветом
//Current - первый в списке братьев
//Color - искомый цвет
//pParent - адрес указателя на родителя, в начале должен быть NULL
// используется при удалении узла
//pBrother- арес указателя на предыдущего брата, там в начале должен быть NULL
// используется при удалении узла
Node* Find(Node* Current, node_t Color, Node** pParent, Node** pBrother)
{
Node *node, *nodeSon;
//сначала сравним поле для братьев, начиная с заданного
for (node=Current; node; node=node->Brother)
{
//сравниваем цвет
if (node->Color == Color)
{
return node; //нашли, вернем указатель на узел
}
*pParent = NULL; //NULL для всех последующих братьев
*pBrother = node; //сохраним указатель на предыдущего брата
}
//идем на седующий уровень - по сыновьям всех братьев
for (node=Current; node; node=node->Brother)
{
//зададим родителя для первого сына
*pParent = node;
//ищем среди всех потомков текущего брата
if (NULL != (nodeSon=Find(node->Son, Color, pParent, pBrother)))
//если наши, то возвращаем выше указатель на узел
return nodeSon;
}
return NULL; //не найдено
}

//поиск последнего в списке братьев
Node* Last(Node * node)
{
for (; node->Brother; node=node->Brother);
return node;
}

//добавение узла с указанием цвета родителя(или 0 для корня и его братьев) и вставяемого узла
int AddNode (node_t ColorParent, node_t Color)
{
Node *node, *nodeLast, *nodeNew;
Node *Parent = NULL;
Node *Brother = NULL;
//что-то есть вообще?
if (Root == NULL) //корня еще пока нет
{
if (ColorParent == nocolor) //проверим правильность задания цвета родителя! Для корня 0!
{
Root = CreateNode(Color);//создаем корень
return 1; //внесли
}
else
return 2; //неправильные данные - родитель не найден!
}
else if (ColorParent == nocolor) //родитель - 0 уровень, т.е. братья корня?
{
if (NULL == Find(Root, Color, &Parent, &Brother)) //есть ли уже узел с цветом color?
{
nodeNew = CreateNode(Color); //создаем узел
nodeLast = Last(Root); //ищем последнего брата
nodeLast->Brother = nodeNew; //добавляем нового в цепочку братьев
return 1; //внесли
}
else
return 0; //дубликат цвета
} //родитель - не корень
//ищем родителя
else if (NULL != (node = Find(Root, ColorParent, &Parent, &Brother)))
{
//есть ли уже узел с цветом color?
Parent = NULL; //начинаем искать с начала
Brother = NULL;
if (NULL == Find(Root, Color, &Parent, &Brother))
{ //цвет не найден
//добавяем
nodeNew = CreateNode(Color); //создаем узел
if (NULL == node->Son) //у родителя уже есть дети?
node->Son = nodeNew; //нет - будем первым сыном
else
{ //есть - будем младшим сыном
nodeLast = Last(node->Son); //ищем самого последнего
nodeLast->Brother = nodeNew;//и добавляем новый элемент в конец цепочки братьев
}
return 1; //внесли
}
else
return 0; //дубликат цвета
}
else
return 2; //родитель не найден!
}

//рекурентное удаление узла вместе со всеми потомками
void DeleteAllSons(Node *nodeParent)
{
Node *node,*nodeBrother;
//по всем сыновьям
for(node=nodeParent->Son; node; node=nodeBrother)
{
//запомним следуюещго брата
nodeBrother = node->Brother;
//удаляем текущего сына со всего его потомками
DeleteAllSons(node);
}
//удаляем сам узел
free (nodeParent);
}

//удаление узла с заанным цветом
bool DelNode(node_t Color)
{
Node *node, *nodeBrother;
Node *Parent = NULL;
Node *Brother = NULL;

//ищем узел
if (NULL != (node=Find(Root, Color, &Parent, &Brother)))
{ //нашли!
nodeBrother = node->Brother;//запомним следующего брата

DeleteAllSons(node); //удаляем узел со всеми потомками

//подправим ссылку
if (node == Root) //узел - корень?
Root = nodeBrother; //корнем будет следующий брат
else if (Parent != NULL) //узел - первый из братьев?
Parent->Son = nodeBrother; //делаем первым сыном брата
else
Brother->Brother = nodeBrother; //сеующий брат будет идти за предыдущим брат
return true; //уалили
}
else
return false; //узел не найден
}

//удаение всего дерева (в конце)
void DelAll(void)
{
while(Root)
DelNode(Root->Color); //удаяем всех братьев корня
}

//рекурентный структуированный вывод дерева, начиная с узла node
//уровень узла задается параметром level
void PrintTree(Node* node, int level)
{
char str[80]; //для формирования первых пробелов
int i;

for (; node; node=node->Brother) //по братьям
{
for (i=0; i<level; i++) //сформируем level пробелов
str[i] = ' '; //можно по-разному, я сделал "в лоб"
str[i] = 0; //закрываем строку нулем
//выводим цвет с пробелами
printf("%s%s\n", str, GetColorString(node->Color));
PrintTree(node->Son, level+2); //выводим потомков, на каждый уровень по 2 пробела
}
}

//рекурентный поиск узла с минимальной глубиной
//nodeParent - началный узел
//iDepth - глубина до текущего уровня (в начале 0)
//piDepthMin - адрес переменной - минимальной глубины
//nodeMin - адрес указателя на узел с минимальной глубиной
void SearchLeafs(Node *nodeParent, int iDepth, int *piDepthMin, Node **nodeMin)
{
Node *node;

//если NULL, то начинаем с корня, иначе с первого сына
node = (nodeParent == NULL) ? Root : nodeParent->Son;

iDepth++; //глубина текущего уровня
for (; node; node=node->Brother) //по братьям
{
if (node->Son == NULL) //узел - лист (без сыновей)?
{ //в начале просто сохраняем первого
//для всех остальных - ищем минимального
if ((*piDepthMin == NULL)||(*piDepthMin > iDepth))
{
*piDepthMin = iDepth; //сохраняем глубину
*nodeMin = node; //и узел
}
}
else //имеет потомков - задаем поиск по потомкам
SearchLeafs(node, iDepth, piDepthMin, nodeMin);
}
}

//добавить элемент
void AddElement()
{
node_t parent, Color;
printf("Введите цвет родителя\n");
parent = GetColor(true); //вводим цвет родителя, с возможностью ввода корня
printf("Введите цвет элемента\n");
Color = GetColor(false); //вводим цвет нового элемента

switch (AddNode(parent, Color)) //пытаемся добавить
{
case 1:
printf("Элемент добавлен\n");
break;
case 0:
printf("Элемент c данным цветом уже есть\n");
break;
case 2:
printf("Родитель не найден\n");
}
}

//удалить элемент
void DelElement()
{
node_t Color;
printf("Введите цвет элемента\n");
Color = GetColor(false); //вводим цвет

if (DelNode(Color)) //пытаемся удалить
printf("Элемент удален\n");
else
printf("Элемент c данным цветом не найден\n");
}

//вывод дерева
void OutTree()
{
PrintTree(Root, 0); //начинаем с корня и уровня 0
}

//поиск узла с минималной глубиной
void CalcMinDepth()
{
int iDepthMin = 0;
Node *nodeMin = NULL;

SearchLeafs(NULL, 0, &iDepthMin, &nodeMin); //ищем
if (iDepthMin)
printf("Минимальная глубина = %d, Цвет = %s\n", iDepthMin, GetColorString(nodeMin->Color));
else
printf("Дерево пустое\n");
}

void Exit() //выход
{
DelAll(); //освобождаем память
}

bool IsNum(char *str) //проверка строки на число
{
for(;isdigit(*str);str++);
return (*str == 0);
}
//ввод числа
int GetNum()
{
char str[80];

while(1)
{
gets(str); //введем строку
if (IsNum(str)) //проверим на корректность
return(atoi(str)); //возвращаем число
printf("Введите число!\n");
}
//сюда не попадем, но
return -1; //подпрограмма должна что-то возвращать
}
//ввод цвета с отображением всех цветов
//Parent = true для выбора родителя - корня
node_t GetColor(bool Parent)
{
node_t iColor;

while(1)
{
//выведем цведа в две строки для выбора
for(iColor=red; iColor<yellow; iColor=(node_t)((int)iColor+1))
printf("%d.%s,\t", iColor, GetColorString(iColor));
printf("%d.%s\n", iColor, GetColorString(iColor));

for(iColor=indigo; iColor<black; iColor=(node_t)((int)iColor+1))
printf("%d.%s,\t", iColor, GetColorString(iColor));
printf("%d.%s\n", iColor, GetColorString(iColor));
//выбор корня нужен?
if (Parent)
printf("%d.%s\n", nocolor, GetColorString(nocolor));
printf("Ваш выбор: ");

iColor = (node_t)GetNum();
if (Parent)
{
if ((iColor >= nocolor) || (iColor <= black))
return(iColor);
}
else if((iColor >= red) || (iColor <= black))
return(iColor);
else
printf("Введите число из диапозона!\n");
}
return nocolor; //сюда не попадем никогда
}
//показ меню с вводом номера строки
int ViewMenu(char** mes, int max)
{
int ret;
do
{
//меню
for ( int i = 0; i < max; i++ )
printf("%d. %s\n", i+1, mes[i]);
printf("Ваш выбор: ");
//вводим число
ret = GetNum();
}
//проверим на допустимость
while ( ret < 1 || ret > max );
//вернем номер строки
return ret;
}

int main()
{
int ret;
//чтобы писалось по-русски
system("chcp 1251 >> nul");

do
{
ret = ViewMenu(mesMain, MesMainCount); //выводим меню, вводим номер строки
funcMain[ret-1](); //отрабатываем пункт меню
printf("--------------------------------\n");
if (ret == MesMainCount) //последняя - выход
break;
}while ( ret );

return 0;
}[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
22.05.2012, 21:40
общий
Адресаты:
А чтобы программа скомпилировалась, нужна еще библиотека?
давно
Посетитель
7438
7205
23.05.2012, 00:11
общий
Да нет, все стандартно...
Какая среда? Что говорит?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
23.05.2012, 16:54
общий
Адресаты:
Говорит, что не объявлена куча функций.. Сейчас скопирую
Неизвестный
23.05.2012, 16:58
общий
Адресаты:
23.c:11:5: error: expected specifier-qualifier-list before ‘Node’
23.c:14:10: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token
23.c:21:5: warning: parameter names (without types) in function declaration
23.c:66:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token
23.c:81:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token
23.c:108:9: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token
23.c: In function ‘AddNode’:
23.c:116:5: error: ‘Node’ undeclared (first use in this function)
23.c:116:5: note: each undeclared identifier is reported only once for each function it appears in
23.c:116:11: error: ‘node’ undeclared (first use in this function)
23.c:116:18: error: ‘nodeLast’ undeclared (first use in this function)
23.c:116:29: error: ‘nodeNew’ undeclared (first use in this function)
23.c:117:11: error: ‘Parent’ undeclared (first use in this function)
23.c:118:11: error: ‘Brother’ undeclared (first use in this function)
23.c:120:9: error: ‘Root’ undeclared (first use in this function)
23.c: At top level:
23.c:168:29: error: expected ‘)’ before ‘*’ token
23.c:183:10: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘DelNode’
23.c: In function ‘DelAll’:
23.c:208:11: error: ‘Root’ undeclared (first use in this function)
23.c: At top level:
23.c:213:24: error: expected ‘)’ before ‘*’ token
23.c:232:27: error: expected ‘)’ before ‘*’ token
23.c: In function ‘AddElement’:
23.c:258:23: error: ‘true’ undeclared (first use in this function)
23.c:260:22: error: ‘false’ undeclared (first use in this function)
23.c: In function ‘DelElement’:
23.c:278:22: error: ‘false’ undeclared (first use in this function)
23.c: In function ‘OutTree’:
23.c:287:15: error: ‘Root’ undeclared (first use in this function)
23.c: In function ‘CalcMinDepth’:
23.c:293:5: error: ‘Node’ undeclared (first use in this function)
23.c:293:11: error: ‘nodeMin’ undeclared (first use in this function)
23.c: At top level:
23.c:304:10: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘IsNum’
23.c:325:26: error: expected ‘)’ before ‘Parent’
23.c: In function ‘ViewMenu’:
23.c:361:5: error: ‘for’ loop initial declarations are only allowed in C99 mode
23.c:361:5: note: use option -std=c99 or -std=gnu99 to compile your code
ivan@ubuntu:~$
давно
Посетитель
7438
7205
23.05.2012, 17:07
общий
Среда-то какая? Вижу, что под Ubuntu...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
23.05.2012, 18:02
общий
Адресаты:
emacs + GNU - Вы про это?
давно
Посетитель
7438
7205
23.05.2012, 18:17
общий
24.05.2012, 02:03
К сожалению, я под Линуксом не сижу, проверить не смогу. В условии уточнять надо... Программа писалась под Windows.
Но я попрошу некоторых экспертов глянуть...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
23.05.2012, 18:21
общий
Адресаты:
Хорошо! Премного Вам благодарен!
давно
Посетитель
7438
7205
24.05.2012, 00:25
общий
Адресаты:
Коллеги, подскажите, пожалуйста, что надо подправить, чтобы программа заработала в среде emacs + GNU?
Я только вижу, что system ("chcp... лишнее
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2012, 01:15
общий
Адресаты:
Я так понял надо на C, а не C++:
Код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>
#include <stdbool.h>
//первый элемент nocolor нужен для поиска родителя-корня

enum node_t{
nocolor, red, green, blue, orange, yellow, indigo, violet, brown, white, black
} ;

struct Node {
enum node_t Color; //цвет
struct Node *Son; //указатель на первого сына
struct Node *Brother; //указатель на слеующего брата
};
struct Node * Root = NULL; //корень дерева
void AddElement();
void DelElement();
void OutTree();
void CalcMinDepth();
void Exit();
int GetNum();
enum node_t GetColor(bool);
//преобразование enum в строку

char* GetColorString(enum node_t color) {
switch (color) {
case nocolor:
return "корень или братья корня";
case red:
return "красный";
case green:
return "зеленый";
case blue:
return "голубой";
case orange:
return "оранжевый";
case yellow:
return "желтый";
case indigo:
return "индиго";
case violet:
return "фиолетовый";
case brown:
return "коричневый";
case white:
return "белый";
case black:
return "черный";
default:
return "неизвестный"; //на всякий случай
}
}
char *mesMain[] = //сообщения меню
{
"Включить новый элемент",
"Удалить элемент",
"Вывести дерево",
"Найти лист с минимальной глубиной",
"Выход"
};
//количество пунктов меню
int MesMainCount = sizeof ( mesMain) / sizeof ( mesMain[0]);
//функции отработки пунктов меню
void ( *funcMain[])() = {AddElement, DelElement, OutTree, CalcMinDepth, Exit};
//создание нового узла, возвращает указатель на этот элемент

struct Node* CreateNode(enum node_t Color) {
struct Node * node = (struct Node*) malloc(sizeof (struct Node));
node->Color = Color; //цвет
node->Son = NULL; //без детей
node->Brother = NULL; //и брата нет
return node;
}
//рекурентный поиск узла с аданным цветом
//Current - первый в списке братьев
//Color - искомый цвет
//pParent - адрес указателя на родителя, в начале должен быть NULL
// используется при удалении узла
//pBrother- арес указателя на предыдущего брата, там в начале должен быть NULL
// используется при удалении узла

struct Node* Find(struct Node* Current, enum node_t Color, struct Node** pParent, struct Node** pBrother) {
struct Node *node, *nodeSon;
//сначала сравним поле для братьев, начиная с заданного
for (node = Current; node; node = node->Brother) {
//сравниваем цвет
if (node->Color == Color) {
return node; //нашли, вернем указатель на узел
}
*pParent = NULL; //NULL для всех последующих братьев
*pBrother = node; //сохраним указатель на предыдущего брата
}
//идем на седующий уровень - по сыновьям всех братьев
for (node = Current; node; node = node->Brother) {
//зададим родителя для первого сына
*pParent = node;
//ищем среди всех потомков текущего брата
if (NULL != (nodeSon = Find(node->Son, Color, pParent, pBrother)))
//если наши, то возвращаем выше указатель на узел
return nodeSon;
}
return NULL; //не найдено
}
//поиск последнего в списке братьев

struct Node* Last(struct Node * node) {
for (; node->Brother; node = node->Brother);
return node;
}
//добавение узла с указанием цвета родителя(или 0 для корня и его братьев) и вставяемого узла

int AddNode(enum node_t ColorParent,enum node_t Color) {
struct Node *node, *nodeLast, *nodeNew;
struct Node *Parent = NULL;
struct Node *Brother = NULL;
//что-то есть вообще?
if (Root == NULL) //корня еще пока нет
{
if (ColorParent == nocolor) //проверим правильность задания цвета родителя! Для корня 0!
{
Root = CreateNode(Color); //создаем корень
return 1; //внесли
} else
return 2; //неправильные данные - родитель не найден!
} else if (ColorParent == nocolor) //родитель - 0 уровень, т.е. братья корня?
{
if (NULL == Find(Root, Color, &Parent, &Brother)) //есть ли уже узел с цветом color?
{
nodeNew = CreateNode(Color); //создаем узел
nodeLast = Last(Root); //ищем последнего брата
nodeLast->Brother = nodeNew; //добавляем нового в цепочку братьев
return 1; //внесли
} else
return 0; //дубликат цвета
}//родитель - не корень
//ищем родителя
else if (NULL != (node = Find(Root, ColorParent, &Parent, &Brother))) {
//есть ли уже узел с цветом color?
Parent = NULL; //начинаем искать с начала
Brother = NULL;
if (NULL == Find(Root, Color, &Parent, &Brother)) { //цвет не найден
//добавяем
nodeNew = CreateNode(Color); //создаем узел
if (NULL == node->Son) //у родителя уже есть дети?
node->Son = nodeNew; //нет - будем первым сыном
else { //есть - будем младшим сыном
nodeLast = Last(node->Son); //ищем самого последнего
nodeLast->Brother = nodeNew; //и добавляем новый элемент в конец цепочки братьев
}
return 1; //внесли
} else
return 0; //дубликат цвета
} else
return 2; //родитель не найден!
}
//рекурентное удаление узла вместе со всеми потомками

void DeleteAllSons(struct Node *nodeParent) {
struct Node *node, *nodeBrother;
//по всем сыновьям
for (node = nodeParent->Son; node; node = nodeBrother) {
//запомним следуюещго брата
nodeBrother = node->Brother;
//удаляем текущего сына со всего его потомками
DeleteAllSons(node);
}
//удаляем сам узел
free(nodeParent);
}
//удаление узла с заанным цветом

bool DelNode(enum node_t Color) {
struct Node *node, *nodeBrother;
struct Node *Parent = NULL;
struct Node *Brother = NULL;
//ищем узел
if (NULL != (node = Find(Root, Color, &Parent, &Brother))) { //нашли!
nodeBrother = node->Brother; //запомним следующего брата
DeleteAllSons(node); //удаляем узел со всеми потомками
//подправим ссылку
if (node == Root) //узел - корень?
Root = nodeBrother; //корнем будет следующий брат
else if (Parent != NULL) //узел - первый из братьев?
Parent->Son = nodeBrother; //делаем первым сыном брата
else
Brother->Brother = nodeBrother; //сеующий брат будет идти за предыдущим брат
return true; //уалили
} else
return false; //узел не найден
}
//удаение всего дерева (в конце)

void DelAll(void) {
while (Root)
DelNode(Root->Color); //удаяем всех братьев корня
}
//рекурентный структуированный вывод дерева, начиная с узла node
//уровень узла задается параметром level

void PrintTree(struct Node* node, int level) {
char str[80]; //для формирования первых пробелов
int i;
for (; node; node = node->Brother) //по братьям
{
for (i = 0; i < level; i++) //сформируем level пробелов
str[i] = ' '; //можно по-разному, я сделал "в лоб"
str[i] = 0; //закрываем строку нулем
//выводим цвет с пробелами
printf("%s%s\n", str, GetColorString(node->Color));
PrintTree(node->Son, level + 2); //выводим потомков, на каждый уровень по 2 пробела
}
}
//рекурентный поиск узла с минимальной глубиной
//nodeParent - началный узел
//iDepth - глубина до текущего уровня (в начале 0)
//piDepthMin - адрес переменной - минимальной глубины
//nodeMin - адрес указателя на узел с минимальной глубиной

void SearchLeafs(struct Node *nodeParent, int iDepth, int *piDepthMin, struct Node **nodeMin) {
struct Node *node;
//если NULL, то начинаем с корня, иначе с первого сына
node = (nodeParent == NULL) ? Root : nodeParent->Son;
iDepth++; //глубина текущего уровня
for (; node; node = node->Brother) //по братьям
{
if (node->Son == NULL) //узел - лист (без сыновей)?
{ //в начале просто сохраняем первого
//для всех остальных - ищем минимального
if ((*piDepthMin == NULL) || (*piDepthMin > iDepth)) {
*piDepthMin = iDepth; //сохраняем глубину
*nodeMin = node; //и узел
}
} else //имеет потомков - задаем поиск по потомкам
SearchLeafs(node, iDepth, piDepthMin, nodeMin);
}
}
//добавить элемент

void AddElement() {
enum node_t parent, Color;
printf("Введите цвет родителя\n");
parent = GetColor(true); //вводим цвет родителя, с возможностью ввода корня
printf("Введите цвет элемента\n");
Color = GetColor(false); //вводим цвет нового элемента
switch (AddNode(parent, Color)) //пытаемся добавить
{
case 1:
printf("Элемент добавлен\n");
break;
case 0:
printf("Элемент c данным цветом уже есть\n");
break;
case 2:
printf("Родитель не найден\n");
}
}
//удалить элемент

void DelElement() {
enum node_t Color;
printf("Введите цвет элемента\n");
Color = GetColor(false); //вводим цвет
if (DelNode(Color)) //пытаемся удалить
printf("Элемент удален\n");
else
printf("Элемент c данным цветом не найден\n");
}
//вывод дерева

void OutTree() {
PrintTree(Root, 0); //начинаем с корня и уровня 0
}
//поиск узла с минималной глубиной

void CalcMinDepth() {
int iDepthMin = 0;
struct Node *nodeMin = NULL;
SearchLeafs(NULL, 0, &iDepthMin, &nodeMin); //ищем
if (iDepthMin)
printf("Минимальная глубина = %d, Цвет = %s\n", iDepthMin, GetColorString(nodeMin->Color));
else
printf("Дерево пустое\n");
}

void Exit() //выход
{
DelAll(); //освобождаем память
}

bool IsNum(char *str) //проверка строки на число
{
for (; isdigit(*str); str++);
return (*str == 0);
}
//ввод числа

int GetNum() {
char str[80];
while (1) {
gets(str); //введем строку
if (IsNum(str)) //проверим на корректность
return (atoi(str)); //возвращаем число
printf("Введите число!\n");
}
//сюда не попадем, но
return -1; //подпрограмма должна что-то возвращать
}
//ввод цвета с отображением всех цветов
//Parent = true для выбора родителя - корня

enum node_t GetColor(bool Parent) {
enum node_t iColor;
while (1) {
//выведем цведа в две строки для выбора
for (iColor = red; iColor < yellow; iColor = (enum node_t) ((int) iColor + 1))
printf("%d.%s,\t", iColor, GetColorString(iColor));
printf("%d.%s\n", iColor, GetColorString(iColor));
for (iColor = indigo; iColor < black; iColor = (enum node_t) ((int) iColor + 1))
printf("%d.%s,\t", iColor, GetColorString(iColor));
printf("%d.%s\n", iColor, GetColorString(iColor));
//выбор корня нужен?
if (Parent)
printf("%d.%s\n", nocolor, GetColorString(nocolor));
printf("Ваш выбор: ");
iColor = (enum node_t) GetNum();
if (Parent) {
if ((iColor >= nocolor) || (iColor <= black))
return (iColor);
} else if ((iColor >= red) || (iColor <= black))
return (iColor);
else
printf("Введите число из диапозона!\n");
}
return nocolor; //сюда не попадем никогда
}
//показ меню с вводом номера строки

int ViewMenu(char** mes, int max) {
int ret,i;
do {
//меню
for (i = 0; i < max; i++)
printf("%d. %s\n", i + 1, mes[i]);
printf("Ваш выбор: ");
//вводим число
ret = GetNum();
}//проверим на допустимость
while (ret < 1 || ret > max);
//вернем номер строки
return ret;
}

int main() {
int ret;
//чтобы писалось по-русски
system("chcp 1251 >> nul");
do {
ret = ViewMenu(mesMain, MesMainCount); //выводим меню, вводим номер строки
funcMain[ret - 1](); //отрабатываем пункт меню
printf("--------------------------------\n");
if (ret == MesMainCount) //последняя - выход
break;
} while (ret);
return 0;
}

Правда есть нехорошее предупреждение:
Код:

main.c: В функции ‘SearchLeafs’:
main.c:232:30: предупреждение: сравнение указателя и целого

build/Debug/GNU-Linux-x86/main.o: In function `GetNum':
main.c:303: warning: the `gets' function is dangerous and should not be used.

ПОСТРОИТЬ SUCCESSFUL (общее время: 163мс)

давно
Посетитель
7438
7205
24.05.2012, 01:55
общий
24.05.2012, 02:00
Спасибо
С первым понятно, надо заменить *piDepthMin == NULL на *piDepthMin == 0
А как подправить второе? Если не нравится gets, чем можно заменить?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Старший Модератор
17042
808
24.05.2012, 07:10
общий
Адресаты:
Читаем man gets:

Цитата: gets(3)

C89, C99, POSIX.1-2001. LSB deprecates gets(). POSIX.1-2008 marks gets() obsolescent.
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.


Т.е. вместо gets рекомендуется fgets.
Об авторе:
We have but faith: we cannot know;
For knowledge is of things we see;
And yet we trust it comes from thee,
A beam in darkness: let it grow.
-----
https://www.linkedin.com/in/andreynkuznetsov
https://www.researchgate.net/profile/Andrey_Kuznetsov11
http://www.researcherid.com/rid/K-8824-2014
давно
Посетитель
7438
7205
24.05.2012, 11:27
общий
Адресаты:
Спасибо
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
24.05.2012, 11:28
общий
Общими усилиями программу подправили.
Пробуйте
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2012, 14:23
общий
Уважаемые эксперты! Все отлично функционирует и работает! Огромное человеческое спасибище!
Единственное - можно, пожалуйста, не закрывать мини-форум, на случай появления вопросов? Или он и так всегда открыт?
давно
Посетитель
7438
7205
24.05.2012, 14:32
общий
Он всегда открыт, заходите, если что...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
27.05.2012, 18:13
общий
Объясните, пожалуйста, суть вот этой строки(чуть подробнее) : int MesMainCount = sizeof ( mesMain) / sizeof ( mesMain[0]);
И еще вопрос : Что делает операция "**"?То же, что и обычное разыменование "*"?

Заранее спасибо!
Неизвестный
27.05.2012, 23:48
общий
И вот еще вот эта строчка непонятна : node = (nodeParent == NULL) ? Root : nodeParent->Son;
давно
Посетитель
7438
7205
27.05.2012, 23:58
общий
28.05.2012, 00:23
Зачем кидать вопрос всем экспертам?
Спросите меня, я отвечу.
1) Итак, int MesMainCount = sizeof ( mesMain) / sizeof ( mesMain[0])
mesMain - массив ссылок на строки, каждый элемент - слово (4 байта)
sizeof ( mesMain) - размер всего массива в байтах (число элементов * 4)
sizeof ( mesMain[0]) - размер одного элемента массива в байтах, т.е. 4
В итоге, sizeof ( mesMain) / sizeof ( mesMain[0]) - число элементов в массиве mesMain
2) Допустим, есть такие объекты:
int i;
int *pi;
int **ppi;
i - целое
pi - будет указателем на целое, можно написать *pi = i, pi = &i, *pi = 2 (i = 2)
ppi - адрес указателя на целое, т.е. можно писать *ppi = pi, ppi = &pi, *(*ppi) = 2 (получим i=2)
Т.о., можно сказать, что *(*ppi) дает нам двойное разыменовывание

Удобно использовать, когда надо из подпрограммы вернуть адрес чего-то.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
27.05.2012, 23:59
общий
28.05.2012, 00:34
node = (nodeParent == NULL) ? Root : nodeParent->Son;
Это более короткая запись следующего выражения:
if (nodeParent == NULL)
node = Root;
else
node = nodeParent->Son;
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
28.05.2012, 00:23
общий
Адресаты:
Спасибо, все понял!
Последний вопрос - символ "->" является символом обращения к какому-либо элементу структуры?
давно
Посетитель
7438
7205
28.05.2012, 00:30
общий
Да. Если у нас есть указатель на структуру, то -> дает нам обращение элементу структуры, адресуемой этим указателем.
Если же у нас сама структура, то для обращения к полю структуры необходимо использовать точку.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
02.06.2012, 15:45
общий
Адресаты:
Игорь Витальевич, а ведь у дерева только 1 корень, только что заметил ... Вам не сложно будет ввести дополнительное условие для ограничения количества корней? Уже очень неловко даже просить что-либо, но все же...
давно
Посетитель
7438
7205
02.06.2012, 21:19
общий
А почему у корня не должно быть братьев? Дерево общего вполне это допускает.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
02.06.2012, 21:38
общий
Адресаты:
Разве? Мне всегда казалось, что у любого дерева должен быть 1 корень.Хорошо спасибо
Еще маленький вопрос - почему если корень или братья корня имеют минимальную глубину, то она выводится как "1", а не "0"?
давно
Посетитель
7438
7205
02.06.2012, 23:42
общий
Ну так есть же один уровень, вот и выводится 1.
Конечно, это все условно. Мне просто показалось, что так логично.
Кроме того, у меня глубина 0 говорит об отсутствии дерева.
Впрочем, если хочется, можно при выводе уменьшить на 1 (т.е. выводить iDepthMin-1)

Хм, прочитал определение глубины, как длину пути из корня...
Получается, что для корня таки должно быть 0. Ну так сделайте, как сказал выше, и будет Вам счет с 0
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
02.06.2012, 23:45
общий
Адресаты:
Спасибо!
Форма ответа