链接列表练习,我做错了什么?

时间:2010-03-13 19:10:47

标签: c++ pointers linked-list dynamic-memory-allocation

嘿所有人。我正在做一个涉及动态内存分配,指针,类和异常的链表练习。有人愿意批评它并告诉我我做错了什么以及我应该在风格和上面列出的那些主题方面做得更好吗?

/*

Linked List exercise

*/

#include <iostream>
#include <exception>
#include <string>
using namespace std;

class node{
public:
    node * next;
    int * data;
    node(const int i){
        data = new int;
        *data = i;
    }
    node& operator=(node n){
        *data = *(n.data);
    }
    ~node(){
        delete data;
    }
};

class linkedList{

public:

    node * head;
    node * tail;
    int nodeCount;

    linkedList(){
        head = NULL;
        tail = NULL;
    }

    ~linkedList(){
        while (head){
            node* t = head->next;
            delete head;
            if (t) head = t;
        }
    }

    void add(node * n){
        if (!head) {
            head = n;
            head->next = NULL;
            tail = head;
            nodeCount = 0;
        }else {
            node * t = head;
            while (t->next) t = t->next;
            t->next = n;
            n->next = NULL;
            nodeCount++;
        }
    }

    node * operator[](const int &i){
        if ((i >= 0) && (i < nodeCount)) throw new exception("ERROR:  Invalid index on linked list.", -1);
        node *t = head;
        for (int x = i; x < nodeCount; x++) t = t->next;
        return t;
    }

    void print(){
        if (!head) return;
        node * t = head;
        string collection;
        cout << "[";
        int c = 0;
        if (!t->next) cout << *(t->data);
        else while (t->next){
            cout << *(t->data);
            c++;
            if (t->next) t = t->next;
            if (c < nodeCount) cout << ", ";
        }
        cout << "]" << endl;
    }

};

int main (const int & argc, const char * argv[]){

    try{
        linkedList * myList = new linkedList;
        for (int x = 0; x < 10; x++) myList->add(new node(x));
        myList->print();
    }catch(exception &ex){
        cout << ex.what() << endl;
        return -1;
    }   
    return 0;
}

4 个答案:

答案 0 :(得分:7)

不需要数据作为指针。

使用ctor-initializer列表,最好是const-correctness和exception safety。你的构造函数都不需要在体内有任何代码。

您的linkedList构造函数未初始化nodeCount。

您没有使用列表的尾指针来表示任何事情。如果你保持最新状态,它可以节省你在非空的添加情况下扫描整个列表。

索引(operator [])在链表上支持是一件不寻常的事情。 OTOH你还没有删除功能。

operator []不应该通过引用获取其参数。只有大型结构需要通过const引用传递,像int这样的小类型应该只通过值传递。

现在,如果添加失败,指向新节点()的指针会泄漏。 (但我实际上并没有看到添加失败的方法,除非列表链接被破坏。)

您应该在节点上定义私有复制构造函数,以防止数据双重释放。每次定义operator =和析构函数时,您还应该定义或删除复制构造函数(三个规则)。您还应该在linkedList上定义私有拷贝构造函数和赋值运算符,以防止双重释放。

不使用print函数中的变量字符串集合。 print()中的变量t应该是指向const的指针。 print本身应该是const成员函数。

答案 1 :(得分:4)

/*
Linked List exercise
*/

class node {
public:
    node * next;
    int * data;

data并不一定需要成为一个指针(除非你的课堂作业必须是这样)。您可以将其更改为int,然后将引用从*(t->data)更改为仅t->data。同样,您不需要在ctor / dtor中使用newdelete

    node(const int i) {
        data = new int;
        *data = i;
    } 
    node& operator=(node n) {
        *data = *(n.data);
    } 
    ~node() {
        delete data;
    } 
};

class linkedList {

public:
    node * head;
    node * tail;
    int nodeCount;

    linkedList() {
        head = NULL;
        tail = NULL;

您应该在此处初始化所有数据成员。除非您在此处设置为零,否则nodeCount将具有一些随机值。

    } 

    ~linkedList() {
        while (head) {
            node* t = head->next;
            delete head;
            if (t)
                head = t;

这看起来像个错误。您需要始终分配head = t,即使t为NULL,否则您的循环将不会终止(但多次删除同一节点可能会导致异常)。

        } 
    } 

    void add(node * n) {
        if (!head) {
            head = n;
            head->next = NULL;
            tail = head;
            nodeCount = 0;

我认为整个if声明是不必要的。当链表为空时,两个分支都执行相同的操作,因此您可以始终使用第二个( else )分支。

此外,将nodeCount设置为0似乎是一个错误;不应该是1

        } else {
            node * t = head;

            while (t->next)
                t = t->next;

            t->next = n;
            n->next = NULL;
            nodeCount++;
        } 
    } 

    node * operator[](const int &i) {

一个小问题,但const int &论证并没有任何意义。你只是传递int类型而没有获得任何好处。

        if ((i >= 0) && (i < nodeCount))
            throw new exception("ERROR:  Invalid index on linked list.", -1);

上述情况向我看来;你总是会抛出有效参数的异常。

        node *t = head;

        for (int x = i; x < nodeCount; x++)
            t = t->next;

上面的循环对我来说似乎有点怀疑。如果i是您想要的节点从零开始的索引,那么您的计数器不应该从0转到i-1吗?

        return t;
    } 

    void print() {
        if (!head)
            return;

同样,你应该让这个方法工作,而不必防止空列表。我希望有一个空列表可以打印[]之类的内容,但是上面有保护代码,你什么都不打印。

        node * t = head;
        string collection;
        int c = 0;

        cout << "[";

        if (!t->next) {
            cout << *(t->data);

与上述其他条件一样,我认为上面的分支是不必要的。第二个( else )分支应该处理NULL情况。

        } else {
            while (t->next) {

我认为你想要while (t)而不是while (t->next)

                cout << *(t->data);
                c++;

                if (t->next)
                    t = t->next;

我认为这是一个像之前的错误。您总是分配't = t-&gt; next',否则您的循环将不会终止。

                if (c < nodeCount)
                    cout << ", ";
            } 
        } 

        cout << "]" << endl;
    } 
};

int main (const int & argc, const char * argv[]) { // const int& ?

const int &再次......

    try {
        linkedList * myList = new linkedList;
        for (int x = 0; x < 10; x++)
            myList->add(new node(x));
        myList->print();
    } catch(exception &ex) {
        cout << ex.what() << endl;
        return -1;
    }  

家庭作业可能很好,但抓住每一个可能的例外(正如你上面所做的那样)可能在这里没有增加太多价值,而且通常被认为是不好的做法。

如果省略上面的try / catch内容,我怀疑每当程序以异常终止时,编译器提供的默认顶级异常处理程序将转储异常并堆栈跟踪信息(取决于你的编译器)。

    return 0;
}

答案 2 :(得分:0)

if ((i >= 0) && (i < nodeCount)) throw new exception("ERROR:  Invalid index on linked list.", -1);

该行应为:

if( i < 0 || i >= nodeCount ) throw...

add方法也存在问题:

void add(node * n){
    if (!head) {
        head = n;
        head->next = NULL;
        tail = head;
        nodeCount = 0;
    }else {
        node * t = head;
        while (t->next) t = t->next;
        t->next = n;
        n->next = NULL;
        nodeCount++;
    }
}

对于一个添加后的第一个节点计数将为0,对于另一个,您正在进行搜索以插入链接列表...人们期望的操作是O(1)。

更典型的实现是:

void add( node* n ) {
   node* old_head = head;
   head = n;
   head->next = old_head;
   ++nodeCount;
   if( old_head == NULL )
      tail = head
}

答案 3 :(得分:0)

1)您可以使用data = new int(i)初始化字段。

2)您在operator [] if ((i >= 0) && (i < nodeCount))中创建了一个错误的条件,它应该被反转,如if ((i < 0) || (i >= nodeCount))