从二叉搜索树中搜索,插入,输出。

时间:2016-09-02 11:17:22

标签: c binary-search-tree

如何使用多个重复键和csv在一个程序中执行上述操作。输入数据文件?

1 个答案:

答案 0 :(得分:0)

编辑:假设为KEY "," DATA "\n"(为简洁起见没有空格)并在末尾附加一个简短的草图,以便OP有一个开始。

我无法修复它,因为我不知道输入,但我可以指出你做的一些错误。请参阅代码中的注释

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXNAMELENTH 64
#define MAXDATALENTH 1465

typedef struct node {
  char name[MAXNAMELENTH];
  char data[MAXDATALENTH];
  struct node *left;
  struct node *right;
} node;

node *root;
node *search(node ** tree, char *key, int count, FILE * fp_out);
node *insertion(node * r, char *key, char *value);
void deltree(node * tree);
char *strtok_r(char *str, const char *delim, char **nextp);


int main(int argc, char *argv[])
{
  node *root;
  node *tmp;
  FILE *fp;
  FILE *outputfile;
  FILE *keyfile;
  FILE *fp_key;
  int i;
  int counter = 0;
  int bufsize = MAXDATALENTH + MAXNAMELENTH;
  int keyfilelen = MAXNAMELENTH;
  char *keyread;
  char *buffer, *saveptr;
  char *line = NULL;
  char *keyin = NULL;
  char *valuein = NULL;
  char inputkey[MAXNAMELENTH];
  char *target_key = NULL;
  char *keyline = NULL;

  root = NULL;

  /* Inserting nodes into tree */
  buffer = (char *) malloc(bufsize * sizeof(char));
  if (buffer == NULL) {
    // use the proper macros, please
    exit(EXIT_FAILURE);
  }
  // Check outputs! Always check outputs!
  // I just assume that it has not been done here for simplicity
  // and fear of posting-size limits (limit is 30k IIRC, that's a lot of code)
  fp = fopen(argv[1], "r");
  outputfile = fopen("outputfile.txt", "a");

  // this is an infinite loop. How do you break out?
  while (1) {
    // fgets() returns NULL in case of EOF and error
    // (yes, both, so check, e.g.: with ferror())
    fgets(line, bufsize, fp);
    buffer = line;
    // I'm not fully sure, but I think you wanted a "=" instead of a ","
    // Please switch on warnings for your compiler
    keyin, strtok_r(buffer, ",", &saveptr);
    // NUL delimited? Really? Are you sure strtok_r() can handle it?
    valuein = strtok_r(NULL, "\0", &saveptr);
    // insertion() returns a node
    insertion(root, keyin, valuein);
  }


  /* Search node into tree */

  // Wrong type: keyfile is a filepointer (FILE *), not a string (char *)
  if (scanf("%s", keyfile) != EOF) {
    // hu? Please switch on warnings for your compiler
    keyfile = fopen(argv[4], "r");
    // where's keyfile? Gone?
    while ((fgets(keyline, keyfilelen, fp_key))) {
      keyread = strtok_r(keyline, "\n", &saveptr);
      search((&root), keyread, counter, outputfile);
    }
    // Please use braces, even here, thank you
    if (keyline) {
      free(keyline);
    }
    fclose(keyfile);
  }
  // This reads keys given as arguments at programstart, 
  // that's not what the teacher wanted
  for (i = 3; argv[i] != NULL; i++) {
    target_key = argv[i];
    search((&root), target_key, counter, outputfile);
  }

  // This program does not read from stdin.
  // Hint: stdin is also nothing more (although slightly less) than a file
  // but it is already open and you don't close it
  // (but it may not exist at all, so check first)

  /* Deleting all nodes of tree */
  deltree(root);

  fclose(fp);
  fclose(outputfile);
  return 0;
}

node *insertion(node * r, char *key, char *value)
{
  if (r == NULL)                // BST is not created created
  {
    r = (node *) malloc(sizeof(node));  // create a new node
    // insert data to new node
    strcpy(r->name, key);
    strcpy(r->data, value);
    // make left and right childs empty
    r->left = NULL;
    r->right = NULL;
  }
  // if the data is less than node value then we must put this in left sub-tree
  else if (strcmp(key, r->name) < 0) {
    r->left = insertion(r->left, key, value);
  }
  // else this will be in the right subtree
  else if (strcmp(key, r->name) > 0) {
    r->right = insertion(r->right, key, value);
  } else {
    if (strcmp(value, r->data) > 0) {
      r->left = insertion(r->left, key, value);
    } else if (strcmp(value, r->data) < 0) {
      r->right = insertion(r->right, key, value);
    }
    // what if both, name and data are equal?
  }
  // if you don't want to do anything with the returned
  // node than don't return it. Just an int indicating error
  // or something in the line
  return r;
}

void deltree(node * tree)
{
  if (tree) {
    deltree(tree->left);
    deltree(tree->right);
    free(tree);
  }
}

// searching does not compare the same way as inserting
node *search(node ** tree, char *key, int count, FILE * fp_out)
{
  if (!(*tree)) {
    return NULL;
  }
  if (strcmp(key, (*tree)->name) < 0) {
    search(&((*tree)->left), key, count, fp_out);
    count++;
  } else if (strcmp(key, (*tree)->name) > 0) {
    search(&((*tree)->right), key, count, fp_out);
    count++;
  } else if (strcmp(key, (*tree)->name) == 0) {
    // won't print anything, because you return before the printing
    return *tree;
    fprintf(fp_out, "%s --> %s\n", key, (*tree)->data);
  } else {
    fprintf(fp_out, "%s --> NOTFOUND", key);
  }
  printf("%s --> %s\n", key, count);
  // nothing to return here?
}
// Thank you for the proper reference!
// Seems to grow less and less usual these times.
/*
* public domain strtok_r() by Charlie Gordon
*
*   from comp.lang.c  9/14/2007
*
*      http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684
*
*     (Declaration that it's public domain):
*      http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c
*/

char *strtok_r(char *str, const char *delim, char **nextp)
{
  char *ret;
  if (str == NULL) {
    str = *nextp;
  }
  str += strspn(str, delim);
  if (*str == '\0') {
    return NULL;
  }
  ret = str;
  str += strcspn(str, delim);
  if (*str) {
    *str++ = '\0';
  }
  *nextp = str;
  return ret;
}

编辑:草图。请注意,我没有做所有你的作业,我为学生留下了一点#34;正如俗话所说。

/*
 * 
 * - Construct a binary search tree to store the information contained in the file specified
 * in the command line argument. Each record should be stored in a separate Node.
 * 
 * - Search the binary search tree for records, based on their keys. The keys are read in
 * from stdin, i.e. from the screen. 
 * 
 * For testing, it is often convenient to create a file of keys to be searched, one per line, and redirect the input from this file.
 * 
 * Use the UNIX operator < for redirecting input from a file.
 * 
 * - Examples of use: 
 * ./yelp1 datafile outputfile then type in keys;
 * or 
 * ./yelp1 datafile outputfile < keyfile
 * 
 * - Your program will look up each key and output the information (the data found) to the output
 * file specified by the second command line parameter.
 * 
 * If the key is not found in the tree,you must output the word NOTFOUND.
 * 
 * The number of key comparisons performed during both successful and unsuccessful lookups
 * have to be written to stdout.
 * 
 * - Remember that the entries in the file do not necessarily have unique keys.
 * Your search must locate all keys matching the search key, and output all the data found.
 */
/*
 * Tested with datafile produced by the following shellcode
 * 
 * # KEY "," DATA
 * counter=1;
 * while [ $counter -le 100 ];
 * do counter=$((counter + 1));
 * echo $(pwgen 10 1)","$(pwgen 10 1) >> testtree.db
 * done;
 * 
 * # ten random KEY
 * shuf -n10 testtree.db | sed -e 's/,[a-z]\+//g' > testtree10keys
 * 
 * # ten random DATA
 * shuf -n10 testtree.db | sed -e 's/[a-z]\+,//g' > testtree10datas
 * 
 * Please insert doublettes manually
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// data produced has only 10 characters each (plus NUL)
#define MAXNAMELENTH 11
#define MAXDATALENTH 11

typedef struct node {
  char name[MAXNAMELENTH];
  char data[MAXDATALENTH];
  struct node *left;
  struct node *right;
} node;

node *root;
node *search(node ** tree, char *key, int *count, FILE * fp_out);
int insertion(node ** r, char *key, char *value);
void deltree(node * tree);
//char *strtok_r(char *str, const char *delim, char **nextp);
void bt_print(node * leaf);

int main(int argc, char *argv[])
{
  node *root;
  //  node *tmp;
  FILE *fp;
  FILE *outputfile;
  //  FILE *keyfile;
  //  FILE *fp_key;
  //  int i;
  int counter = 0;
  int bufsize = MAXDATALENTH + MAXNAMELENTH + 2;
  //  int keyfilelen = MAXNAMELENTH;
  //  char *keyread;
  char *buffer;
  //  char *saveptr;
  //  char *line = NULL;
  char *keyin = NULL;
  char *valuein = NULL;
  //  char inputkey[MAXNAMELENTH];
  //  char *target_key = NULL;
  //  char *keyline = NULL;

  char *e;
  int res;
  char *comma;


  root = NULL;

  // must have at least one argument
  if (argc < 2) {
    fprintf(stderr, "Usage: %s datafile [< key-list]\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  /* Inserting nodes into tree */
  buffer = malloc(bufsize);
  if (buffer == NULL) {
    fprintf(stderr, "Malloc failed\n");
    exit(EXIT_FAILURE);
  }
  fp = fopen(argv[1], "r");
  if (fp == NULL) {
    fprintf(stderr, "Opening \"%s\" for reading failed\n", argv[1]);
    exit(EXIT_FAILURE);
  }
  outputfile = fopen("outputfile.txt", "a");
  if (fp == NULL) {
    fprintf(stderr, "Opening \"outputfile.txt\" for appending failed\n");
    exit(EXIT_FAILURE);
  }

  while ((e = fgets(buffer, bufsize, fp))) {
    if (e == NULL) {
      if (ferror(fp)) {
        // TODO: check errno for the exact kind of error
        fprintf(stderr, "An eror occured during reading \"%s\"\n", argv[1]);
        exit(EXIT_FAILURE);
      } else if (feof(fp)) {
        break;
      }
    }
    // assuming strict KEY","DATA"\n" and without whitespace
    // otherwise you need to check every step here!
    // valuein points to the comma before DATA
    valuein = strchr(buffer, ',');
    // valuein points to DATA
    valuein++;
    // DATA is 10 characters large
    valuein[10] = '\0';
    // comma points to the comma before DATA
    comma = strchr(buffer, ',');
    // make *comma NUL
    *comma = '\0';
    keyin = buffer;
    // ignoring return for now
    //printf("%s,%s\n",keyin, valuein);
    (void) insertion(&root, keyin, valuein);
  }

  bt_print(root);

  // search-keys come from either stdin or get typed in.
  // things typed in are also stdin
  while ((res = scanf("%10s", buffer)) == 1) {
    //printf("%s\n",buffer);
    search(&root, buffer, &counter, outputfile);
    printf("Misses for KEY \"%s\" = %d\n", buffer, counter);
    counter = 0;
  }

  /* Deleting all nodes of tree */
  deltree(root);

  fclose(fp);
  fclose(outputfile);
  return 0;
}

void bt_print(node * leaf)
{
  if (leaf) {
    printf("%s,%s\n", leaf->name, leaf->data);
    bt_print(leaf->left);
    bt_print(leaf->right);
  }
}

int insertion(node ** r, char *key, char *value)
{
  if (*r == NULL) {
    *r = malloc(sizeof(node));
    if (r == NULL) {
      return 0;
    }
    strcpy((*r)->name, key);
    strcpy((*r)->data, value);

    (*r)->left = NULL;
    (*r)->right = NULL;
  }
  // Checks for returns omitted for clarity
  else if (strcmp(key, (*r)->name) < 0) {
    insertion(&(*r)->left, key, value);
  }
  // else this will be in the right subtree
  else if (strcmp(key, (*r)->name) > 0) {
    insertion(&(*r)->right, key, value);
  } else {
    if (strcmp(value, (*r)->data) > 0) {
      insertion(&(*r)->left, key, value);
    } else if (strcmp(value, (*r)->data) < 0) {
      insertion(&(*r)->right, key, value);
    }
    // what if both, name *and* data are equal?
    return 0;
  }

  return 1;
}

void deltree(node * tree)
{
  if (tree) {
    deltree(tree->left);
    deltree(tree->right);
    free(tree);
  }
}

// search still cannot find multiple occurences of KEY
// Can you repair it?
node *search(node ** tree, char *key, int *count, FILE * fp_out)
{
  node *tmp;
  if (!(*tree)) {
    printf("%s --> NOTFOUND\n", key);
    fprintf(fp_out, "%s --> NOTFOUND", key);
    return NULL;
  } else {
    if (strcmp(key, (*tree)->name) < 0) {
      tmp = search(&((*tree)->left), key, count, fp_out);
      (*count)++;
      return tmp;
    } else if (strcmp(key, (*tree)->name) > 0) {
      tmp = search(&((*tree)->right), key, count, fp_out);
      (*count)++;
      return tmp;
    } else {
      // HINT 1: check  (*tree)->left->name and (*tree)->right->name
      //       (recursively) and print it as long as key==name
      // HINT 2: you don't need recursion, you can do it in a loop
      printf("FOUND KEY %s --> DATA %s\n", key, (*tree)->data);
      fprintf(fp_out, "%s --> %s\n", key, (*tree)->data);
      return *tree;
    }
  }
}