Drzewo binarne BST

0

Witajcie

Jako jeden z programów na zajęcia mam napisać program segregujący i wyświetlający faktury w kolejności rosnącej. Chciałbym najpierw mieć program,który korzysta ze struktury jaką jest drzewo.

Napisałem takie cos:

#include<stdio.h>
#include<stdlib.h>//do malloca
#include<string.h>//do strcmp

struct tree {
char *faktura;//uzywane jest przy drzewo->faktura
struct tree *lewy;
struct tree *prawy;
};


Zależy mi na tym,żeby zrozumieć mój błąd jaki popełniam i mam przez to naruszenie ochrony pamięci.

Serdecznie dziękuję za wszelaką pomoc i cenne wskazówki. 
struct tree *dodaj(struct tree *drzewo,char *nrfaktury)
{

    if(drzewo==NULL)
    {    
    drzewo=(struct tree*)malloc(sizeof(struct tree));
    drzewo->faktura=(char*)malloc(strlen(nrfaktury)); 
    strcpy(drzewo->faktura,nrfaktury);  //strcpy(strTO,strFrom)
    drzewo->lewy=NULL;
    drzewo->prawy=NULL;
    drzewo->faktura=nrfaktury;
    //return drzewo;
    }//if
    else
	{
	    if(strcmp(nrfaktury,(drzewo->faktura)<0))
	    {
	    drzewo->lewy=dodaj(drzewo->lewy,nrfaktury);
	    }
	    else 
	    {
	    drzewo->prawy=dodaj(drzewo->prawy,nrfaktury);
	    }
	}//else
return drzewo;
}//dodaj
/*void drukuj(struct tree *drzewo) {
int i;
    if(drzewo != NULL)
    {    
    drukuj(drzewo->lewy);
    printf("%c", drzewo->faktura);
    drukuj(drzewo->prawy);
    }
}*/
int main()
{
int n;//liczba faktur
scanf("%d",&n);
int i;
struct tree *drzewo=NULL;
char *numer;
for(i=0;i<n;i++)
{
scanf("%s",&numer);
dodaj(drzewo,numer);
//drukuj(drzewo);
}//for  
}//main 

Zależy mi na wyłapaniu i zrozumieniu gdzie popełniam błąd/błędy

Dziękuję za wszelaką pomoc i cenne wskazówki.
1

Tak na szybko:

drzewo=(struct tree*)malloc(sizeof(struct tree));
    drzewo->faktura=(char*)malloc(strlen(nrfaktury)); 
    strcpy(drzewo->faktura,nrfaktury);  //strcpy(strTO,strFrom)
    drzewo->lewy=NULL;
    drzewo->prawy=NULL;
    drzewo->faktura=nrfaktury;

Najpierw kopiujesz napis do drzewo->faktura, a potem do tego samego wskaźnika przypisujesz. Nie twierdzę, że to jedyny błąd.

1
djinsekt napisał(a):

Tak na szybko:

drzewo=(struct tree*)malloc(sizeof(struct tree));
    drzewo->faktura=(char*)malloc(strlen(nrfaktury)); 
    strcpy(drzewo->faktura,nrfaktury);  //strcpy(strTO,strFrom)
    drzewo->lewy=NULL;
    drzewo->prawy=NULL;
    drzewo->faktura=nrfaktury;

Absolutnie nie!

tak:

drzewo=(struct tree*)malloc(sizeof(struct tree));
    drzewo->faktura=(char*)malloc(strlen(nrfaktury)+1); // koniecznie +1 na znak końca napisu
    strcpy(drzewo->faktura,nrfaktury);
    drzewo->lewy=NULL;
    drzewo->prawy=NULL;

lub:

drzewo=(struct tree*)malloc(sizeof(struct tree));
    drzewo->faktura=strdup(nrfaktury);
    drzewo->lewy=NULL;
    drzewo->prawy=NULL;
1

Widzę jeszcze kilka problemów.

struct tree *drzewo=NULL;
//...
dodaj(drzewo,numer);

W ten sposób nie dodasz pierwszego elementu. Masz 2 możliwości. Pierwsza to umieścić jako korzeń drzewa stały "pusty" element który będzie tylko takim znacznikiem. Druga to przekazać wskaźnik korzenia przez referencję a nie przez wartość czyli albo podwójny wskaźnik:

dodaj(struct tree **drzewo, char *nrfaktury)

albo najlepiej osobna strukturka opisująca drzewo (a nie jego element) i przekazanie jej przez wskaźnik:

struct node {
    char *faktura;
    struct node *lewy;
    struct node *prawy;
};
 
struct tree {
    struct node *korzen;
};

struct node *dodaj(struct tree *drzewo, char *nrfaktury)...

aby można było nadpisać również korzeń drzewa.

Kolejny problem:

char *numer;
scanf("%s",&numer);
W ten sposób nie wczytuje się łańcuchów. Musisz najpierw utworzyć bufor (tablicę) na znaki. Np. tak:

char numer[50 + 1];
scanf("%50s", numer);

Dodatkowo funkcję dodającą można podzielić. Na funkcję szukającą (wykorzystasz ją w wielu miejscach - dodawanie, usuwanie, wyszukiwanie) i funkcję wstawiającą element.
Oprócz tego można przydzielać pamięć dla łańcucha razem z elementem drzewa.
No i pasuje również nie dodawać powtórzeń skoro to jakieś numery faktur.

Razem mi się zebrało coś takiego:

#include <stdio.h>
#include <stdlib.h> //do malloca
#include <string.h> //do strcmp
 
// osobna strukturka na drzewo, osobna na element drzewa
struct node {
    struct node *lewy;
    struct node *prawy;
 
    char faktura[]; // niech bufor znakowy będzie częścią struktury węzła
};

struct tree {
    struct node *korzen;
};

// wyszukuje wskaźnik prowadzący do elementu o zadanym numerze faktury lub jeśli tego elementu nie ma - miejsce w którym należałoby taki element wstawić
struct node **znajdz_wezel(struct node **wezel, char *nrfaktury)
{
    if (*wezel != NULL) {
        int cmp = strcmp(nrfaktury, (*wezel)->faktura);
        if (cmp < 0) return znajdz_wezel(&((*wezel)->lewy), nrfaktury);
        if (cmp > 0) return znajdz_wezel(&((*wezel)->prawy), nrfaktury);
    }
 
    return wezel;
}

// tylko utworzenie i wypełnienie elmentu
struct node *nowy_wezel(char *nrfaktury)
{
    // alokujemy pamięć na element + na bufor znakowy
    struct node *wezel = (struct node*)malloc(sizeof(struct node) + strlen(nrfaktury) + 1);
 
    wezel->lewy = NULL;
    wezel->prawy = NULL;
    strcpy(wezel->faktura, nrfaktury);
 
    return wezel;
}


// zwraca istniejącą fakturę lub dodaje nową do drzewa jeśli jeszcze jej nie ma
struct node *dodaj(struct tree *drzewo, char *nrfaktury)
{
    struct node **wezel = znajdz_wezel(&drzewo->korzen, nrfaktury);
    if (*wezel == NULL) *wezel = nowy_wezel(nrfaktury);
    return *wezel;
}
 
int main()
{
    int n; //liczba faktur
    scanf("%d", &n);
    int i;
 
    struct tree drzewo;
    memset(&drzewo, 0, sizeof(drzewo));
 
    char numer[50 + 1]; // bufor na wczytane scanf'em znaki
    for(i = 0; i < n; i++)
    {
        scanf("%50s", numer);
        dodaj(&drzewo, numer);
    }
    
    return 0;
}
0

Przepraszam za odgrzanie "starego kotleta". W końcu program zadziałał i pragnę podziękować wszystkim za cenne wskazówki. :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1