【问题标题】:Hashing text file line by line逐行散列文本文件
【发布时间】:2019-10-08 20:18:27
【问题描述】:

我正在尝试对包含 19 行学生个人信息的文本文件进行哈希处理。有一个基于案例的系统,我可以选择我想要执行的操作,例如在哈希中插入、显示等。代码根本不会读取我提供的文本文件,当我按显示作为操作时,它会弹出没有。当我按下插入选项等时也会发生同样的事情。

【问题讨论】:

  • 你在未初始化的指针int hashIndex = Hash(AM, 19);上调用Hash你是不是要调用int hashIndex = Hash(node.AM, 19);
  • @kiran Biradar 我根据这篇文章编写了我的代码,所以我认为这回答了你的问题stackoverflow.com/questions/56226055/…
  • 请阅读How to Ask
  • 最好提供一个简短但完整的可编译示例来说明您遇到的具体问题。在这种情况下,您提供了太多格式错误的代码(此后已被编辑),但它不包含 int main(void)int main(int argc, char *argv[]) 函数,因此无法编译。请编辑您的帖子以包含您编写主要功能的方式。
  • 对我来说(line[len - 1] != '\n')必须是(line[len - 1] == '\n'),还有其他几个问题,看我的回答

标签: c database hash


【解决方案1】:

代码根本不会读取我提供的文本文件

您的问题可能来自:

   char line[4096];
   while (fgets(line, sizeof line,fp)) 
   {
       size_t len = strlen(line);
       if (len && (line[len - 1] != '\n')) 

因为 (line[len - 1] != '\n') 这可能永远不会正确,因为 fgets 能够读取大行并且考虑到行后的 fscanf 仅包含少量数据。 p>

你为什么要处理 /* 不完整的行 */

通过测试完成完整的行

if (len && (line[len - 1] == '\n')) 

你还有一个意想不到的回报

 if (!hashTable[hashIndex].head) 
 {
   hashTable[hashIndex].head = newNode;
   hashTable[hashIndex].count = 1;
   return;
 }

因此,您不能阅读多个答案,请将后面的行放在 else { ... }

还请注意,您的代码假设用户要求只插入一次,如果他多次插入,您将添加多次相同的元素。

在你读完一行之后你再次在文件中读到

 fscanf(fp,"%s %s %s %d",node.AM, node.first_name, node.last_name, &node.grade);

所以你只保存了你想做的一半的数据

sscanf(line,"%s %s %s %d",node.AM, node.first_name, node.last_name, &node.grade);

您还有其他问题

Hash 中,您假设标识符至少有 7 个字符,如果不是这种情况,您会以未定义的行为读出名称(在空字符之后)

做一些类似的事情:

int Hash(char *AM, int n)
{    
  int i;
  int hashIndex = 0;

  for (i=0; (i< 8) && (AM[i] != 0); i++)
  {
    hashIndex += AM[i];
  }

  return hashIndex % n;
}

但是你的哈希值很差,有更好的方法来哈希一个字符串

        fscanf(fp,"%s %s %s %d",node.AM, node.first_name, node.last_name, &node.grade);

你对 int 使用格式 %dnode.gradefloat,替换 %d 通过 %f 并检查 fscanf 返回 4

我还鼓励您限制读取字符串的大小,以免冒险写出字段,因此(实际上 fscanf 必须替换为 sscanf )

fscanf(fp,"%99s %99s %99s %f", ...)

printf("Student ID  : %d\n", myNode->AM);

printf("%-12d", myNode->AM);

您使用 %d 格式表示 int,但您给出的是 char*

s替换d或改变AM的类型(当然还有如何在别处阅读和使用它)

insertToHash末尾的return没用,还有一些其他没用的return else where

printf("grade      : %d\n", myNode->grade);

printf("%d\n", myNode->grade);

你使用 %d 格式作为 int 但你给了一个双倍

%d 替换为 %lf%lg

int hashIndex = Hash(AM, 19);

AM 未初始化,行为未定义

你想要的

int hashIndex = Hash(node.AM, 19);

struct node *newnode = createNode(AM, first_name, last_name, grade);

AMfirst_namelast_namegrade 未初始化,行为未定义

你想要的

struct node *newnode = createNode(node.AM, node.first_name, node.last_name, node.grade);

并删除无用的变量hashIndex, grade, last_name, first_name, AM

deleteFromHashsearchInHash中测试

 if (myNode->AM == AM)

错了,因为你比较指针,你想要

if (!strcmp(myNode->AM, AM))

struct node 
{
  float grade;
  char AM[100];
  char first_name[100];
  char last_name[100];
  struct node *next;
}node;

结构和全局变量使用相同的名称,这不是一个好主意。

另外全局变量node只在insertToHash中使用,所以不需要,去掉全局变量,在insertToHash。


编辑后添加 main

scanf("%d", &AM);

必须是(2次)

scanf("%99s", AM);

您的变量 first_name, last_namegrade 未使用


考虑到我所有言论的代码是:

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

struct hash *hashTable = NULL;
int eleCount = 0;

struct Node 
{
  float grade;
  char AM[100];
  char first_name[100];
  char last_name[100];
  struct Node *next;
};

struct hash 
{
struct Node *head;
int count;
};

struct Node * createNode(char *AM, char *first_name, char *last_name, float grade) 
{
  struct Node *newNode;

  newNode = (struct Node *) malloc(sizeof(struct Node));
  strcpy(newNode->AM, AM);
  strcpy(newNode->last_name, last_name);
  strcpy(newNode->first_name, first_name);
  newNode->grade = grade;
  newNode->next = NULL;
  return newNode;
}

int Hash(char *AM, int n)
{    
  int i;
  int hashIndex = 0;

  for (i=0; (i< 8) && (AM[i] != 0); i++)
  {
    hashIndex += AM[i];
  }

  return hashIndex % n;
}

void insertToHash() 
{
  struct Node node;

  FILE *fp;
  fp = fopen ("Foitites-Vathmologio-DS.txt","rb");

  if (fp == NULL) 
  { 
    fprintf(stderr,"Could not open file");  
    return;
  } 

  char line[4096];

  while (fgets(line, sizeof line,fp)) {
    size_t len = strlen(line);
    if (len && (line[len - 1] == '\n')) {
      /* complete line */
      if (sscanf(line,"%99s %99s %99s %f",node.AM, node.first_name, node.last_name, &node.grade) != 4) {
    puts("invalid file");
    return;
      }

      int hashIndex = Hash(node.AM, 19);

      struct Node *newNode = createNode(node.AM, node.first_name, node.last_name, node.grade);
      /* head of list for the bucket with index "hashIndex" */

      if (!hashTable[hashIndex].head) 
      {
        hashTable[hashIndex].head = newNode;
        hashTable[hashIndex].count = 1;
      }
      else {
        /* adding new Node to the list */
        newNode->next = (hashTable[hashIndex].head);
        /*
           * update the head of the list and no of
           * Nodes in the current bucket
        */
        hashTable[hashIndex].head = newNode;
        hashTable[hashIndex].count++;
      }
    }
  }
  fclose(fp);
  printf("Done! \n");
}

void deleteFromHash(char *AM) 
{
  /* find the bucket using hash index */
  int hashIndex = Hash(AM, 19);
  int flag = 0;

  struct Node *temp, *myNode;
  /* get the list head from current bucket */

  myNode = hashTable[hashIndex].head;

  if (!myNode) {
    printf("Given data is not present in hash Table!!\n");

    return;
  }

  temp = myNode;
  while (myNode != NULL) {
    /* delete the Node with given AM */
    if (!strcmp(myNode->AM, AM)) {
      flag = 1;
      if (myNode == hashTable[hashIndex].head)
        hashTable[hashIndex].head = myNode->next;
      else
        temp->next = myNode->next;

      hashTable[hashIndex].count--;
      free(myNode);
      break;
    }

    temp = myNode;
    myNode = myNode->next;
  }
  if (flag)
    printf("Data deleted successfully from Hash Table\n");
  else
    printf("Given data is not present in hash Table!!!!\n");
}

void searchInHash(char *AM) {
  int hashIndex = Hash(AM, 19);
  int flag = 0;
  struct Node *myNode;        myNode = hashTable[hashIndex].head;
  if (!myNode) {
    printf("Search element unavailable in hash table\n");
    return;
  }
  while (myNode != NULL) {
    if (!strcmp(myNode->AM, AM)) {
      printf("Student ID  : %s\n", myNode->AM);
      printf("First Name     : %s\n", myNode->first_name);
      printf("Last Name     : %s\n", myNode->last_name);
      printf("grade      : %lg\n", myNode->grade);
      flag = 1;
      break;
    }
    myNode = myNode->next;
  }
  if (!flag)
    printf("Search element unavailable in hash table\n");
}

void display() {
  struct Node *myNode;
  int i;
  for (i = 0; i < eleCount; i++) {
    if (hashTable[i].count == 0)
      continue;
    myNode = hashTable[i].head;
    if (!myNode)
      continue;
    printf("\nData at index %d in Hash Table:\n", i);
    printf("Student ID    First Name    Last Name      Grade   \n");
    printf("--------------------------------\n");
    while (myNode != NULL) {
      printf("%-12s", myNode->AM);
      printf("%-15s", myNode->first_name);
      printf("%-15s", myNode->last_name);
      printf("%lg\n", myNode->grade);
      myNode = myNode->next;
    }
  }
}

int main() 
{
  int n=19, ch;
  char AM[100];
  int insertDone = 0;

  eleCount = n;
  /* create hash table with "n" no of buckets */
  hashTable = (struct hash *) calloc(n, sizeof(struct hash));
  while (1) {
    printf("\n1. Insertion\t2. Deletion\n");
    printf("3. Searching\t4. Display\n5. Exit\n");
    printf("Enter your choice:");
    scanf("%d", &ch);


    switch (ch) {
    case 1: 
      if (insertDone)
        puts("Inserton was already done");
      else {
    /*inserting new Node to hash table */
        insertToHash();
        insertDone = 1;
      }
      break;

    case 2: 
      printf("Enter the AM to perform deletion:");
      scanf("%99s", AM);
      /* delete Node with "AM" from hash table */
      deleteFromHash(AM);
      break;

    case 3: 
      printf("Enter the AM to search:");
      scanf("%99s", AM);
      searchInHash(AM);
      break;
    case 4: 
      display();
      break;
    case 5: 
      exit(0);
    default: 
      printf("U have entered wrong option!!\n");
      break;
    }
  }
  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -g -pedantic -Wextra -Wall c.c
pi@raspberrypi:/tmp $ cat Foitites-Vathmologio-DS.txt
123 aze qsd 1.23
456 iop jkl 4.56
pi@raspberrypi:/tmp $ ./a.out

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:4

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:1
Done! 

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:4

Data at index 7 in Hash Table:
Student ID    First Name    Last Name      Grade   
--------------------------------
456         iop            jkl            4.56

Data at index 17 in Hash Table:
Student ID    First Name    Last Name      Grade   
--------------------------------
123         aze            qsd            1.23

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:1
Inserton was already done

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:3
Enter the AM to search:123
Student ID  : 123
First Name     : aze
Last Name     : qsd
grade      : 1.23

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:3
Enter the AM to search:1234
Search element unavailable in hash table

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:2
Enter the AM to perform deletion:1
Given data is not present in hash Table!!

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:2
Enter the AM to perform deletion:123
Data deleted successfully from Hash Table

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:4

Data at index 7 in Hash Table:
Student ID    First Name    Last Name      Grade   
--------------------------------
456         iop            jkl            4.56

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:2
Enter the AM to perform deletion:456
Data deleted successfully from Hash Table

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:4

1. Insertion    2. Deletion
3. Searching    4. Display
5. Exit
Enter your choice:5
pi@raspberrypi:/tmp $ 

【讨论】:

  • 我认为我们在这方面取得了一些进展!在我对主要功能进行更改之前,特别是在 scaf("%d", &AM) 中,当我选择 Display case 它只会显示我文件的第一行但在你提出的更改之后我得到 return ld1 exit状态
  • @vaskar 我继续更正您的代码,目前显示会生成我放入文件中的条目
  • 我在 mu 代码中编辑了您提供的更正以及我的 .txt 文件的内容和形式,现在,当我选择显示时,它会同时显示两个或三个学生,就好像它们在同一个节点中
  • @vaskar 我继续编辑我的答案以更正您的代码,请等待我完成,我会警告您并输入完整的更正代码
  • 加一个,只为您的大量努力。
猜你喜欢
  • 2015-03-13
  • 2021-04-25
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
  • 2015-05-13
相关资源
最近更新 更多