編集-以下に回答しましたが、中括弧を見逃しました。皆さんありがとう。
私は、他のプログラムで使用できる基本的な単一リンクリストを作成しようとしています。組み込み型とユーザー定義型で動作できるようにしたいと思います。つまり、テンプレート化する必要があります。
このため、格納する情報がわからないため、ノードもテンプレート化する必要があります。私は次のようにノードクラスを書きました-
template <class T> class Node
{
T data; //the object information
Node* next; //pointer to the next node element
public:
//Methods omitted for brevity
};
リンクリストクラスは別のクラスに実装されており、リストの最後に新しいノードを追加するときにノードをインスタンス化する必要があります。私はこれを次のように実装しました-
#include <iostream>
#include "Node.h"
using namespace std;
template <class T> class CustomLinkedList
{
Node<T> *head, *tail;
public:
CustomLinkedList()
{
head = NULL;
tail = NULL;
}
~CustomLinkedList()
{
}
//Method adds info to the end of the list
void add(T info)
{
if(head == NULL) //if our list is currently empty
{
head = new Node<T>; //Create new node of type T
head->setData(info);
tail = head;
}
else //if not empty add to the end and move the tail
{
Node* temp = new Node<T>;
temp->setData(info);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
}
//print method omitted
};
私は次のようにドライバー/テストクラスを設定しました-
#include "CustomLinkedList.h"
using namespace std;
int main()
{
CustomLinkedList<int> firstList;
firstList.add(32);
firstList.printlist();
//Pause the program until input is received
int i;
cin >> i;
return 0;
}
ただし、コンパイル時にエラーが発生します-エラーC2955: 'ノード':クラステンプレートの使用にはテンプレート引数リストが必要です-これは、addメソッドの次のコード行を示しています-
Node* temp = new Node<T>;
ドライバークラスで作成されたときにリンクリストに渡されたため、これにタイプに関する情報がない理由がわかりません。 タイプ情報をノードに渡すにはどうすればよいですか?
個別のクラスの代わりにプライベートノード構造体を作成し、両方のクラスのメソッドを1つのファイルに結合する必要がありますか?これで問題が解決するかどうかはわかりませんが、解決できると思います。可能であれば、別のクラスを用意したいと思います。
ありがとう、アンドリュー。
試してみたいかもしれません
Node<T>* temp = new Node<T>;
また、リストの設計方法のヒントを得るために、もちろんstd :: listを見ることができますが、少し気が遠くなることもあります。
答えはすでに出ていますが、私は塩の粒を追加すると思います。
テンプレートクラスを設計するときは、(ある日)特定の詳細を変更したい場合に備えて、テンプレート引数をほぼすべての場所で繰り返さないことをお勧めします。一般に、これはtypedefを使用して行われます。
template <class T>
class Node
{
public:
// bunch of types
typedef T value_type;
typedef T& reference_type;
typedef T const& const_reference_type;
typedef T* pointer_type;
typedef T const* const_pointer_type;
// From now on, T should never appear
private:
value_type m_value;
Node* m_next;
};
template <class T>
class List
{
// private, no need to expose implementation
typedef Node<T> node_type;
// From now on, T should never appear
typedef node_type* node_pointer;
public:
typedef typename node_type::value_type value_type;
typedef typename node_type::reference_type reference_type;
typedef typename node_type::const_reference_type const_reference_type;
// ...
void add(value_type info);
private:
node_pointer m_head, m_tail;
};
また、クラス宣言の外部でメソッドを定義することをお勧めします。これにより、インターフェイスが読みやすくなります。
template <class T>
void List<T>::add(value_type info)
{
if(head == NULL) //if our list is currently empty
{
head = new node_type;
head->setData(info);
tail = head;
}
else //if not empty add to the end and move the tail
{
Node* temp = new node_type;
temp->setData(info);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
}
さて、いくつかの意見:
insert
メソッドがSTLで行うように、List<T>::add
が新しく追加されたオブジェクトにイテレータを返す場合はよりユーザーフレンドリーになります(名前を変更して挿入することもできます)List<T>::add
の実装では、メモリをtemp
に割り当ててから、一連の操作を実行します。スローが発生した場合は、メモリリークが発生しています。setNextNull
呼び出しは必要ありません。Node
のコンストラクターは、すべてのデータメンバーをm_next
を含む意味のある値に初期化する必要があります。だからここに改訂版があります:
template <class T>
Node<T>::Node(value_type info): m_value(info), m_next(NULL) {}
template <class T>
typename List<T>::iterator insert(value_type info)
{
if (m_head == NULL)
{
m_head = new node_type(info);
m_tail = m_head;
return iterator(m_tail);
}
else
{
m_tail.setNext(new node_type(info));
node_pointer temp = m_tail;
m_tail = temp.getNext();
return iterator(temp);
}
}
適切なコンストラクターを使用するという単純な事実により、例外の安全性がどのように向上するかに注意してください。コンストラクター中に何かがスローされた場合、メモリを割り当てないためにnew
が必要になるため、何もリークされず、まだ操作を実行していません。 List<T>::insert
メソッドは復元力があります。
最後の質問:
単一のリンクリストの通常のinsert
メソッドは、簡単なため、最初に挿入されます。
template <class T>
typename List<T>::iterator insert(value_type info)
{
m_head = new node_type(info, m_head); // if this throws, m_head is left unmodified
return iterator(m_head);
}
最後にインサートを付けてよろしいですか?または、従来のベクトルとリストのPush_back
メソッドのために、このようにしましたか?
その行は読む必要があります
Node<T>* temp = new Node<T>;
Nodeクラスのnext
ポインタについても同じです。
述べたように、解決策は
Node<T>* temp = new Node<T>;
... Node
自体は型ではないため、Node<T>
です。
この方法で新しいノードを追加する必要があります
Node<T>* temp=new node<T>;
あなたが解決したことを願っています:)
必要なもの:
Node<T> *temp = new Node<T>;
この問題が再び発生するのを防ぐために、CustomLinkedList
クラスのtypedef NodeType = Node<T>
の価値があるかもしれません。
また、printlistでもNode * tempのテンプレートパラメータを指定する必要があります。
#include<iostream>
using namespace std;
template < class data > class node {
private :
data t;
node<data > *ptr;
public:
node() {
ptr = NULL;
}
data get_data() {
return t;
}
void set_data(data d) {
t = d;
}
void set_ptr(node<data > *p) {
ptr = p;
}
node * get_ptr() {
return ptr;
}
};
template <class data > node < data > * add_at_last(data d , node<data > *start) {
node< data > *temp , *p = start;
temp = new node<data>();
temp->set_data(d);
temp->set_ptr(NULL);
if(!start) {
start = temp;
return temp;
}
else {
while(p->get_ptr()) {
p = p->get_ptr();
}
p->set_ptr(temp);
}
}
template < class data > void display(node< data > *start) {
node< data > *temp;
temp = start;
while(temp != NULL) {
cout<<temp->get_data()<<" ";
temp = temp->get_ptr();
}
cout<<endl;
}
template <class data > node < data > * reverse_list(node<data > * start) {
node< data > *p = start , *q = NULL , *r = NULL;
while(p->get_ptr()) {
q = p;
p = p->get_ptr();
q->set_ptr(r);
r = q;
}
p->set_ptr(r);
return p;
}
int main() {
node < int > *start;
for(int i =0 ; i < 10 ; i ++) {
if(!i) {
start = add_at_last(i , start);
}
else {
add_at_last(i , start);
}
}
display(start);
start = reverse_list(start);
cout<<endl<<"reverse list is"<<endl<<endl;
display(start);
}
// file: main.cc
#include "linkedlist.h"
int main(int argc, char *argv[]) {
LinkedList<int> list;
for(int i = 1; i < 10; i++) list.add(i);
list.print();
}
// file: node.h
#ifndef _NODE_H
#define _NODE_H
template<typename T> class LinkedList;
template<typename T>class Node {
friend class LinkedList<T>;
public:
Node(T data = 0, Node<T> *next = 0)
: data(data), next(next)
{ /* vacio */ }
private:
T data;
Node<T> *next;
};
#endif//_NODE_H
// file: linkedlist.h
#ifndef _LINKEDLIST_H
#define _LINKEDLIST_H
#include <iostream>
using namespace std;
#include "node.h"
template<typename T> class LinkedList {
public:
LinkedList();
~LinkedList();
void add(T);
void print();
private:
Node<T> *head;
Node<T> *tail;
};
#endif//_LINKEDLIST_H
template<typename T>LinkedList<T>::LinkedList()
: head(0), tail(0)
{ /* empty */ }
template<typename T>LinkedList<T>::~LinkedList() {
if(head) {
Node<T> *p = head;
Node<T> *q = 0;
while(p) {
q = p;
p = p->next;
delete q;
}
cout << endl;
}
}
template<typename T>LinkedList<T>::void add(T info) {
if(head) {
tail->next = new Node<T>(info);
tail = tail->next;
} else {
head = tail = new Node<T>(info);
}
}
template<typename T>LinkedList<T>::void print() {
if(head) {
Node<T> *p = head;
while(p) {
cout << p->data << "-> ";
p = p->next;
}
cout << endl;
}
}