C链接列表错误

时间:2012-10-11 21:15:19

标签: c linked-list

我需要一些认真的帮助来理解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。我尝试在一堆地方放置并声明它们,但似乎无法解决这些错误。

我真的很感激你能提供给我的一些帮助和任何可能的知识。我真的给了这个很大的帮助,但我只是暂时停下来。

3 个答案:

答案 0 :(得分:1)

好的,我会尽力让您快速了解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)
{
}

此函数将“first item”指针初始化为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)。然后尝试编写一个“遍历”列表的方法,打印出每个整数。一旦你理解了这一点,尝试编写方法在最后或中间添加/删除。

答案 1 :(得分: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;
};  

接下来,您需要添加头部声明。这将是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 :(得分:0)

简单来说,您需要将数组(类型为struct)转换为具有相同字段的链接列表。

#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
            }
     }
  }

}

您可能希望将代码放入函数中。请注意,插入单个链表比插入双链表更棘手,但它保存了一个指针。并提醒一句:我没有对此进行过测试,只是输入了它的逻辑。