【问题标题】:C Linked List errorsC 链表错误
【发布时间】:2012-10-11 21:15:18
【问题描述】:

我需要一些认真的帮助来理解 C++ 中的链接列表 我想使用我几周前使用数组结构编写的程序并将它们转换为链接列表并添加几个新函数。我最担心的是我对链接列表没有信心,并且一直在这里和其他网站上花费时间来获取有关它们的知识。但我找不到可以帮助我解决我现在面临的问题的来源。

这是我的原始代码:

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

#define MAX 100

struct YouTubeVideo { 
char video_name[1024];        // YouTube video name
int video_ranking;            // Number of viewer hits
char video_url[1024];         // YouTube URL
};

struct YouTubeVideo Collection[MAX];

int tail = 0;

//-- Forward Declaration --// 
void printall();
void insertion();
void sort();
void branching(char option);        
void menu(); 
void load_file();
void save_file();

int main()
{
char ch; 

load_file();

printf("\n\nWelcome to CSE240: YouTube Classic Hits\n");

do {
     menu();
     fflush(stdin);                 // Flush the standard input buffer 
     ch = tolower(getchar());       // read a char, convert to lower case
     branching(ch);
} while (ch != 'q');

return 0; 
}

void menu()
{
 printf("\nMenu Options\n");
 printf("------------------------------------------------------\n");
 printf("i: Insert a new favorite\n");
 printf("p: Review your list\n"); 
 printf("q: Save and quit\n");
 printf("\n\nPlease enter a choice (i, p, or q) ---> "); 
}

void branching(char option)
{
switch(option)
{
    case 'i':
        insertion();
        sort();
    break;

    case 'p':
        printall();
    break;

    case 'q':
        save_file();
    break;

    default:
        printf("\nError: Invalid Input.  Please try again..."); 
    break;
}
}

void insertion()
{
if(tail < MAX)
{
    printf("\nWhat is the name of the video? (No spaces characters allowed)\n");
    scanf("%s", Collection[tail].video_name);

    printf("\nHow many viewer hits does this video have?\n");
    scanf("%d", &Collection[tail].video_ranking);

    printf("\nPlease enter the URL: ");
    scanf("%s", Collection[tail].video_url);

    tail++;
}
else
{
    printf("\nERROR: Your collection is full. Cannot add new entries.\n");
}
}

void sort()
{
int i = 0, j = 0; 
struct YouTubeVideo temp;

for(i = 0; i < tail; i++)
{
    for(j = i+1; j < tail; j++)
    {
        if(Collection[i].video_ranking < Collection[j].video_ranking)
        {
            temp = Collection[i];
            Collection[i] = Collection[j];
            Collection[j] = temp;
        }
    }
}

//RA: I think it's easier (and faster) to assume your current list is already
//    sorted and then insert your new element into the correct position. (You
//    can show this maintains a sorted list by induction.)

printf("\nSorting Complete...\n");
}

void printall()
{
int i; 

printf("\nCollections: \n"); 

for(i = 0; i < tail; i++)
{
    printf("\nVideo Name: %s", Collection[i].video_name);
    printf("\nRanking (Hits): %d", Collection[i].video_ranking);
    printf("\nURL: %s", Collection[i].video_url);
    printf("\n");
}
}

void save_file() { 
FILE *fileName;                                     // declare a pointer to File type 
char ch; 
int index = 0; 

fileName = fopen("ranking.dbm", "wb");              // "b" for binary mode 
                                                        // ìwî for write


if(fileName != NULL) 
{   
    fwrite(&tail, sizeof(int), 1, fileName);        // Write tail to the     file for later retrieval.

    for(index = 0; index < tail; index++)
    { 
        fwrite(&Collection[index].video_name, 1024, 1, fileName); 
        fwrite(&Collection[index].video_ranking, sizeof(int), 1, fileName);     
        fwrite(&Collection[index].video_url, 1024, 1, fileName);
    } 

    fclose(fileName);
} 
else 
    printf ("ERROR: Could not open file for saving data !\n"); 
}

void load_file() { 
FILE *fileName;                         // declare a pointer     to File type 
int index = 0; 

fileName = fopen("ranking.dbm", "rb");  // "b" for binary mode 
                                    // ìrî           for read

if(fileName != NULL) {   
    fread(&tail, sizeof(int), 1, fileName);

    for(index = 0; index < tail; index++) 
    {
        fread(Collection[index].video_name, 1024, 1, fileName);
        fread(&Collection[index].video_ranking, sizeof(int), 1, fileName);
        fread(Collection[index].video_url, 1024, 1, fileName);
    }

    fclose(fileName);
}
else 
    printf ("ERROR: Could not open file for loading data !\n"); 
}

这些是我应该做的确切说明:

Convert the “YouTubeVideo” array structure (Collection) into a linked-list. The program must sort (by “video_name”) the entries as they are inserted into the linked-list. [30 points] (*Note: You will lose 10 points if the linked list is not sorted.)

现在我已经尽我所能,以我目前的理解,但我现在遇到了问题。

这是我尝试解决方案的代码:

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

using namespace std;

#define MAX 100

 struct YouTubeVideo
{
char name[1024];        // YouTube video name
int ranking;                // Number of viewer hits
char url[1024];             // YouTube URL
};

struct YouTubeVideo Collection[MAX];

int tail = 0;

//-- Forward Declaration --//
void printall();
void insertion();
void branching(char option);
void menu();


int main()
{
char ch;

// TODO: Add code to load save data from file

cout << "\n\nWelcome to CSE240: YouTube Classic Hits\n";

do {
    menu();
    cin >> ch; // read a char, convert to lower case
    cin.ignore();

    ch = tolower(ch);
    branching(ch);
} while (ch != 'q');

return 0;
}

void menu()
{
cout << "\nMenu Options\n";
cout << "------------------------------------------------------\n";
cout << "i: Insert a new favorite\n";
cout << "p: Review your list\n";
cout << "s: Search\n";
cout << "d: Delete an entry\n";
cout << "q: Save and quit\n";
cout << "\n\nPlease enter a choice (i, p, s, d, or q) ---> ";
}

void branching(char option)
{
switch(option)
{
    case 'i':
        insertion();
        break;

    case 'p':
        printall();
        break;

    case 's':
        // TODO: Add code to search for a particular node by name
        break;

    case 'd':
        // TODO: Add code to remove a node
        break;

    case 'q':
        // TODO: Add code to save data into a file
        break;

    default:
        cout << "\nError: Invalid Input.  Please try again...";
        break;
}
}

void insertion() { // insert a new entry
struct YouTubeVideo *p, *temp;
p = (struct YouTubeVideo *) malloc(sizeof(struct YouTubeVideo)); if (p == 0) {
    printf("out of memory\n"); return; }
printf("Enter Video name, Views, URL: \n"); scanf("%s", p->name); // p->name is array         scanf("%d", &p->phone);
scanf("%s", p->ranking);
temp = head;
if ((head == NULL)||(strcmp(p->name, temp->name) <=0)) {
    p->next = head;
    head = p;
}

else {
    while (temp->next != NULL) {
        if (stricmp(p->name, temp->next->name) <=0) { p->next = temp->next;
            temp->next = p;
            return;
        } else
            temp = temp->next; }
    p->next = NULL;
    temp->next = p;
} }

void printall()
{
int i;

cout << "\nCollections: \n";

for(i = 0; i < tail; i++)
{
    cout << "\nVideo Name: " << Collection[i].name << "\n";
    cout << "\nRanking (Hits): " << Collection[i].ranking << "\n";
    cout << "\nURL: " << Collection[i].url << "\n";
    cout << "\n";
}
}

我遇到的问题是我的insertion 我收到错误undeclared identifier headno member named next in YouTubeVideo。我尝试在很多地方放置和声明它们,但似乎无法修复这些错误。

我非常感谢您能给予我的一些帮助和任何可能的知识。我真的很努力,但只是暂时卡住了。

【问题讨论】:

  • 这是 C,不是 C++。这段代码中唯一特定于 C++ 的就是结构中存在函数。您已经继承了 C++ 中不需要的 C 语法(即 struct YouTubeVideo* p;,甚至使用 mallocfree 来分配您的结构(对于非 POD 类型来说是个坏主意)。
  • 顺便说一句,您的编译器当然是正确的;我没有在任何地方看到 head 声明,但您在 insertion() 中使用它
  • 从头开始;你没有声明任何成员函数,我错过了一个卷曲。所以实际上这是 C,而不是 C++。重新标记。同样,YouTubeVideo 没有声明名为 next 的成员。错误信息很清楚。
  • 那么放在哪里合适呢?因为我找不到一个如果声明不会导致错误的地方?

标签: c linked-list


【解决方案1】:

您需要实际实现一个链表。这看起来像是一项家庭作业,所以我想知道您对 C++ 的了解程度。如果您还没有真正进行类和面向对象的编程,那么解决此问题的最简单方法是将下一个和上一个对象添加到您的 youtube 视频结构中。像这样:

struct YouTubeVideo {   
    char video_name[1024];        // YouTube video name  
    int video_ranking;            // Number of viewer hits 
    char video_url[1024];         // YouTube URL  
    YouTubeVideo* next;
    YouTubeVideo* previous;
};  

接下来,您需要添加一个 head 声明。这将是 YouTubeVideo* 类型。添加第一个视频时,将头部设置为指向该视频。然后,每当您添加新视频时,将头视频的下一个指针设置为指向新视频,新视频上的前一个指针应指向头视频。那是您的链表的开始,但是您的解决方案仍然很混乱。

如果我是你,我会看看一些 Linked List 类是如何实现的。这是我编写的第一个 Linked List 类的头文件:

#ifndef LINKEDLIST_H 
#define LINKEDLIST_H

#include "List.h" 

class LinkedList : public List { 
 public: 
  LinkedList();
  virtual double get(int index) const; 
  virtual void add(double item); 
  virtual void insert(int index, double item); 
  virtual double delete_item(int index); 
  virtual int size() const;  
 private:
  class Node;
  Node* first;
  Node* last;
  int listsize;
}; 
class LinkedList::Node{
 public:
  double value;
  Node* next;
};

#endif

可以看到这个列表里面有一个类Node,这个类包含一个值double value。如果您想使用此代码,则必须使您的节点类具有一个字段,即 YouTubeVideo* 值。

【讨论】:

    【解决方案2】:

    好的,我会尽力让您快速了解 C++ 中的链表是什么,同时让您通过自己的作业来学习。您的代码几乎是 C,这将是更多 C++ 风格,尽管我会避免使用模板,并且有时会拼出 C++ 兽医可能会使事情更简洁的地方。

    这是一个典型的简单节点结构,用于保存整数的单链表:

    struct LinkedListNode
    {
      int value;
      LinkedListNode* next;
    };
    

    这个节点保存一个整数,外加一个指向列表中下一个节点的指针。

    对于这种链表来说,这是一个简化的界面:

    struct LinkedList
    {
    public:
      LinkedList();
      bool isEmpty() const;
      int valueAtBeginning() const;
      void insertAtBeginning(int newValue);
    
    private:
      LinkedListNode* head;
    };
    

    这个类提供了一个构造函数(一种制作链表的方法),一种向列表中插入新项目的方法,一种获取列表中第一个值的方法,以及一种检查列表是否为空的方法。它还保留(供自己参考)指向列表中第一个节点的指针。

    让我们通过一种方式来实现这些。

    这里是构造函数:

    LinkedList::LinkedList():
      head(NULL)
    {
    }
    

    此函数将“第一项”指针初始化为 NULL。这将是“没有第一项,因为列表为空”的代码。说到这里:

    bool LinkedList::isEmpty() const
    {
      return (head == NULL);
    }
    

    这个函数说“如果头指针为空,则列表为空。否则它不是”。请注意该方法是如何标记为const 的,它保证此代码不会修改列表的任何部分。

    下一个也很简单:

    int LinkedList::valueAtBeginning() const
    {
      assert(!isEmpty());
      return head->value;
    }
    

    这个函数只是简单地跟随指向列表中第一项的指针,并取出它的value 成员并返回它。它还断言列表不为空。这将使您很容易发现您是否犯了从空列表中要求某些东西的错误。同样,请注意该方法是如何标记为 const 的,因为它不会更改列表。

    最后,在开头添加新的东西:

    void LinkedList::insertAtBeginning(int newValue)
    {
      LinkedListNode* oldHead = head;
      LinkedListNode* newHead = new LinkedListNode();
      newHead->value = newValue;
      newHead->next = oldHead;
      head = newHead;
    }
    

    这在概念上很简单。我们创建一个新节点,并将其粘贴在列表的前面。旧的第一项成为第二项。另外,请注意我在这里如何使用 C++ new 而不是 C malloc。测验:如果列表为空,这会起作用吗?

    好的,现在我将由您来存储不仅仅是整数。另外,尝试弄清楚如何编写一个从列表中删除第一项的方法(使用 C++ delete,而不是 C free)。然后尝试编写一个“遍历”列表的方法,打印出每个整数。完成后,尝试在末尾或中间编写添加/删除方法。

    【讨论】:

      【解决方案3】:

      简单来说,你需要将一个数组(结构类型)转换为一个具有相同字段的链表。

      #include <stdio.h>
      #include <stdlib.h>
      
      struct LL
      {
          char name[1024];        // YouTube video name
          int ranking;                // Number of viewer hits
          char url[1024];             // YouTube URL
      
          struct LL *next; // pointer to the next element
      };
      
      // this is from your code
      #define MAX 100
      struct YouTubeVideo
      {
          char name[1024];        // YouTube video name
          int ranking;                // Number of viewer hits
          char url[1024];             // YouTube URL
      };
      
      // now you have an array of those structs
      struct YouTubeVideo Collection[MAX];
      
      // and you can fill it up as you wish
      
      int main(int argc, char**argv)
      {
          struct LL *ll = NULL;
      
          for (int i = 0; i < MaxElements; i++)
          {
              // we have a blob of memo to store your stuff
              x=(struct LL*)calloc(1, sizeof(struct LL));
              if (x != NULL)
          {
              // just run out of memory
              // so handle the error
          }
              else
          {
              // nothing to do just copy fields of Collection[i]
              // to the newly allocated space
              x->name    = strdup(Collection[i].name);
              x->ranking = Collectionp[i].ranking;
              x->url     = strdup(Collection[i].name);
              x->next    = NULL;
      
              // since you want your result sorted we need to find its
              // location in the linked list
      
              if (ll == NULL) // if the list is empty
              {
                  ll=x;
                  // and nothing else to do since a list with a single element
                  // is always sorted
              }
              else
              {
                  struct LL *p = ll, *q = ll;
                  // need to find where in the list should x be inserted
                  // p is not null (see the assignment above) so we
                  // always can call strcmp on it. also for x
      
                  while (p!=NULL && strcmp(p->name, x->name) < 0)
              // p can become null if your struct is to become the last
              // in the linked list: the order of comparisons are
              // important
              {
                  q=p; // we need q, the parent node because it is
                       // the parent node's next pointer needs to be modified
                  p=p->next;
              }
                  // once we get here p points to an LL structure or NULL if
                  // the element to be inserted will be the last in the list
                  // q points to the element before p
      
                      // one more trick: if element being inserted is comes earlier than
                      // the first element we need to modify ll
                      if (q == ll)
                      {
                       x->next = ll;
                       ll = x;
                      }
                      else
                      {
                          x->next=q->next;
                          q->next=x;
      
                      // these lines don't fiddle with p
                  }
           }
        }
      

      }

      您可能希望将代码放入函数中。请注意,插入单链表比插入双链表要复杂一些,但它节省了一个指针。还有一句警告:我没有测试过,只是输入了它的逻辑。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多