multiple definition of
Сделал вроде все нормально, но вот ругается
В проекте 4е файла:
main.c
/*
Программу подготовил: Буренков Игорь (М8О-206Б-17)
Вариант: АВЛ-дерево
*/
/////////////////////////////////////////////////////////
/* Системные библиотеки */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
/* Пользовательские библиотеки */
#include "AVL_tree_slimrg.h"
#include "settings_slimrg.h"
/* Структуры */
/* Сигнатуры функций */
unsigned short int InputFiller(); // Ввод и исполнение комманд
void PrintError(unsigned short int ErrorCode); // Вывод ошибок
/* Основной цикл */
int main(){
// Переменные
unsigned short int log_error; // Код ошибки
// Считываем и выполняем команды
log_error = InputFiller();
// Выввод ошибки
PrintError(log_error);
// Пауза при закрытии
if (debug_pauseonclose) system("pause");
// Все ОК
return 0;
}
// Цикл ввода и выполнения
unsigned short int InputFiller(){
// Переменные
char tmpchar[StringLengthPS+1]; // Временный контейнер для символа
char tmpword[StringLengthPS+1]; // Временный контейнер для слова (массива символов)
unsigned long long int tmpkey; // Временный контейнер для ключа
unsigned char errorcode; // Код ошибки
unsigned int i; // Тикер (для циклов и т.д.)
// Создание пустого дерева
struct avltree* AVLTree1 = AVL_Create();
// Пока возможно - считываем первый символ строки
while (scanf("%s", tmpchar) >= 1){
// Перевод в нижний регистр
tmpchar[0] = tolower(tmpchar[0]);
// Определение комманды
switch (tmpchar[0]) {
// Добавить слово
case '+':
// Считываем слово
scanf("%s", tmpword);
// Преобразование в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Считывание ключа
scanf("%llu", &tmpkey);
// Довавляем лист (с включенным выводом)
AVL_InsertLeaf(tmpword, tmpkey, AVLTree1, true);
break;
// Отладочные комманды
case '!':
// Считываем слово
scanf("%s", tmpword);
// Перевод в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Распознание слова
if (strcmp(tmpword, "exit") == 0) {
return 0;
} else
if (strcmp(tmpword, "print") == 0) {
AVL_PrintMe(AVLTree1);
} else
if (strcmp(tmpword, "save") == 0) {
AVL_SaveTree(AVLTree1, true);
} else
if (strcmp(tmpword, "load") == 0) {
AVL_LoadTree(AVLTree1, true);
}
break;
// Удаление слова
case '-':
// Считываем слово
scanf("%s", tmpword);
// Преобразование в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Удаляем лист
AVL_RemoveLeaf(tmpword, AVLTree1, true);
break;
// Заглушка
case 'n':
break;
// Осталось слово
default:
for (i = 0; i < StringLengthPS; i++) tmpchar[i] = tolower(tmpchar[i]);
// Поиск
tmpkey = AVL_FindMe_p(tmpchar, AVLTree1, true);
break;
}
}
return 0;
}
// Печать ошибок
void PrintError(unsigned short int ErrorCode){
}
AVL_tree_slimrg.h
#ifndef AVL_tree_slimrg_h
#define AVL_tree_slimrg_h
// Стандартные заголовки
#include <stdbool.h>
#include <string.h>
// Настройки
#include "settings_slimrg.h"
// Сама структура
struct avltree;
// Создание дерева
struct avltree* AVL_Create();
// Уничтожение дерева
void AVL_FreeAndNil(struct avltree* AVL_Tree);
// Проверка на пустоту
bool AVL_IsEmpty(struct avltree* AVL_Tree);
// Добавить лист
void AVL_InsertLeaf(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVL_Tree, bool PrintStatus);
// Удаление листа по значению
void AVL_RemoveLeaf(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus);
// Поиск значения
bool AVL_FindMe(char key[StringLengthPS+1], struct avltree* AVL_Tree);
unsigned long long int AVL_FindMe_p(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus);
// Печать дерева
void AVL_PrintMe(struct avltree* AVL_Tree);
// Сохранение дерева
void AVL_SaveTree(struct avltree* AVL_Tree, bool PrintStatus);
// Загрузка дерева
void AVL_LoadTree(struct avltree* AVL_Tree, bool PrintStatus);
#endif
AVL_tree_slimrg.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "AVL_tree_slimrg.h"
// Структура строки
struct String{
char* Text;
unsigned short int count;
};
// Структура листа
struct avlleaf {
struct String key; // Ключ
unsigned long long int llupar; // Значение
long int height; // Высота
struct avlleaf* left; // Левый ребенок
struct avlleaf* right; // Правый ребенок
};
// Структура дерева
struct avltree {
struct avlleaf* root;
};
// Создание дерева
struct avltree* AVL_Create() {
struct avltree* AVL_Tree = malloc(sizeof(struct avltree));
AVL_Tree->root = NULL;
return AVL_Tree;
}
// Уничтожение дерева
void AVL_FreeAndNil(struct avltree* AVL_Tree) {
// Переменные
char tmpword[StringLengthPS+1];
unsigned short int i; // Тикер (для циклов и т.д.)
// Запускаем балалайку ^_^
while (AVL_IsEmpty(AVL_Tree) == false) {
for (i = 0; i <= AVL_Tree->root->key.count; i++) {
tmpword[i] = AVL_Tree->root->key.Text[i];
}
AVL_RemoveLeaf(tmpword, AVL_Tree, false);
}
}
// Проверка на пустоту
bool AVL_IsEmpty(struct avltree* AVL_Tree) {
return (AVL_Tree->root == NULL);
}
// Инициализация листа
struct avlleaf* AVLLeaf_Create(char inputkey[StringLengthPS+1], unsigned long long int llupar) {
// Переменные
struct avlleaf* keim; // Лист
unsigned short int i; // Тикер (для циклов и т.д.)
// Начальная инициализация
keim = malloc(sizeof(struct avlleaf));
keim->right = keim->left = NULL;
keim->llupar = llupar;
// Сложная инициализация
i = 0;
while (inputkey[i] != 0) i++;
keim->key.count = i;
keim->key.Text = malloc(keim->key.count * sizeof(char));
for (i = 0; i <= keim->key.count; i++) {
keim->key.Text[i] = inputkey[i];
}
keim->height = 0;
return keim;
}
// Получение высоты листа
long int AVLLeaf_GetHeight(struct avlleaf* Leaf) {
if (Leaf == NULL) return (-1); else return Leaf->height;
}
// Получение коэффицента балансировки
char AVLLeaf_GetBalance(struct avlleaf* Leaf) {
return (AVLLeaf_GetHeight(Leaf->right) - AVLLeaf_GetHeight(Leaf->left));
}
// Проверка высоты
void AVLLeaf_CheckHeight(struct avlleaf* Leaf) {
// Переменные
long int left, right; // Дети листа Leaf
left = AVLLeaf_GetHeight(Leaf->left);
right = AVLLeaf_GetHeight(Leaf->right);
// Высота получается увеличением максимальной детской высоты на единицу
if (left <= right) Leaf->height = right + 1; else Leaf->height = left + 1;
}
// Малое леве вращение (Small Left)
struct avlleaf* AVL_rotation_SL(struct avlleaf* Leaf) {
// Переменные
struct avlleaf* aor; // Ось вращения (Axis Of Rotation)
aor = Leaf->right;
// Магия вращения... (Вжух...)
Leaf->right = aor->left;
aor->left = Leaf;
// Выправляем высоту
AVLLeaf_CheckHeight(Leaf);
AVLLeaf_CheckHeight(aor);
return aor;
}
// Малое правое вращение (Small Right)
struct avlleaf* AVL_rotation_SR(struct avlleaf* Leaf) {
// Переменные
struct avlleaf* aor; // Ось вращения (Axis Of Rotation)
aor = Leaf->left;
// Магия вращения... (Вжух...)
Leaf->left = aor->right;
aor->right = Leaf;
// Выправляем высоту
AVLLeaf_CheckHeight(Leaf);
AVLLeaf_CheckHeight(aor);
return aor;
}
// Ребалансировка дерева
struct avlleaf* AVL_BalanceMe(struct avlleaf* Leaf) {
// Переменные
char balfac; // Коэффицент баласировки (от -2 до +2)
balfac = AVLLeaf_GetBalance(Leaf);
// Оцениваем баланс и выправляем его
if (balfac < -1) {
// Смотрим, требуется ли большое вращение
if (AVLLeaf_GetBalance(Leaf->left) > 0) {
Leaf->left = AVL_rotation_SL(Leaf->left);
}
return (AVL_rotation_SR(Leaf));
} else if (balfac > 1) {
// Смотрим, требуется ли большое вращение
if (AVLLeaf_GetBalance(Leaf->right) < 0) {
Leaf->right = AVL_rotation_SR(Leaf->right);
}
return (AVL_rotation_SL(Leaf));
} else { // Если нуль
// Вращение НЕ требуется
AVLLeaf_CheckHeight(Leaf);
return Leaf;
}
}
// Поиск места вставки и вставка
struct avlleaf* AVL_FindAndInsert(char key[StringLengthPS+1], unsigned long long int llupar, struct avlleaf* Leaf, bool PrintStatus) {
// Если поддерево пустое
if (Leaf == NULL) {
if (PrintStatus) printf("OKn");
return AVLLeaf_Create(key, llupar);
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndInsert(key, llupar, Leaf->left, PrintStatus);
} else if (strcmp(key, Leaf->key.Text) > 0){
Leaf->right = AVL_FindAndInsert(key, llupar, Leaf->right, PrintStatus);
} else {
if (PrintStatus) printf("Existn");
}
return AVL_BalanceMe(Leaf);
}
// Добавление листа (обертка над функцией выше)
void AVL_InsertLeaf(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVLTree, bool PrintStatus) {
AVLTree->root = AVL_FindAndInsert(key, llupar, AVLTree->root, PrintStatus);
}
// Получение минимального значения
struct String AVL_GetMinKey(struct avlleaf* Leaf) {
while (Leaf->left != NULL) Leaf = Leaf->left;
return Leaf->key;
}
// Получение параметра у листа с минимальным значением
unsigned long long int AVL_GetMinVal(struct avlleaf* Leaf) {
while (Leaf->left != NULL) Leaf = Leaf->left;
return Leaf->llupar;
}
// Поиск и удаление
struct avlleaf* AVL_FindAndRemove(char key[StringLengthPS+1], struct avlleaf* Leaf, bool PrintStatus) {
// Переменные
struct avlleaf* child; // Служебная (для случаев с одним ребенком)
char tmpkey[StringLengthPS+1]; // Временный контейнер для ключа
unsigned short int i; // Тикер (для циклов и т.д.)
if (Leaf == NULL) {
// Нет значения для удаления
if (PrintStatus) printf("NoSuchWordn");
return NULL;
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndRemove(key, Leaf->left, PrintStatus);
return AVL_BalanceMe(Leaf);
} else if (strcmp(key, Leaf->key.Text) > 0) {
Leaf->right = AVL_FindAndRemove(key, Leaf->right, PrintStatus);
return AVL_BalanceMe(Leaf);
} else { // Найдена позиция
if (PrintStatus) printf("OKn");
// Анализ детей и перемещение
if (Leaf->left != NULL && Leaf->right != NULL) {
Leaf->key = AVL_GetMinKey(Leaf->right);
Leaf->llupar = AVL_GetMinVal(Leaf->right);
for (i = 0; i <= Leaf->key.count; i++) {
tmpkey[i] = Leaf->key.Text[i];
}
Leaf->right = AVL_FindAndRemove(tmpkey, Leaf->right, PrintStatus);
return AVL_BalanceMe(Leaf);
} else if (Leaf->left != NULL) {
// Есть только один ребенок (правый)
child = Leaf->left;
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return child;
} else if (Leaf->right != NULL) {
// Есть только один ребенок (левый)
child = Leaf->right;
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return child;
} else {
// Нет дитей - просто выкидываем
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return NULL;
}
}
}
// Удаление из дерева (обертка над функцией выше)
void AVL_RemoveLeaf(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus) {
AVL_Tree->root = AVL_FindAndRemove(key, AVL_Tree->root, PrintStatus);
}
// Поиск элемента в дереве
bool AVL_FindMe(char key[StringLengthPS+1], struct avltree* AVL_Tree) {
// Переменные
struct avlleaf* CuP;
CuP = AVL_Tree->root;
while (CuP != NULL) {
if (strcmp (key, CuP->key.Text) == 0) {
return true;
} else if (strcmp(key, CuP->key.Text) < 0) {
CuP = CuP->left;
} else {
CuP = CuP->right;
}
}
return false;
}
// Еще один алгоритм поиска (удобнее для пользователя)
unsigned long long int AVL_FindMe_p(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
struct avlleaf* CuP;
CuP = AVL_Tree->root;
while (CuP != NULL) {
if (strcmp (key, CuP->key.Text) == 0) {
if (PrintStatus){
printf("OK: ");
printf("%llu", (CuP->llupar));
printf("n");
}
return CuP->llupar;
} else if (strcmp(key, CuP->key.Text) < 0) {
CuP = CuP->left;
} else {
CuP = CuP->right;
}
}
if (PrintStatus) printf("NoSuchWordn");
return 0;
}
// Печать дерева
void AVL_print_rec(struct avlleaf* Leaf, long int lvl) {
// Переменные
int i;
if (Leaf == NULL) {
return;
}
AVL_print_rec(Leaf->left, lvl + 1);
for (i = 0; i < lvl; i++) printf("t");
printf("%s", Leaf->key.Text);
printf("%c", '|');
printf("%llu", Leaf->llupar);
printf("n");
AVL_print_rec(Leaf->right, lvl + 1);
}
// Печать дерева (обертка над функцией выше)
void AVL_PrintMe(struct avltree* AVL_Tree){
if (AVL_Tree->root == NULL) {
printf("EMPTYn");
} else {
AVL_print_rec(AVL_Tree->root, 0);
}
}
// Запись лист в файл
void AVL_LeafToFile(struct avlleaf* Leaf, FILE * file){
if (Leaf == NULL) return;
fwrite(&(Leaf->key.count), sizeof(unsigned short int), 1, file);
fwrite(Leaf->key.Text, sizeof(char), Leaf->key.count+1, file);
fwrite(&(Leaf->llupar), sizeof(unsigned long long int), 1, file);
AVL_LeafToFile(Leaf->right, file);
AVL_LeafToFile(Leaf->left, file);
}
// Сохранение дерева
void AVL_SaveTree(struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
char adress[1024];
FILE *file = NULL;
// Открытие файла
scanf("%s", adress);
file = fopen(adress, "wb+");
if ((file == NULL)&&(PrintStatus)) printf("ERROR: Couldn't create filen");
if (file == NULL) return;
// Запись дерева
fwrite(&(UnCo), sizeof(unsigned long long int), 1, file);
AVL_LeafToFile(AVL_Tree->root, file);
// Закрытие
if (PrintStatus) printf("OKn");
fclose(file);
}
// Поиск места вставки и вставка
struct avlleaf* AVL_FindAndInsert_clean(char key[StringLengthPS+1], unsigned long long int llupar, struct avlleaf* Leaf, bool PrintStatus) {
// Если поддерево пустое
if (Leaf == NULL) {
return AVLLeaf_Create(key, llupar);
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndInsert_clean(key, llupar, Leaf->left, PrintStatus);
} else if (strcmp(key, Leaf->key.Text) > 0){
Leaf->right = AVL_FindAndInsert_clean(key, llupar, Leaf->right, PrintStatus);
} else {
if (PrintStatus) printf("ERROR: Broken Filen");
}
return Leaf;
}
// Добавление листа (обертка над функцией выше)
void AVL_InsertLeaf_clean(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVLTree, bool PrintStatus) {
AVLTree->root = AVL_FindAndInsert_clean(key, llupar, AVLTree->root, PrintStatus);
}
// Загрузка листа из файла
void AVL_LeafFromFile(struct avltree* AVL_Tree, FILE * file){
// Переменные
char tmpkey[StringLengthPS+1];
unsigned long long int tmpllupar;
unsigned short int charcount;
while (feof(file) == 0){
fread(&charcount, sizeof(unsigned short int), 1, file);
fread(tmpkey, sizeof(char), charcount+1, file);
fread(&tmpllupar, sizeof(unsigned long long int), 1, file);
AVL_InsertLeaf_clean(tmpkey, tmpllupar, AVL_Tree, false);
}
}
// Загрузка дерева
void AVL_LoadTree(struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
char adress[1024];
FILE *file = NULL;
unsigned long long int FileUnCo;
// Открытие файла
scanf("%s", adress);
file = fopen(adress, "rb");
if ((file == NULL)&&(PrintStatus)) printf("ERROR: Couldn't read filen");
if (file == NULL) return;
// Тест совместимости
fread(&FileUnCo, sizeof(unsigned long long int), 1, file);
if (UnCo != FileUnCo){
printf("ERROR: Unsupported filen");
return;
}
// Уничтожаем ранее созданное дерево
AVL_FreeAndNil(AVL_Tree);
// Загружаем новое дерево
AVL_LeafFromFile(AVL_Tree, file);
// Закрытие
if (PrintStatus) printf("OKn");
fclose(file);
}
settings_slimrg.h
#ifndef settings_h
#define settings_h
/* Settings */
// Настройка ввода
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
// Настройка отладки
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
// Номер сборки
const unsigned long long int UnCo = 115700744534137162;
#endif
MakeFile
all:
gcc -pedantic -Wall -std=c99 -Werror -Wno-sign-compare main.c AVL_tree_slimrg.c -lm -o lb2
Лог (здесь main.c заменен на lb2.c)
gcc -pedantic -Wall -std=c99 -Werror -Wno-sign-compare lb2.c AVL_tree_slimrg.c -lm -o lb2
/tmp/cc4upHwG.o:(.rodata+0x0): multiple definition of `StringLengthPS'
/tmp/ccORqDAb.o:(.rodata+0x0): first defined here
/tmp/cc4upHwG.o:(.rodata+0x4): multiple definition of `debug_pauseonclose'
/tmp/ccORqDAb.o:(.rodata+0x4): first defined here
/tmp/cc4upHwG.o:(.rodata+0x8): multiple definition of `UnCo'
/tmp/ccORqDAb.o:(.rodata+0x8): first defined here
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
c компиляция
добавить комментарий |
Сделал вроде все нормально, но вот ругается
В проекте 4е файла:
main.c
/*
Программу подготовил: Буренков Игорь (М8О-206Б-17)
Вариант: АВЛ-дерево
*/
/////////////////////////////////////////////////////////
/* Системные библиотеки */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
/* Пользовательские библиотеки */
#include "AVL_tree_slimrg.h"
#include "settings_slimrg.h"
/* Структуры */
/* Сигнатуры функций */
unsigned short int InputFiller(); // Ввод и исполнение комманд
void PrintError(unsigned short int ErrorCode); // Вывод ошибок
/* Основной цикл */
int main(){
// Переменные
unsigned short int log_error; // Код ошибки
// Считываем и выполняем команды
log_error = InputFiller();
// Выввод ошибки
PrintError(log_error);
// Пауза при закрытии
if (debug_pauseonclose) system("pause");
// Все ОК
return 0;
}
// Цикл ввода и выполнения
unsigned short int InputFiller(){
// Переменные
char tmpchar[StringLengthPS+1]; // Временный контейнер для символа
char tmpword[StringLengthPS+1]; // Временный контейнер для слова (массива символов)
unsigned long long int tmpkey; // Временный контейнер для ключа
unsigned char errorcode; // Код ошибки
unsigned int i; // Тикер (для циклов и т.д.)
// Создание пустого дерева
struct avltree* AVLTree1 = AVL_Create();
// Пока возможно - считываем первый символ строки
while (scanf("%s", tmpchar) >= 1){
// Перевод в нижний регистр
tmpchar[0] = tolower(tmpchar[0]);
// Определение комманды
switch (tmpchar[0]) {
// Добавить слово
case '+':
// Считываем слово
scanf("%s", tmpword);
// Преобразование в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Считывание ключа
scanf("%llu", &tmpkey);
// Довавляем лист (с включенным выводом)
AVL_InsertLeaf(tmpword, tmpkey, AVLTree1, true);
break;
// Отладочные комманды
case '!':
// Считываем слово
scanf("%s", tmpword);
// Перевод в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Распознание слова
if (strcmp(tmpword, "exit") == 0) {
return 0;
} else
if (strcmp(tmpword, "print") == 0) {
AVL_PrintMe(AVLTree1);
} else
if (strcmp(tmpword, "save") == 0) {
AVL_SaveTree(AVLTree1, true);
} else
if (strcmp(tmpword, "load") == 0) {
AVL_LoadTree(AVLTree1, true);
}
break;
// Удаление слова
case '-':
// Считываем слово
scanf("%s", tmpword);
// Преобразование в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Удаляем лист
AVL_RemoveLeaf(tmpword, AVLTree1, true);
break;
// Заглушка
case 'n':
break;
// Осталось слово
default:
for (i = 0; i < StringLengthPS; i++) tmpchar[i] = tolower(tmpchar[i]);
// Поиск
tmpkey = AVL_FindMe_p(tmpchar, AVLTree1, true);
break;
}
}
return 0;
}
// Печать ошибок
void PrintError(unsigned short int ErrorCode){
}
AVL_tree_slimrg.h
#ifndef AVL_tree_slimrg_h
#define AVL_tree_slimrg_h
// Стандартные заголовки
#include <stdbool.h>
#include <string.h>
// Настройки
#include "settings_slimrg.h"
// Сама структура
struct avltree;
// Создание дерева
struct avltree* AVL_Create();
// Уничтожение дерева
void AVL_FreeAndNil(struct avltree* AVL_Tree);
// Проверка на пустоту
bool AVL_IsEmpty(struct avltree* AVL_Tree);
// Добавить лист
void AVL_InsertLeaf(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVL_Tree, bool PrintStatus);
// Удаление листа по значению
void AVL_RemoveLeaf(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus);
// Поиск значения
bool AVL_FindMe(char key[StringLengthPS+1], struct avltree* AVL_Tree);
unsigned long long int AVL_FindMe_p(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus);
// Печать дерева
void AVL_PrintMe(struct avltree* AVL_Tree);
// Сохранение дерева
void AVL_SaveTree(struct avltree* AVL_Tree, bool PrintStatus);
// Загрузка дерева
void AVL_LoadTree(struct avltree* AVL_Tree, bool PrintStatus);
#endif
AVL_tree_slimrg.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "AVL_tree_slimrg.h"
// Структура строки
struct String{
char* Text;
unsigned short int count;
};
// Структура листа
struct avlleaf {
struct String key; // Ключ
unsigned long long int llupar; // Значение
long int height; // Высота
struct avlleaf* left; // Левый ребенок
struct avlleaf* right; // Правый ребенок
};
// Структура дерева
struct avltree {
struct avlleaf* root;
};
// Создание дерева
struct avltree* AVL_Create() {
struct avltree* AVL_Tree = malloc(sizeof(struct avltree));
AVL_Tree->root = NULL;
return AVL_Tree;
}
// Уничтожение дерева
void AVL_FreeAndNil(struct avltree* AVL_Tree) {
// Переменные
char tmpword[StringLengthPS+1];
unsigned short int i; // Тикер (для циклов и т.д.)
// Запускаем балалайку ^_^
while (AVL_IsEmpty(AVL_Tree) == false) {
for (i = 0; i <= AVL_Tree->root->key.count; i++) {
tmpword[i] = AVL_Tree->root->key.Text[i];
}
AVL_RemoveLeaf(tmpword, AVL_Tree, false);
}
}
// Проверка на пустоту
bool AVL_IsEmpty(struct avltree* AVL_Tree) {
return (AVL_Tree->root == NULL);
}
// Инициализация листа
struct avlleaf* AVLLeaf_Create(char inputkey[StringLengthPS+1], unsigned long long int llupar) {
// Переменные
struct avlleaf* keim; // Лист
unsigned short int i; // Тикер (для циклов и т.д.)
// Начальная инициализация
keim = malloc(sizeof(struct avlleaf));
keim->right = keim->left = NULL;
keim->llupar = llupar;
// Сложная инициализация
i = 0;
while (inputkey[i] != 0) i++;
keim->key.count = i;
keim->key.Text = malloc(keim->key.count * sizeof(char));
for (i = 0; i <= keim->key.count; i++) {
keim->key.Text[i] = inputkey[i];
}
keim->height = 0;
return keim;
}
// Получение высоты листа
long int AVLLeaf_GetHeight(struct avlleaf* Leaf) {
if (Leaf == NULL) return (-1); else return Leaf->height;
}
// Получение коэффицента балансировки
char AVLLeaf_GetBalance(struct avlleaf* Leaf) {
return (AVLLeaf_GetHeight(Leaf->right) - AVLLeaf_GetHeight(Leaf->left));
}
// Проверка высоты
void AVLLeaf_CheckHeight(struct avlleaf* Leaf) {
// Переменные
long int left, right; // Дети листа Leaf
left = AVLLeaf_GetHeight(Leaf->left);
right = AVLLeaf_GetHeight(Leaf->right);
// Высота получается увеличением максимальной детской высоты на единицу
if (left <= right) Leaf->height = right + 1; else Leaf->height = left + 1;
}
// Малое леве вращение (Small Left)
struct avlleaf* AVL_rotation_SL(struct avlleaf* Leaf) {
// Переменные
struct avlleaf* aor; // Ось вращения (Axis Of Rotation)
aor = Leaf->right;
// Магия вращения... (Вжух...)
Leaf->right = aor->left;
aor->left = Leaf;
// Выправляем высоту
AVLLeaf_CheckHeight(Leaf);
AVLLeaf_CheckHeight(aor);
return aor;
}
// Малое правое вращение (Small Right)
struct avlleaf* AVL_rotation_SR(struct avlleaf* Leaf) {
// Переменные
struct avlleaf* aor; // Ось вращения (Axis Of Rotation)
aor = Leaf->left;
// Магия вращения... (Вжух...)
Leaf->left = aor->right;
aor->right = Leaf;
// Выправляем высоту
AVLLeaf_CheckHeight(Leaf);
AVLLeaf_CheckHeight(aor);
return aor;
}
// Ребалансировка дерева
struct avlleaf* AVL_BalanceMe(struct avlleaf* Leaf) {
// Переменные
char balfac; // Коэффицент баласировки (от -2 до +2)
balfac = AVLLeaf_GetBalance(Leaf);
// Оцениваем баланс и выправляем его
if (balfac < -1) {
// Смотрим, требуется ли большое вращение
if (AVLLeaf_GetBalance(Leaf->left) > 0) {
Leaf->left = AVL_rotation_SL(Leaf->left);
}
return (AVL_rotation_SR(Leaf));
} else if (balfac > 1) {
// Смотрим, требуется ли большое вращение
if (AVLLeaf_GetBalance(Leaf->right) < 0) {
Leaf->right = AVL_rotation_SR(Leaf->right);
}
return (AVL_rotation_SL(Leaf));
} else { // Если нуль
// Вращение НЕ требуется
AVLLeaf_CheckHeight(Leaf);
return Leaf;
}
}
// Поиск места вставки и вставка
struct avlleaf* AVL_FindAndInsert(char key[StringLengthPS+1], unsigned long long int llupar, struct avlleaf* Leaf, bool PrintStatus) {
// Если поддерево пустое
if (Leaf == NULL) {
if (PrintStatus) printf("OKn");
return AVLLeaf_Create(key, llupar);
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndInsert(key, llupar, Leaf->left, PrintStatus);
} else if (strcmp(key, Leaf->key.Text) > 0){
Leaf->right = AVL_FindAndInsert(key, llupar, Leaf->right, PrintStatus);
} else {
if (PrintStatus) printf("Existn");
}
return AVL_BalanceMe(Leaf);
}
// Добавление листа (обертка над функцией выше)
void AVL_InsertLeaf(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVLTree, bool PrintStatus) {
AVLTree->root = AVL_FindAndInsert(key, llupar, AVLTree->root, PrintStatus);
}
// Получение минимального значения
struct String AVL_GetMinKey(struct avlleaf* Leaf) {
while (Leaf->left != NULL) Leaf = Leaf->left;
return Leaf->key;
}
// Получение параметра у листа с минимальным значением
unsigned long long int AVL_GetMinVal(struct avlleaf* Leaf) {
while (Leaf->left != NULL) Leaf = Leaf->left;
return Leaf->llupar;
}
// Поиск и удаление
struct avlleaf* AVL_FindAndRemove(char key[StringLengthPS+1], struct avlleaf* Leaf, bool PrintStatus) {
// Переменные
struct avlleaf* child; // Служебная (для случаев с одним ребенком)
char tmpkey[StringLengthPS+1]; // Временный контейнер для ключа
unsigned short int i; // Тикер (для циклов и т.д.)
if (Leaf == NULL) {
// Нет значения для удаления
if (PrintStatus) printf("NoSuchWordn");
return NULL;
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndRemove(key, Leaf->left, PrintStatus);
return AVL_BalanceMe(Leaf);
} else if (strcmp(key, Leaf->key.Text) > 0) {
Leaf->right = AVL_FindAndRemove(key, Leaf->right, PrintStatus);
return AVL_BalanceMe(Leaf);
} else { // Найдена позиция
if (PrintStatus) printf("OKn");
// Анализ детей и перемещение
if (Leaf->left != NULL && Leaf->right != NULL) {
Leaf->key = AVL_GetMinKey(Leaf->right);
Leaf->llupar = AVL_GetMinVal(Leaf->right);
for (i = 0; i <= Leaf->key.count; i++) {
tmpkey[i] = Leaf->key.Text[i];
}
Leaf->right = AVL_FindAndRemove(tmpkey, Leaf->right, PrintStatus);
return AVL_BalanceMe(Leaf);
} else if (Leaf->left != NULL) {
// Есть только один ребенок (правый)
child = Leaf->left;
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return child;
} else if (Leaf->right != NULL) {
// Есть только один ребенок (левый)
child = Leaf->right;
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return child;
} else {
// Нет дитей - просто выкидываем
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return NULL;
}
}
}
// Удаление из дерева (обертка над функцией выше)
void AVL_RemoveLeaf(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus) {
AVL_Tree->root = AVL_FindAndRemove(key, AVL_Tree->root, PrintStatus);
}
// Поиск элемента в дереве
bool AVL_FindMe(char key[StringLengthPS+1], struct avltree* AVL_Tree) {
// Переменные
struct avlleaf* CuP;
CuP = AVL_Tree->root;
while (CuP != NULL) {
if (strcmp (key, CuP->key.Text) == 0) {
return true;
} else if (strcmp(key, CuP->key.Text) < 0) {
CuP = CuP->left;
} else {
CuP = CuP->right;
}
}
return false;
}
// Еще один алгоритм поиска (удобнее для пользователя)
unsigned long long int AVL_FindMe_p(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
struct avlleaf* CuP;
CuP = AVL_Tree->root;
while (CuP != NULL) {
if (strcmp (key, CuP->key.Text) == 0) {
if (PrintStatus){
printf("OK: ");
printf("%llu", (CuP->llupar));
printf("n");
}
return CuP->llupar;
} else if (strcmp(key, CuP->key.Text) < 0) {
CuP = CuP->left;
} else {
CuP = CuP->right;
}
}
if (PrintStatus) printf("NoSuchWordn");
return 0;
}
// Печать дерева
void AVL_print_rec(struct avlleaf* Leaf, long int lvl) {
// Переменные
int i;
if (Leaf == NULL) {
return;
}
AVL_print_rec(Leaf->left, lvl + 1);
for (i = 0; i < lvl; i++) printf("t");
printf("%s", Leaf->key.Text);
printf("%c", '|');
printf("%llu", Leaf->llupar);
printf("n");
AVL_print_rec(Leaf->right, lvl + 1);
}
// Печать дерева (обертка над функцией выше)
void AVL_PrintMe(struct avltree* AVL_Tree){
if (AVL_Tree->root == NULL) {
printf("EMPTYn");
} else {
AVL_print_rec(AVL_Tree->root, 0);
}
}
// Запись лист в файл
void AVL_LeafToFile(struct avlleaf* Leaf, FILE * file){
if (Leaf == NULL) return;
fwrite(&(Leaf->key.count), sizeof(unsigned short int), 1, file);
fwrite(Leaf->key.Text, sizeof(char), Leaf->key.count+1, file);
fwrite(&(Leaf->llupar), sizeof(unsigned long long int), 1, file);
AVL_LeafToFile(Leaf->right, file);
AVL_LeafToFile(Leaf->left, file);
}
// Сохранение дерева
void AVL_SaveTree(struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
char adress[1024];
FILE *file = NULL;
// Открытие файла
scanf("%s", adress);
file = fopen(adress, "wb+");
if ((file == NULL)&&(PrintStatus)) printf("ERROR: Couldn't create filen");
if (file == NULL) return;
// Запись дерева
fwrite(&(UnCo), sizeof(unsigned long long int), 1, file);
AVL_LeafToFile(AVL_Tree->root, file);
// Закрытие
if (PrintStatus) printf("OKn");
fclose(file);
}
// Поиск места вставки и вставка
struct avlleaf* AVL_FindAndInsert_clean(char key[StringLengthPS+1], unsigned long long int llupar, struct avlleaf* Leaf, bool PrintStatus) {
// Если поддерево пустое
if (Leaf == NULL) {
return AVLLeaf_Create(key, llupar);
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndInsert_clean(key, llupar, Leaf->left, PrintStatus);
} else if (strcmp(key, Leaf->key.Text) > 0){
Leaf->right = AVL_FindAndInsert_clean(key, llupar, Leaf->right, PrintStatus);
} else {
if (PrintStatus) printf("ERROR: Broken Filen");
}
return Leaf;
}
// Добавление листа (обертка над функцией выше)
void AVL_InsertLeaf_clean(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVLTree, bool PrintStatus) {
AVLTree->root = AVL_FindAndInsert_clean(key, llupar, AVLTree->root, PrintStatus);
}
// Загрузка листа из файла
void AVL_LeafFromFile(struct avltree* AVL_Tree, FILE * file){
// Переменные
char tmpkey[StringLengthPS+1];
unsigned long long int tmpllupar;
unsigned short int charcount;
while (feof(file) == 0){
fread(&charcount, sizeof(unsigned short int), 1, file);
fread(tmpkey, sizeof(char), charcount+1, file);
fread(&tmpllupar, sizeof(unsigned long long int), 1, file);
AVL_InsertLeaf_clean(tmpkey, tmpllupar, AVL_Tree, false);
}
}
// Загрузка дерева
void AVL_LoadTree(struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
char adress[1024];
FILE *file = NULL;
unsigned long long int FileUnCo;
// Открытие файла
scanf("%s", adress);
file = fopen(adress, "rb");
if ((file == NULL)&&(PrintStatus)) printf("ERROR: Couldn't read filen");
if (file == NULL) return;
// Тест совместимости
fread(&FileUnCo, sizeof(unsigned long long int), 1, file);
if (UnCo != FileUnCo){
printf("ERROR: Unsupported filen");
return;
}
// Уничтожаем ранее созданное дерево
AVL_FreeAndNil(AVL_Tree);
// Загружаем новое дерево
AVL_LeafFromFile(AVL_Tree, file);
// Закрытие
if (PrintStatus) printf("OKn");
fclose(file);
}
settings_slimrg.h
#ifndef settings_h
#define settings_h
/* Settings */
// Настройка ввода
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
// Настройка отладки
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
// Номер сборки
const unsigned long long int UnCo = 115700744534137162;
#endif
MakeFile
all:
gcc -pedantic -Wall -std=c99 -Werror -Wno-sign-compare main.c AVL_tree_slimrg.c -lm -o lb2
Лог (здесь main.c заменен на lb2.c)
gcc -pedantic -Wall -std=c99 -Werror -Wno-sign-compare lb2.c AVL_tree_slimrg.c -lm -o lb2
/tmp/cc4upHwG.o:(.rodata+0x0): multiple definition of `StringLengthPS'
/tmp/ccORqDAb.o:(.rodata+0x0): first defined here
/tmp/cc4upHwG.o:(.rodata+0x4): multiple definition of `debug_pauseonclose'
/tmp/ccORqDAb.o:(.rodata+0x4): first defined here
/tmp/cc4upHwG.o:(.rodata+0x8): multiple definition of `UnCo'
/tmp/ccORqDAb.o:(.rodata+0x8): first defined here
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
c компиляция
добавить комментарий |
Сделал вроде все нормально, но вот ругается
В проекте 4е файла:
main.c
/*
Программу подготовил: Буренков Игорь (М8О-206Б-17)
Вариант: АВЛ-дерево
*/
/////////////////////////////////////////////////////////
/* Системные библиотеки */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
/* Пользовательские библиотеки */
#include "AVL_tree_slimrg.h"
#include "settings_slimrg.h"
/* Структуры */
/* Сигнатуры функций */
unsigned short int InputFiller(); // Ввод и исполнение комманд
void PrintError(unsigned short int ErrorCode); // Вывод ошибок
/* Основной цикл */
int main(){
// Переменные
unsigned short int log_error; // Код ошибки
// Считываем и выполняем команды
log_error = InputFiller();
// Выввод ошибки
PrintError(log_error);
// Пауза при закрытии
if (debug_pauseonclose) system("pause");
// Все ОК
return 0;
}
// Цикл ввода и выполнения
unsigned short int InputFiller(){
// Переменные
char tmpchar[StringLengthPS+1]; // Временный контейнер для символа
char tmpword[StringLengthPS+1]; // Временный контейнер для слова (массива символов)
unsigned long long int tmpkey; // Временный контейнер для ключа
unsigned char errorcode; // Код ошибки
unsigned int i; // Тикер (для циклов и т.д.)
// Создание пустого дерева
struct avltree* AVLTree1 = AVL_Create();
// Пока возможно - считываем первый символ строки
while (scanf("%s", tmpchar) >= 1){
// Перевод в нижний регистр
tmpchar[0] = tolower(tmpchar[0]);
// Определение комманды
switch (tmpchar[0]) {
// Добавить слово
case '+':
// Считываем слово
scanf("%s", tmpword);
// Преобразование в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Считывание ключа
scanf("%llu", &tmpkey);
// Довавляем лист (с включенным выводом)
AVL_InsertLeaf(tmpword, tmpkey, AVLTree1, true);
break;
// Отладочные комманды
case '!':
// Считываем слово
scanf("%s", tmpword);
// Перевод в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Распознание слова
if (strcmp(tmpword, "exit") == 0) {
return 0;
} else
if (strcmp(tmpword, "print") == 0) {
AVL_PrintMe(AVLTree1);
} else
if (strcmp(tmpword, "save") == 0) {
AVL_SaveTree(AVLTree1, true);
} else
if (strcmp(tmpword, "load") == 0) {
AVL_LoadTree(AVLTree1, true);
}
break;
// Удаление слова
case '-':
// Считываем слово
scanf("%s", tmpword);
// Преобразование в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Удаляем лист
AVL_RemoveLeaf(tmpword, AVLTree1, true);
break;
// Заглушка
case 'n':
break;
// Осталось слово
default:
for (i = 0; i < StringLengthPS; i++) tmpchar[i] = tolower(tmpchar[i]);
// Поиск
tmpkey = AVL_FindMe_p(tmpchar, AVLTree1, true);
break;
}
}
return 0;
}
// Печать ошибок
void PrintError(unsigned short int ErrorCode){
}
AVL_tree_slimrg.h
#ifndef AVL_tree_slimrg_h
#define AVL_tree_slimrg_h
// Стандартные заголовки
#include <stdbool.h>
#include <string.h>
// Настройки
#include "settings_slimrg.h"
// Сама структура
struct avltree;
// Создание дерева
struct avltree* AVL_Create();
// Уничтожение дерева
void AVL_FreeAndNil(struct avltree* AVL_Tree);
// Проверка на пустоту
bool AVL_IsEmpty(struct avltree* AVL_Tree);
// Добавить лист
void AVL_InsertLeaf(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVL_Tree, bool PrintStatus);
// Удаление листа по значению
void AVL_RemoveLeaf(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus);
// Поиск значения
bool AVL_FindMe(char key[StringLengthPS+1], struct avltree* AVL_Tree);
unsigned long long int AVL_FindMe_p(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus);
// Печать дерева
void AVL_PrintMe(struct avltree* AVL_Tree);
// Сохранение дерева
void AVL_SaveTree(struct avltree* AVL_Tree, bool PrintStatus);
// Загрузка дерева
void AVL_LoadTree(struct avltree* AVL_Tree, bool PrintStatus);
#endif
AVL_tree_slimrg.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "AVL_tree_slimrg.h"
// Структура строки
struct String{
char* Text;
unsigned short int count;
};
// Структура листа
struct avlleaf {
struct String key; // Ключ
unsigned long long int llupar; // Значение
long int height; // Высота
struct avlleaf* left; // Левый ребенок
struct avlleaf* right; // Правый ребенок
};
// Структура дерева
struct avltree {
struct avlleaf* root;
};
// Создание дерева
struct avltree* AVL_Create() {
struct avltree* AVL_Tree = malloc(sizeof(struct avltree));
AVL_Tree->root = NULL;
return AVL_Tree;
}
// Уничтожение дерева
void AVL_FreeAndNil(struct avltree* AVL_Tree) {
// Переменные
char tmpword[StringLengthPS+1];
unsigned short int i; // Тикер (для циклов и т.д.)
// Запускаем балалайку ^_^
while (AVL_IsEmpty(AVL_Tree) == false) {
for (i = 0; i <= AVL_Tree->root->key.count; i++) {
tmpword[i] = AVL_Tree->root->key.Text[i];
}
AVL_RemoveLeaf(tmpword, AVL_Tree, false);
}
}
// Проверка на пустоту
bool AVL_IsEmpty(struct avltree* AVL_Tree) {
return (AVL_Tree->root == NULL);
}
// Инициализация листа
struct avlleaf* AVLLeaf_Create(char inputkey[StringLengthPS+1], unsigned long long int llupar) {
// Переменные
struct avlleaf* keim; // Лист
unsigned short int i; // Тикер (для циклов и т.д.)
// Начальная инициализация
keim = malloc(sizeof(struct avlleaf));
keim->right = keim->left = NULL;
keim->llupar = llupar;
// Сложная инициализация
i = 0;
while (inputkey[i] != 0) i++;
keim->key.count = i;
keim->key.Text = malloc(keim->key.count * sizeof(char));
for (i = 0; i <= keim->key.count; i++) {
keim->key.Text[i] = inputkey[i];
}
keim->height = 0;
return keim;
}
// Получение высоты листа
long int AVLLeaf_GetHeight(struct avlleaf* Leaf) {
if (Leaf == NULL) return (-1); else return Leaf->height;
}
// Получение коэффицента балансировки
char AVLLeaf_GetBalance(struct avlleaf* Leaf) {
return (AVLLeaf_GetHeight(Leaf->right) - AVLLeaf_GetHeight(Leaf->left));
}
// Проверка высоты
void AVLLeaf_CheckHeight(struct avlleaf* Leaf) {
// Переменные
long int left, right; // Дети листа Leaf
left = AVLLeaf_GetHeight(Leaf->left);
right = AVLLeaf_GetHeight(Leaf->right);
// Высота получается увеличением максимальной детской высоты на единицу
if (left <= right) Leaf->height = right + 1; else Leaf->height = left + 1;
}
// Малое леве вращение (Small Left)
struct avlleaf* AVL_rotation_SL(struct avlleaf* Leaf) {
// Переменные
struct avlleaf* aor; // Ось вращения (Axis Of Rotation)
aor = Leaf->right;
// Магия вращения... (Вжух...)
Leaf->right = aor->left;
aor->left = Leaf;
// Выправляем высоту
AVLLeaf_CheckHeight(Leaf);
AVLLeaf_CheckHeight(aor);
return aor;
}
// Малое правое вращение (Small Right)
struct avlleaf* AVL_rotation_SR(struct avlleaf* Leaf) {
// Переменные
struct avlleaf* aor; // Ось вращения (Axis Of Rotation)
aor = Leaf->left;
// Магия вращения... (Вжух...)
Leaf->left = aor->right;
aor->right = Leaf;
// Выправляем высоту
AVLLeaf_CheckHeight(Leaf);
AVLLeaf_CheckHeight(aor);
return aor;
}
// Ребалансировка дерева
struct avlleaf* AVL_BalanceMe(struct avlleaf* Leaf) {
// Переменные
char balfac; // Коэффицент баласировки (от -2 до +2)
balfac = AVLLeaf_GetBalance(Leaf);
// Оцениваем баланс и выправляем его
if (balfac < -1) {
// Смотрим, требуется ли большое вращение
if (AVLLeaf_GetBalance(Leaf->left) > 0) {
Leaf->left = AVL_rotation_SL(Leaf->left);
}
return (AVL_rotation_SR(Leaf));
} else if (balfac > 1) {
// Смотрим, требуется ли большое вращение
if (AVLLeaf_GetBalance(Leaf->right) < 0) {
Leaf->right = AVL_rotation_SR(Leaf->right);
}
return (AVL_rotation_SL(Leaf));
} else { // Если нуль
// Вращение НЕ требуется
AVLLeaf_CheckHeight(Leaf);
return Leaf;
}
}
// Поиск места вставки и вставка
struct avlleaf* AVL_FindAndInsert(char key[StringLengthPS+1], unsigned long long int llupar, struct avlleaf* Leaf, bool PrintStatus) {
// Если поддерево пустое
if (Leaf == NULL) {
if (PrintStatus) printf("OKn");
return AVLLeaf_Create(key, llupar);
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndInsert(key, llupar, Leaf->left, PrintStatus);
} else if (strcmp(key, Leaf->key.Text) > 0){
Leaf->right = AVL_FindAndInsert(key, llupar, Leaf->right, PrintStatus);
} else {
if (PrintStatus) printf("Existn");
}
return AVL_BalanceMe(Leaf);
}
// Добавление листа (обертка над функцией выше)
void AVL_InsertLeaf(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVLTree, bool PrintStatus) {
AVLTree->root = AVL_FindAndInsert(key, llupar, AVLTree->root, PrintStatus);
}
// Получение минимального значения
struct String AVL_GetMinKey(struct avlleaf* Leaf) {
while (Leaf->left != NULL) Leaf = Leaf->left;
return Leaf->key;
}
// Получение параметра у листа с минимальным значением
unsigned long long int AVL_GetMinVal(struct avlleaf* Leaf) {
while (Leaf->left != NULL) Leaf = Leaf->left;
return Leaf->llupar;
}
// Поиск и удаление
struct avlleaf* AVL_FindAndRemove(char key[StringLengthPS+1], struct avlleaf* Leaf, bool PrintStatus) {
// Переменные
struct avlleaf* child; // Служебная (для случаев с одним ребенком)
char tmpkey[StringLengthPS+1]; // Временный контейнер для ключа
unsigned short int i; // Тикер (для циклов и т.д.)
if (Leaf == NULL) {
// Нет значения для удаления
if (PrintStatus) printf("NoSuchWordn");
return NULL;
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndRemove(key, Leaf->left, PrintStatus);
return AVL_BalanceMe(Leaf);
} else if (strcmp(key, Leaf->key.Text) > 0) {
Leaf->right = AVL_FindAndRemove(key, Leaf->right, PrintStatus);
return AVL_BalanceMe(Leaf);
} else { // Найдена позиция
if (PrintStatus) printf("OKn");
// Анализ детей и перемещение
if (Leaf->left != NULL && Leaf->right != NULL) {
Leaf->key = AVL_GetMinKey(Leaf->right);
Leaf->llupar = AVL_GetMinVal(Leaf->right);
for (i = 0; i <= Leaf->key.count; i++) {
tmpkey[i] = Leaf->key.Text[i];
}
Leaf->right = AVL_FindAndRemove(tmpkey, Leaf->right, PrintStatus);
return AVL_BalanceMe(Leaf);
} else if (Leaf->left != NULL) {
// Есть только один ребенок (правый)
child = Leaf->left;
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return child;
} else if (Leaf->right != NULL) {
// Есть только один ребенок (левый)
child = Leaf->right;
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return child;
} else {
// Нет дитей - просто выкидываем
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return NULL;
}
}
}
// Удаление из дерева (обертка над функцией выше)
void AVL_RemoveLeaf(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus) {
AVL_Tree->root = AVL_FindAndRemove(key, AVL_Tree->root, PrintStatus);
}
// Поиск элемента в дереве
bool AVL_FindMe(char key[StringLengthPS+1], struct avltree* AVL_Tree) {
// Переменные
struct avlleaf* CuP;
CuP = AVL_Tree->root;
while (CuP != NULL) {
if (strcmp (key, CuP->key.Text) == 0) {
return true;
} else if (strcmp(key, CuP->key.Text) < 0) {
CuP = CuP->left;
} else {
CuP = CuP->right;
}
}
return false;
}
// Еще один алгоритм поиска (удобнее для пользователя)
unsigned long long int AVL_FindMe_p(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
struct avlleaf* CuP;
CuP = AVL_Tree->root;
while (CuP != NULL) {
if (strcmp (key, CuP->key.Text) == 0) {
if (PrintStatus){
printf("OK: ");
printf("%llu", (CuP->llupar));
printf("n");
}
return CuP->llupar;
} else if (strcmp(key, CuP->key.Text) < 0) {
CuP = CuP->left;
} else {
CuP = CuP->right;
}
}
if (PrintStatus) printf("NoSuchWordn");
return 0;
}
// Печать дерева
void AVL_print_rec(struct avlleaf* Leaf, long int lvl) {
// Переменные
int i;
if (Leaf == NULL) {
return;
}
AVL_print_rec(Leaf->left, lvl + 1);
for (i = 0; i < lvl; i++) printf("t");
printf("%s", Leaf->key.Text);
printf("%c", '|');
printf("%llu", Leaf->llupar);
printf("n");
AVL_print_rec(Leaf->right, lvl + 1);
}
// Печать дерева (обертка над функцией выше)
void AVL_PrintMe(struct avltree* AVL_Tree){
if (AVL_Tree->root == NULL) {
printf("EMPTYn");
} else {
AVL_print_rec(AVL_Tree->root, 0);
}
}
// Запись лист в файл
void AVL_LeafToFile(struct avlleaf* Leaf, FILE * file){
if (Leaf == NULL) return;
fwrite(&(Leaf->key.count), sizeof(unsigned short int), 1, file);
fwrite(Leaf->key.Text, sizeof(char), Leaf->key.count+1, file);
fwrite(&(Leaf->llupar), sizeof(unsigned long long int), 1, file);
AVL_LeafToFile(Leaf->right, file);
AVL_LeafToFile(Leaf->left, file);
}
// Сохранение дерева
void AVL_SaveTree(struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
char adress[1024];
FILE *file = NULL;
// Открытие файла
scanf("%s", adress);
file = fopen(adress, "wb+");
if ((file == NULL)&&(PrintStatus)) printf("ERROR: Couldn't create filen");
if (file == NULL) return;
// Запись дерева
fwrite(&(UnCo), sizeof(unsigned long long int), 1, file);
AVL_LeafToFile(AVL_Tree->root, file);
// Закрытие
if (PrintStatus) printf("OKn");
fclose(file);
}
// Поиск места вставки и вставка
struct avlleaf* AVL_FindAndInsert_clean(char key[StringLengthPS+1], unsigned long long int llupar, struct avlleaf* Leaf, bool PrintStatus) {
// Если поддерево пустое
if (Leaf == NULL) {
return AVLLeaf_Create(key, llupar);
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndInsert_clean(key, llupar, Leaf->left, PrintStatus);
} else if (strcmp(key, Leaf->key.Text) > 0){
Leaf->right = AVL_FindAndInsert_clean(key, llupar, Leaf->right, PrintStatus);
} else {
if (PrintStatus) printf("ERROR: Broken Filen");
}
return Leaf;
}
// Добавление листа (обертка над функцией выше)
void AVL_InsertLeaf_clean(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVLTree, bool PrintStatus) {
AVLTree->root = AVL_FindAndInsert_clean(key, llupar, AVLTree->root, PrintStatus);
}
// Загрузка листа из файла
void AVL_LeafFromFile(struct avltree* AVL_Tree, FILE * file){
// Переменные
char tmpkey[StringLengthPS+1];
unsigned long long int tmpllupar;
unsigned short int charcount;
while (feof(file) == 0){
fread(&charcount, sizeof(unsigned short int), 1, file);
fread(tmpkey, sizeof(char), charcount+1, file);
fread(&tmpllupar, sizeof(unsigned long long int), 1, file);
AVL_InsertLeaf_clean(tmpkey, tmpllupar, AVL_Tree, false);
}
}
// Загрузка дерева
void AVL_LoadTree(struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
char adress[1024];
FILE *file = NULL;
unsigned long long int FileUnCo;
// Открытие файла
scanf("%s", adress);
file = fopen(adress, "rb");
if ((file == NULL)&&(PrintStatus)) printf("ERROR: Couldn't read filen");
if (file == NULL) return;
// Тест совместимости
fread(&FileUnCo, sizeof(unsigned long long int), 1, file);
if (UnCo != FileUnCo){
printf("ERROR: Unsupported filen");
return;
}
// Уничтожаем ранее созданное дерево
AVL_FreeAndNil(AVL_Tree);
// Загружаем новое дерево
AVL_LeafFromFile(AVL_Tree, file);
// Закрытие
if (PrintStatus) printf("OKn");
fclose(file);
}
settings_slimrg.h
#ifndef settings_h
#define settings_h
/* Settings */
// Настройка ввода
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
// Настройка отладки
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
// Номер сборки
const unsigned long long int UnCo = 115700744534137162;
#endif
MakeFile
all:
gcc -pedantic -Wall -std=c99 -Werror -Wno-sign-compare main.c AVL_tree_slimrg.c -lm -o lb2
Лог (здесь main.c заменен на lb2.c)
gcc -pedantic -Wall -std=c99 -Werror -Wno-sign-compare lb2.c AVL_tree_slimrg.c -lm -o lb2
/tmp/cc4upHwG.o:(.rodata+0x0): multiple definition of `StringLengthPS'
/tmp/ccORqDAb.o:(.rodata+0x0): first defined here
/tmp/cc4upHwG.o:(.rodata+0x4): multiple definition of `debug_pauseonclose'
/tmp/ccORqDAb.o:(.rodata+0x4): first defined here
/tmp/cc4upHwG.o:(.rodata+0x8): multiple definition of `UnCo'
/tmp/ccORqDAb.o:(.rodata+0x8): first defined here
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
c компиляция
Сделал вроде все нормально, но вот ругается
В проекте 4е файла:
main.c
/*
Программу подготовил: Буренков Игорь (М8О-206Б-17)
Вариант: АВЛ-дерево
*/
/////////////////////////////////////////////////////////
/* Системные библиотеки */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
/* Пользовательские библиотеки */
#include "AVL_tree_slimrg.h"
#include "settings_slimrg.h"
/* Структуры */
/* Сигнатуры функций */
unsigned short int InputFiller(); // Ввод и исполнение комманд
void PrintError(unsigned short int ErrorCode); // Вывод ошибок
/* Основной цикл */
int main(){
// Переменные
unsigned short int log_error; // Код ошибки
// Считываем и выполняем команды
log_error = InputFiller();
// Выввод ошибки
PrintError(log_error);
// Пауза при закрытии
if (debug_pauseonclose) system("pause");
// Все ОК
return 0;
}
// Цикл ввода и выполнения
unsigned short int InputFiller(){
// Переменные
char tmpchar[StringLengthPS+1]; // Временный контейнер для символа
char tmpword[StringLengthPS+1]; // Временный контейнер для слова (массива символов)
unsigned long long int tmpkey; // Временный контейнер для ключа
unsigned char errorcode; // Код ошибки
unsigned int i; // Тикер (для циклов и т.д.)
// Создание пустого дерева
struct avltree* AVLTree1 = AVL_Create();
// Пока возможно - считываем первый символ строки
while (scanf("%s", tmpchar) >= 1){
// Перевод в нижний регистр
tmpchar[0] = tolower(tmpchar[0]);
// Определение комманды
switch (tmpchar[0]) {
// Добавить слово
case '+':
// Считываем слово
scanf("%s", tmpword);
// Преобразование в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Считывание ключа
scanf("%llu", &tmpkey);
// Довавляем лист (с включенным выводом)
AVL_InsertLeaf(tmpword, tmpkey, AVLTree1, true);
break;
// Отладочные комманды
case '!':
// Считываем слово
scanf("%s", tmpword);
// Перевод в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Распознание слова
if (strcmp(tmpword, "exit") == 0) {
return 0;
} else
if (strcmp(tmpword, "print") == 0) {
AVL_PrintMe(AVLTree1);
} else
if (strcmp(tmpword, "save") == 0) {
AVL_SaveTree(AVLTree1, true);
} else
if (strcmp(tmpword, "load") == 0) {
AVL_LoadTree(AVLTree1, true);
}
break;
// Удаление слова
case '-':
// Считываем слово
scanf("%s", tmpword);
// Преобразование в нижний регистр
for (i = 0; i < StringLengthPS; i++) tmpword[i] = tolower(tmpword[i]);
// Удаляем лист
AVL_RemoveLeaf(tmpword, AVLTree1, true);
break;
// Заглушка
case 'n':
break;
// Осталось слово
default:
for (i = 0; i < StringLengthPS; i++) tmpchar[i] = tolower(tmpchar[i]);
// Поиск
tmpkey = AVL_FindMe_p(tmpchar, AVLTree1, true);
break;
}
}
return 0;
}
// Печать ошибок
void PrintError(unsigned short int ErrorCode){
}
AVL_tree_slimrg.h
#ifndef AVL_tree_slimrg_h
#define AVL_tree_slimrg_h
// Стандартные заголовки
#include <stdbool.h>
#include <string.h>
// Настройки
#include "settings_slimrg.h"
// Сама структура
struct avltree;
// Создание дерева
struct avltree* AVL_Create();
// Уничтожение дерева
void AVL_FreeAndNil(struct avltree* AVL_Tree);
// Проверка на пустоту
bool AVL_IsEmpty(struct avltree* AVL_Tree);
// Добавить лист
void AVL_InsertLeaf(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVL_Tree, bool PrintStatus);
// Удаление листа по значению
void AVL_RemoveLeaf(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus);
// Поиск значения
bool AVL_FindMe(char key[StringLengthPS+1], struct avltree* AVL_Tree);
unsigned long long int AVL_FindMe_p(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus);
// Печать дерева
void AVL_PrintMe(struct avltree* AVL_Tree);
// Сохранение дерева
void AVL_SaveTree(struct avltree* AVL_Tree, bool PrintStatus);
// Загрузка дерева
void AVL_LoadTree(struct avltree* AVL_Tree, bool PrintStatus);
#endif
AVL_tree_slimrg.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "AVL_tree_slimrg.h"
// Структура строки
struct String{
char* Text;
unsigned short int count;
};
// Структура листа
struct avlleaf {
struct String key; // Ключ
unsigned long long int llupar; // Значение
long int height; // Высота
struct avlleaf* left; // Левый ребенок
struct avlleaf* right; // Правый ребенок
};
// Структура дерева
struct avltree {
struct avlleaf* root;
};
// Создание дерева
struct avltree* AVL_Create() {
struct avltree* AVL_Tree = malloc(sizeof(struct avltree));
AVL_Tree->root = NULL;
return AVL_Tree;
}
// Уничтожение дерева
void AVL_FreeAndNil(struct avltree* AVL_Tree) {
// Переменные
char tmpword[StringLengthPS+1];
unsigned short int i; // Тикер (для циклов и т.д.)
// Запускаем балалайку ^_^
while (AVL_IsEmpty(AVL_Tree) == false) {
for (i = 0; i <= AVL_Tree->root->key.count; i++) {
tmpword[i] = AVL_Tree->root->key.Text[i];
}
AVL_RemoveLeaf(tmpword, AVL_Tree, false);
}
}
// Проверка на пустоту
bool AVL_IsEmpty(struct avltree* AVL_Tree) {
return (AVL_Tree->root == NULL);
}
// Инициализация листа
struct avlleaf* AVLLeaf_Create(char inputkey[StringLengthPS+1], unsigned long long int llupar) {
// Переменные
struct avlleaf* keim; // Лист
unsigned short int i; // Тикер (для циклов и т.д.)
// Начальная инициализация
keim = malloc(sizeof(struct avlleaf));
keim->right = keim->left = NULL;
keim->llupar = llupar;
// Сложная инициализация
i = 0;
while (inputkey[i] != 0) i++;
keim->key.count = i;
keim->key.Text = malloc(keim->key.count * sizeof(char));
for (i = 0; i <= keim->key.count; i++) {
keim->key.Text[i] = inputkey[i];
}
keim->height = 0;
return keim;
}
// Получение высоты листа
long int AVLLeaf_GetHeight(struct avlleaf* Leaf) {
if (Leaf == NULL) return (-1); else return Leaf->height;
}
// Получение коэффицента балансировки
char AVLLeaf_GetBalance(struct avlleaf* Leaf) {
return (AVLLeaf_GetHeight(Leaf->right) - AVLLeaf_GetHeight(Leaf->left));
}
// Проверка высоты
void AVLLeaf_CheckHeight(struct avlleaf* Leaf) {
// Переменные
long int left, right; // Дети листа Leaf
left = AVLLeaf_GetHeight(Leaf->left);
right = AVLLeaf_GetHeight(Leaf->right);
// Высота получается увеличением максимальной детской высоты на единицу
if (left <= right) Leaf->height = right + 1; else Leaf->height = left + 1;
}
// Малое леве вращение (Small Left)
struct avlleaf* AVL_rotation_SL(struct avlleaf* Leaf) {
// Переменные
struct avlleaf* aor; // Ось вращения (Axis Of Rotation)
aor = Leaf->right;
// Магия вращения... (Вжух...)
Leaf->right = aor->left;
aor->left = Leaf;
// Выправляем высоту
AVLLeaf_CheckHeight(Leaf);
AVLLeaf_CheckHeight(aor);
return aor;
}
// Малое правое вращение (Small Right)
struct avlleaf* AVL_rotation_SR(struct avlleaf* Leaf) {
// Переменные
struct avlleaf* aor; // Ось вращения (Axis Of Rotation)
aor = Leaf->left;
// Магия вращения... (Вжух...)
Leaf->left = aor->right;
aor->right = Leaf;
// Выправляем высоту
AVLLeaf_CheckHeight(Leaf);
AVLLeaf_CheckHeight(aor);
return aor;
}
// Ребалансировка дерева
struct avlleaf* AVL_BalanceMe(struct avlleaf* Leaf) {
// Переменные
char balfac; // Коэффицент баласировки (от -2 до +2)
balfac = AVLLeaf_GetBalance(Leaf);
// Оцениваем баланс и выправляем его
if (balfac < -1) {
// Смотрим, требуется ли большое вращение
if (AVLLeaf_GetBalance(Leaf->left) > 0) {
Leaf->left = AVL_rotation_SL(Leaf->left);
}
return (AVL_rotation_SR(Leaf));
} else if (balfac > 1) {
// Смотрим, требуется ли большое вращение
if (AVLLeaf_GetBalance(Leaf->right) < 0) {
Leaf->right = AVL_rotation_SR(Leaf->right);
}
return (AVL_rotation_SL(Leaf));
} else { // Если нуль
// Вращение НЕ требуется
AVLLeaf_CheckHeight(Leaf);
return Leaf;
}
}
// Поиск места вставки и вставка
struct avlleaf* AVL_FindAndInsert(char key[StringLengthPS+1], unsigned long long int llupar, struct avlleaf* Leaf, bool PrintStatus) {
// Если поддерево пустое
if (Leaf == NULL) {
if (PrintStatus) printf("OKn");
return AVLLeaf_Create(key, llupar);
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndInsert(key, llupar, Leaf->left, PrintStatus);
} else if (strcmp(key, Leaf->key.Text) > 0){
Leaf->right = AVL_FindAndInsert(key, llupar, Leaf->right, PrintStatus);
} else {
if (PrintStatus) printf("Existn");
}
return AVL_BalanceMe(Leaf);
}
// Добавление листа (обертка над функцией выше)
void AVL_InsertLeaf(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVLTree, bool PrintStatus) {
AVLTree->root = AVL_FindAndInsert(key, llupar, AVLTree->root, PrintStatus);
}
// Получение минимального значения
struct String AVL_GetMinKey(struct avlleaf* Leaf) {
while (Leaf->left != NULL) Leaf = Leaf->left;
return Leaf->key;
}
// Получение параметра у листа с минимальным значением
unsigned long long int AVL_GetMinVal(struct avlleaf* Leaf) {
while (Leaf->left != NULL) Leaf = Leaf->left;
return Leaf->llupar;
}
// Поиск и удаление
struct avlleaf* AVL_FindAndRemove(char key[StringLengthPS+1], struct avlleaf* Leaf, bool PrintStatus) {
// Переменные
struct avlleaf* child; // Служебная (для случаев с одним ребенком)
char tmpkey[StringLengthPS+1]; // Временный контейнер для ключа
unsigned short int i; // Тикер (для циклов и т.д.)
if (Leaf == NULL) {
// Нет значения для удаления
if (PrintStatus) printf("NoSuchWordn");
return NULL;
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndRemove(key, Leaf->left, PrintStatus);
return AVL_BalanceMe(Leaf);
} else if (strcmp(key, Leaf->key.Text) > 0) {
Leaf->right = AVL_FindAndRemove(key, Leaf->right, PrintStatus);
return AVL_BalanceMe(Leaf);
} else { // Найдена позиция
if (PrintStatus) printf("OKn");
// Анализ детей и перемещение
if (Leaf->left != NULL && Leaf->right != NULL) {
Leaf->key = AVL_GetMinKey(Leaf->right);
Leaf->llupar = AVL_GetMinVal(Leaf->right);
for (i = 0; i <= Leaf->key.count; i++) {
tmpkey[i] = Leaf->key.Text[i];
}
Leaf->right = AVL_FindAndRemove(tmpkey, Leaf->right, PrintStatus);
return AVL_BalanceMe(Leaf);
} else if (Leaf->left != NULL) {
// Есть только один ребенок (правый)
child = Leaf->left;
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return child;
} else if (Leaf->right != NULL) {
// Есть только один ребенок (левый)
child = Leaf->right;
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return child;
} else {
// Нет дитей - просто выкидываем
Leaf->key.count = 0;
free(Leaf->key.Text);
free(Leaf);
return NULL;
}
}
}
// Удаление из дерева (обертка над функцией выше)
void AVL_RemoveLeaf(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus) {
AVL_Tree->root = AVL_FindAndRemove(key, AVL_Tree->root, PrintStatus);
}
// Поиск элемента в дереве
bool AVL_FindMe(char key[StringLengthPS+1], struct avltree* AVL_Tree) {
// Переменные
struct avlleaf* CuP;
CuP = AVL_Tree->root;
while (CuP != NULL) {
if (strcmp (key, CuP->key.Text) == 0) {
return true;
} else if (strcmp(key, CuP->key.Text) < 0) {
CuP = CuP->left;
} else {
CuP = CuP->right;
}
}
return false;
}
// Еще один алгоритм поиска (удобнее для пользователя)
unsigned long long int AVL_FindMe_p(char key[StringLengthPS+1], struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
struct avlleaf* CuP;
CuP = AVL_Tree->root;
while (CuP != NULL) {
if (strcmp (key, CuP->key.Text) == 0) {
if (PrintStatus){
printf("OK: ");
printf("%llu", (CuP->llupar));
printf("n");
}
return CuP->llupar;
} else if (strcmp(key, CuP->key.Text) < 0) {
CuP = CuP->left;
} else {
CuP = CuP->right;
}
}
if (PrintStatus) printf("NoSuchWordn");
return 0;
}
// Печать дерева
void AVL_print_rec(struct avlleaf* Leaf, long int lvl) {
// Переменные
int i;
if (Leaf == NULL) {
return;
}
AVL_print_rec(Leaf->left, lvl + 1);
for (i = 0; i < lvl; i++) printf("t");
printf("%s", Leaf->key.Text);
printf("%c", '|');
printf("%llu", Leaf->llupar);
printf("n");
AVL_print_rec(Leaf->right, lvl + 1);
}
// Печать дерева (обертка над функцией выше)
void AVL_PrintMe(struct avltree* AVL_Tree){
if (AVL_Tree->root == NULL) {
printf("EMPTYn");
} else {
AVL_print_rec(AVL_Tree->root, 0);
}
}
// Запись лист в файл
void AVL_LeafToFile(struct avlleaf* Leaf, FILE * file){
if (Leaf == NULL) return;
fwrite(&(Leaf->key.count), sizeof(unsigned short int), 1, file);
fwrite(Leaf->key.Text, sizeof(char), Leaf->key.count+1, file);
fwrite(&(Leaf->llupar), sizeof(unsigned long long int), 1, file);
AVL_LeafToFile(Leaf->right, file);
AVL_LeafToFile(Leaf->left, file);
}
// Сохранение дерева
void AVL_SaveTree(struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
char adress[1024];
FILE *file = NULL;
// Открытие файла
scanf("%s", adress);
file = fopen(adress, "wb+");
if ((file == NULL)&&(PrintStatus)) printf("ERROR: Couldn't create filen");
if (file == NULL) return;
// Запись дерева
fwrite(&(UnCo), sizeof(unsigned long long int), 1, file);
AVL_LeafToFile(AVL_Tree->root, file);
// Закрытие
if (PrintStatus) printf("OKn");
fclose(file);
}
// Поиск места вставки и вставка
struct avlleaf* AVL_FindAndInsert_clean(char key[StringLengthPS+1], unsigned long long int llupar, struct avlleaf* Leaf, bool PrintStatus) {
// Если поддерево пустое
if (Leaf == NULL) {
return AVLLeaf_Create(key, llupar);
} else if (strcmp(key, Leaf->key.Text) < 0) {
Leaf->left = AVL_FindAndInsert_clean(key, llupar, Leaf->left, PrintStatus);
} else if (strcmp(key, Leaf->key.Text) > 0){
Leaf->right = AVL_FindAndInsert_clean(key, llupar, Leaf->right, PrintStatus);
} else {
if (PrintStatus) printf("ERROR: Broken Filen");
}
return Leaf;
}
// Добавление листа (обертка над функцией выше)
void AVL_InsertLeaf_clean(char key[StringLengthPS+1], unsigned long long int llupar, struct avltree* AVLTree, bool PrintStatus) {
AVLTree->root = AVL_FindAndInsert_clean(key, llupar, AVLTree->root, PrintStatus);
}
// Загрузка листа из файла
void AVL_LeafFromFile(struct avltree* AVL_Tree, FILE * file){
// Переменные
char tmpkey[StringLengthPS+1];
unsigned long long int tmpllupar;
unsigned short int charcount;
while (feof(file) == 0){
fread(&charcount, sizeof(unsigned short int), 1, file);
fread(tmpkey, sizeof(char), charcount+1, file);
fread(&tmpllupar, sizeof(unsigned long long int), 1, file);
AVL_InsertLeaf_clean(tmpkey, tmpllupar, AVL_Tree, false);
}
}
// Загрузка дерева
void AVL_LoadTree(struct avltree* AVL_Tree, bool PrintStatus){
// Переменные
char adress[1024];
FILE *file = NULL;
unsigned long long int FileUnCo;
// Открытие файла
scanf("%s", adress);
file = fopen(adress, "rb");
if ((file == NULL)&&(PrintStatus)) printf("ERROR: Couldn't read filen");
if (file == NULL) return;
// Тест совместимости
fread(&FileUnCo, sizeof(unsigned long long int), 1, file);
if (UnCo != FileUnCo){
printf("ERROR: Unsupported filen");
return;
}
// Уничтожаем ранее созданное дерево
AVL_FreeAndNil(AVL_Tree);
// Загружаем новое дерево
AVL_LeafFromFile(AVL_Tree, file);
// Закрытие
if (PrintStatus) printf("OKn");
fclose(file);
}
settings_slimrg.h
#ifndef settings_h
#define settings_h
/* Settings */
// Настройка ввода
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
// Настройка отладки
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
// Номер сборки
const unsigned long long int UnCo = 115700744534137162;
#endif
MakeFile
all:
gcc -pedantic -Wall -std=c99 -Werror -Wno-sign-compare main.c AVL_tree_slimrg.c -lm -o lb2
Лог (здесь main.c заменен на lb2.c)
gcc -pedantic -Wall -std=c99 -Werror -Wno-sign-compare lb2.c AVL_tree_slimrg.c -lm -o lb2
/tmp/cc4upHwG.o:(.rodata+0x0): multiple definition of `StringLengthPS'
/tmp/ccORqDAb.o:(.rodata+0x0): first defined here
/tmp/cc4upHwG.o:(.rodata+0x4): multiple definition of `debug_pauseonclose'
/tmp/ccORqDAb.o:(.rodata+0x4): first defined here
/tmp/cc4upHwG.o:(.rodata+0x8): multiple definition of `UnCo'
/tmp/ccORqDAb.o:(.rodata+0x8): first defined here
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
c компиляция
c компиляция
изменён 4 мар в 13:37
aleksandr barakin
55.5k1343166
55.5k1343166
задан 4 мар в 12:15
Alrott SlimRGAlrott SlimRG
41613
41613
добавить комментарий |
добавить комментарий |
2 ответа
2
текущие
по дате публикации
голоса
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
const unsigned long long int UnCo = 115700744534137162;
Раз у вас константы в хедере, то они копируются в каждый .c файл, который этот хедер инклудит - отсюда multiple definition
.
Решение:
Либо сделать переменные static
- тогда каждый файл получит свою копию каждой переменной,
либо заменить переменные на #define
.
добавить комментарий |
В отличие от С++, в языке С const
объекты имеют внешнее связывание по умолчанию. Их нельзя определять в заголовочных файлах.
Либо явно придайте им внутреннее связывание, т.е. определяйте их как static const
, либо идите по традиционному пути: в заголовочный файл кладите, extern const
без инициализатора, а в один из .c
файлов кладите ваши определения.
В вашем случае можно также просто заменить ваши константы на макросы или enum.
добавить комментарий |
Ваш ответ
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "609"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "на платформе u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "Пользовательский контент попадает под действие u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003eлицензии cc by-sa 3.0u003c/au003e с u003ca href="https://stackoverflow.com/legal/content-policy"u003eуказанием ссылки на источникu003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Зарегистрируйтесь или войдите
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Регистрация через Google
Регистрация через Facebook
Регистрация через почту
Отправить без регистрации
Необходима, но никому не показывается
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fru.stackoverflow.com%2fquestions%2f952205%2fmultiple-definition-of%23new-answer', 'question_page');
}
);
Отправить без регистрации
Необходима, но никому не показывается
2 ответа
2
текущие
по дате публикации
голоса
2 ответа
2
текущие
по дате публикации
голоса
текущие
по дате публикации
голоса
текущие
по дате публикации
голоса
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
const unsigned long long int UnCo = 115700744534137162;
Раз у вас константы в хедере, то они копируются в каждый .c файл, который этот хедер инклудит - отсюда multiple definition
.
Решение:
Либо сделать переменные static
- тогда каждый файл получит свою копию каждой переменной,
либо заменить переменные на #define
.
добавить комментарий |
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
const unsigned long long int UnCo = 115700744534137162;
Раз у вас константы в хедере, то они копируются в каждый .c файл, который этот хедер инклудит - отсюда multiple definition
.
Решение:
Либо сделать переменные static
- тогда каждый файл получит свою копию каждой переменной,
либо заменить переменные на #define
.
добавить комментарий |
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
const unsigned long long int UnCo = 115700744534137162;
Раз у вас константы в хедере, то они копируются в каждый .c файл, который этот хедер инклудит - отсюда multiple definition
.
Решение:
Либо сделать переменные static
- тогда каждый файл получит свою копию каждой переменной,
либо заменить переменные на #define
.
const unsigned int StringLengthPS = 256; // Длина строки (в символах)
const bool debug_pauseonclose = true; // Следует ли делать паузу перед выходом
const unsigned long long int UnCo = 115700744534137162;
Раз у вас константы в хедере, то они копируются в каждый .c файл, который этот хедер инклудит - отсюда multiple definition
.
Решение:
Либо сделать переменные static
- тогда каждый файл получит свою копию каждой переменной,
либо заменить переменные на #define
.
ответ дан 4 мар в 12:33
HolyBlackCatHolyBlackCat
5,6241514
5,6241514
добавить комментарий |
добавить комментарий |
В отличие от С++, в языке С const
объекты имеют внешнее связывание по умолчанию. Их нельзя определять в заголовочных файлах.
Либо явно придайте им внутреннее связывание, т.е. определяйте их как static const
, либо идите по традиционному пути: в заголовочный файл кладите, extern const
без инициализатора, а в один из .c
файлов кладите ваши определения.
В вашем случае можно также просто заменить ваши константы на макросы или enum.
добавить комментарий |
В отличие от С++, в языке С const
объекты имеют внешнее связывание по умолчанию. Их нельзя определять в заголовочных файлах.
Либо явно придайте им внутреннее связывание, т.е. определяйте их как static const
, либо идите по традиционному пути: в заголовочный файл кладите, extern const
без инициализатора, а в один из .c
файлов кладите ваши определения.
В вашем случае можно также просто заменить ваши константы на макросы или enum.
добавить комментарий |
В отличие от С++, в языке С const
объекты имеют внешнее связывание по умолчанию. Их нельзя определять в заголовочных файлах.
Либо явно придайте им внутреннее связывание, т.е. определяйте их как static const
, либо идите по традиционному пути: в заголовочный файл кладите, extern const
без инициализатора, а в один из .c
файлов кладите ваши определения.
В вашем случае можно также просто заменить ваши константы на макросы или enum.
В отличие от С++, в языке С const
объекты имеют внешнее связывание по умолчанию. Их нельзя определять в заголовочных файлах.
Либо явно придайте им внутреннее связывание, т.е. определяйте их как static const
, либо идите по традиционному пути: в заголовочный файл кладите, extern const
без инициализатора, а в один из .c
файлов кладите ваши определения.
В вашем случае можно также просто заменить ваши константы на макросы или enum.
изменён 4 мар в 22:53
ответ дан 4 мар в 12:35
AnTAnT
50.3k33895
50.3k33895
добавить комментарий |
добавить комментарий |
Спасибо за ваш ответ на Stack Overflow на русском!
- Пожалуйста, убедитесь, что публикуемое сообщение отвечает на поставленный вопрос. Предоставьте как можно больше деталей, расскажите про проведенное исследование!
Но избегайте …
- Просьб помощи, уточнений или ответов на темы не относящиеся к вопросу.
- Ответов основанных на мнениях; приводите аргументы основанные только на реальном опыте.
Также, обратите внимание на заметку в справочном центре о том, как писать ответы.
Зарегистрируйтесь или войдите
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Регистрация через Google
Регистрация через Facebook
Регистрация через почту
Отправить без регистрации
Необходима, но никому не показывается
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fru.stackoverflow.com%2fquestions%2f952205%2fmultiple-definition-of%23new-answer', 'question_page');
}
);
Отправить без регистрации
Необходима, но никому не показывается
Зарегистрируйтесь или войдите
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Регистрация через Google
Регистрация через Facebook
Регистрация через почту
Отправить без регистрации
Необходима, но никому не показывается
Зарегистрируйтесь или войдите
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Регистрация через Google
Регистрация через Facebook
Регистрация через почту
Отправить без регистрации
Необходима, но никому не показывается
Зарегистрируйтесь или войдите
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Регистрация через Google
Регистрация через Facebook
Регистрация через почту
Регистрация через Google
Регистрация через Facebook
Регистрация через почту
Отправить без регистрации
Необходима, но никому не показывается
Необходима, но никому не показывается
Необходима, но никому не показывается
Необходима, но никому не показывается
Необходима, но никому не показывается
Необходима, но никому не показывается
Необходима, но никому не показывается
Необходима, но никому не показывается
Необходима, но никому не показывается