简体   繁体   English

C ++简单链表尝试:不太了解发生了什么

[英]C++ simple linked list attempt : don't quite understand what's going on

I tried to strictly implement in c++ what I'm studying in algorithmic at the moment, recursive functions with simple linked lists. 我试图在c ++中严格实现我目前在算法方面正在研究的内容,即具有简单链表的递归函数。 Here is what I've come by : 这是我的经历:

#include <iostream>
using namespace std;

class Liste {
    private :
        int val;
        Liste *suivante;
    public :
        Liste(int val = 0, Liste *suivante = NULL) {
            this->val = val;
            this->suivante = suivante;
        }
        void afficherElement() const {
            cout << "Adresse : " << this << endl;
            cout << "Valeur : " << val << endl;
            cout << "Adresse suivante : " << suivante << endl;
            cout << endl;
        }
        int tete() const {
            return val;
        }
        Liste reste() const {
            return *suivante;
        }
        bool estVide() const {
            return (suivante == NULL);
        }
        Liste prefixer(int val) {
            Liste *nouvelle = new Liste(val, this);
            return *nouvelle;
        }
        Liste suffixer(int val) {
            suivante = new Liste(val);
            afficherElement(); // test (last element won't be displayed)
            return *suivante;
        }
};

int main() {
    Liste uneListe(3); // 1st element
    uneListe.suffixer(5).suffixer(8).suffixer(10); // adding 3 more

    cout << "-----------\n\n";

    uneListe.afficherElement(); // displaying 1st element : ok
    uneListe.reste().afficherElement(); // displaying 2nd element : pointer is NULL !!???
    // uneListe.reste().reste().afficherElement(); --> segmentation fault, predictably enough

    return 0;
}

As you can guess, it doesn't work. 如您所料,它不起作用。 When I add elements, calling the display method within the add method, elements seem to be well formed although the pointer value and the next element's adress differ (I don't get why). 当我添加元素并在add方法中调用display方法时,尽管指针值和下一个元素的地址不同(但我不明白为什么),但元素似乎格式良好。 But, after adding process is done, I try to display the list again, 1st element is well linked with 2nd, but then there is a NULL pointer value. 但是,添加过程完成后,我尝试再次显示列表,第一个元素与第二个元素很好地链接在一起,但是有一个NULL指针值。 Wonder why ?? 想知道为什么 ?? I've seen a code with two classes ( Node and Lis t), that works fine, but I'd like to know what is wrong with mine. 我已经看到了带有两个类( NodeLis t)的代码,可以正常工作,但是我想知道我的问题是什么。 Is it that I'm creating new objects of a class within this same class ? 是否正在同一类中创建类的新对象?

Thanks, 谢谢,

Class Liste contains a value and a reference, which is not what a list is: a singly linked list is a pointer to an element containing a value and a pointer to the next node. Liste类包含一个值和一个引用,而不是 列表 :单个链接列表是指向包含值的元素的指针和指向下一个节点的指针。

You might use a value+pointer element as a list object, ignoring the val member. 您可以将value + pointer元素用作列表对象,而忽略val成员。 This would require different coding for some methods, eg, for tete() and reste(). 对于某些方法,例如tete()和reste(),这将需要不同的编码。

But, since using 但是,由于使用

typedef Liste * real_list_type;

is what you have in mind (? - see below), let's look at the methods. 是您要记住的(?-见下文),让我们看一下方法。

bool estVide() const { return (suivante == NULL); }

This is in contradiction to the real_list_type being a mere List *; 这与real_list_type仅仅是列表*相矛盾; if you compare this to method reste(), it actually tests whether the tail is empty, not the list itself! 如果将此与方法reste()进行比较,它实际上会测试尾部是否为空,而不是列表本身! (It would be in sync with using a value+pointer object as the list object.) (它将与使用value + pointer对象作为列表对象同步。)

Liste suffixer(int val) { suivante = new Liste(val); ... }

This is bad: it replaces suivante with a new object, no matter what's stored in there (a memory leak). 这很不好:无论用什么存储新内容,它都会用新对象替换suivante(内存泄漏)。 You'll have to do 你必须要做

Liste suffixer(int val) {
  if( suivante == NULL ){
     suivante = new Liste(val);
  } else {
     suivante->suffixer( val );
  }
  return *this;
}

LATER 后来

I think that would be the best way to keep it as close to the abstract concept as possible. 我认为这将是使其尽可能接近抽象概念的最佳方法。 Note that there is no "isEmpty" - this is done by a test whether the List * variable representing the list equals NULL, but you can't have a method for that. 请注意,没有“ isEmpty”-这是通过测试表示列表的List *变量是否等于NULL来完成的,但是您不能为此使用方法。

template<typename T>
class List {
public:
  List( T v, List* t = nullptr ) : value(v), next(t){}
  ~List(){ delete next; }
  List* prepend( T v ){
    return new List( v, this );
  }
  List* append( T v ){
    if( next == nullptr ){
      next = new List( v );
    } else {
      next->append( v );
    }      
    return this;
  }
  T head(){ return value; }
  List* tail(){ return next; }
  void dump(){
    List* curr = this;
    std::string del = "";
    while( curr != nullptr ){
      std::cout << del << curr->value;
      del = ", ";
      curr = curr->next;
    }
   std::cout << std::endl;
  }

private:
  T value;
  List* next;
};

int main(){
  typedef List<int> * intList;
  intList list = new List<int>( 1 );
  list->append( 2 )->append( 3 );
  list->dump();
}

for right this problem you most change this line 对于这个问题,您最会更改此行
Liste suffixer(int val) 李斯特后缀(int val)
to
Liste* suffixer(int val) Liste *后缀(int val)

and then change this line 然后更改此行
return *suivante; 返回* suivante;
to
return suivante; 退还
and in main use this line 主要使用这条线
uneListe.suffixer(5)->suffixer(8)->suffixer(10); uneListe.suffixer(5) - > suffixer(8) - > suffixer(10);
instead of 代替
uneListe.suffixer(5).suffixer(8).suffixer(10); uneListe.suffixer(5).suffixer(8).suffixer(10);

Your class methods Liste::prefixer(int val) and Liste suffixer(int val) will return a copy of the object created, they should return a pointer to the object (or a reference). 您的类方法Liste::prefixer(int val)Liste suffixer(int val)将返回创建的对象的副本,它们应返回指向该对象(或引用)的指针。

eg 例如

Liste *Liste::suffixer(int val){
    if(suivante == nullptr)
        suivante = new Liste(val);
    else
        throw std::runtime_error("Generic error message");

    return suivante;
}

or 要么

Liste &Liste::suffixer(int val){

    ... previous inner method ...

    return *suivante;
}

Here is the "fixed" version of my first attempt : 这是我第一次尝试的“固定”版本:

#include <iostream>
using namespace std;

class Liste {
private :
    int val;
    bool vide;
    Liste *suivante;
public :
    Liste(int val = 0, bool vide = true, Liste *suivante = NULL) {
        this->val = val;
        this->vide = vide;
        this->suivante = suivante;
    }
    void afficherElement() const {
        cout << "Adresse : " << this << endl;
        cout << "Valeur : " << val << endl;
        cout << "Vide : " << vide << endl;
        cout << "Adresse suivante : " << suivante << endl;
        cout << endl;
    }
    int head() const {
        return val;
    }
    Liste *reste() const {
        return suivante;
    }
    bool estVide() const {
        return vide;
    }
    Liste *prefixer(int val) {
        Liste *nouvelle = new Liste(val, this);
        return nouvelle;
    }
    Liste *suffixer(int val) {
        if(suivante == NULL) {
            suivante = new Liste(val);
            vide = false;
        }
        return suivante;
    }
};

void afficherListe(Liste *uneListe) {
    (*uneListe).afficherElement();
    if(!(*uneListe).estVide()) {
        afficherListe((*uneListe).reste());
    }
}

int main() {
    Liste *test = new Liste(3);
    (*test).suffixer(5);
    afficherListe(test);
    return 0;
}

As expected it's awfully unpractical. 不出所料,这是不切实际的。 Laune's solution looks good... However, the whole thing is bizarre, I suppose I'd be better off sticking with the regular List/Nodes way. Laune的解决方案看起来不错...但是,整个过程很奇怪,我想我最好还是坚持常规的List / Nodes方法。 Definitely gonna talk about that with my teacher. 绝对要和我的老师谈谈。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM