web-dev-qa-db-ja.com

リンクリストをC ++でコピーする関数のコーディング

1つのパラメーター、ListNodeへのポインターを持つcopyListという名前の補助関数を実装する必要があります。この関数は、元のリンクリストのコピーの最初のノードへのポインタを返す必要があります。つまり、リンクリストのヘッダーノードを取得し、そのリンクリスト全体をコピーして、新しいヘッダーノードへのポインターを返すC++の関数をコーディングする必要があります。私はこの機能を実装するのに助けが必要です、そしてこれは私が今持っているものです。

Listnode *SortedList::copyList(Listnode *L) {

    Listnode *current = L;  //holds the current node

    Listnode *copy = new Listnode;
    copy->next = NULL;

    //traverses the list
    while (current != NULL) {
       *(copy->student) = *(current->student);
       *(copy->next) = *(current->next);

        copy = copy->next;
        current = current->next;
    }
    return copy;
}

また、これは私が使用しているListnode構造です。

struct Listnode {    
  Student *student;
  Listnode *next;
};

注:この関数で遭遇するもう1つの要因は、ローカル変数へのポインターを返すという考えです。

12
Pat Murray

自分自身に尋ねる必要がある最初の質問は、コピーのセマンティクスが何であるかです。特に、ノードの内容としてStudent*を使用しています。ノードの内容をコピーするとはどういう意味ですか? 2つのリストが同じ学生インスタンスを指す(共有する)ようにポインタをコピーする必要がありますか、それとも ディープコピー を実行する必要がありますか?

struct Listnode {    
  Student *student; // a pointer?  shouldn't this be a `Student` object?
  Listnode *next;
};

次の質問は、2番目のリストにノードをどのように割り当てるかです。現在、コピーに割り当てるノードは1つだけです。

コードは次のようになります。

Listnode *SortedList::copyList(Listnode *L) {

    Listnode *current = L;

    // Assume the list contains at least 1 student.
    Listnode *copy = new Listnode;
    copy->student = new Student(*current->student);
    copy->next = NULL;

    // Keep track of first element of the copy.
    Listnode *const head = copy;

    // 1st element already copied.
    current = current->next;

    while (current != NULL) {
       // Allocate the next node and advance `copy` to the element being copied.
       copy = copy->next = new Listnode;

       // Copy the node contents; don't share references to students.
       copy->student = new Student(*current->student);

       // No next element (yet).
       copy->next = NULL;

       // Advance 'current' to the next element
       current = current->next;
    }

    // Return pointer to first (not last) element.
    return head;
}

2つのリスト間で学生インスタンスを共有したい場合は、

copy->student = current->student;

の代わりに

copy->student = new Student(*current->student);
5
André Caron

これはexcellentの質問です。あなたは自分で仕事の大部分を行ったので、ほとんどの「宿題をしてください」の質問よりもはるかに優れています。

いくつかのポイント。

まず、空のリストを渡すとどうなりますか?おそらくそれを前もってキャッチして、空のリストを呼び出し元に返すだけです。

次に、コピーリストの最初のノードのみを割り当てます。元のリストのノードごとに1つ割り当てる必要があります。

(宿題の擬似コード(ただしC++のような)、申し訳ありません)のようなもの:

# Detect empty list early.

if current == NULL:
    return NULL;

# Do first node as special case, maintain pointer to last element
# for appending, and start with second original node.

copy = new node()
last = copy

copy->payload = current->payload
current = current->next

# While more nodes to copy.

while current != NULL:
    # Create a new node, tracking last.

    last->next = new node()
    last = last->next

    # Transfer payload and advance pointer in original list.

    last->payload = current->payload
    current = current->next

# Need to terminate new list and return address of its first node

last->next = NULL
return copy

そして、ローカルスタック変数へのポインタを返すべきではないというのは正しいのですが、それはnotあなたがしていることです。返す変数はヒープ割り当てメモリを指します。これは関数の終了後も存続します。

2
paxdiablo

私も同じことをしようとしています。私の要件は次のとおりです。

1。各ノードは非常に基本的で単純なクラスです(私は構造体モデルから離れました)。
2。古いリンクリストへのポインタだけでなく、ディープコピーを作成したいと思います。

これを行うために選択した方法は、次のC++コードを使用することです。

template <class T>
Node <T> * copy(Node <T> * rhs)
{
    Node <T> * current = new Node<T>();
    Node <T> * pHead = current;
    for (Node <T> * p = rhs; p; p = p->pNext)
    {
        Node <T> * prev = current;
        prev->data = p->data;
        if (p->pNext != NULL)
        {
            Node <T> * next = new Node<T>();
            prev->pNext = next;
            current = next;
        }
        else
        {
            prev->pNext = NULL;
        }
    }
    return pHead;
}

これはエラーなしでうまく機能します。 「頭」は特殊なケースであるため、「現在の」ポインタを実装する必要があります。

1
CtheGood

ステートメントcopy->next = current->next 間違っている。やったほうがいい

Create the first node copy here
copy->student = current->student;
copy->next = NULL;
while(current->next!=NULL)
{
    Create new node TEMP here
    copy->next = TEMP;
    TEMP->student = current->student;
    TEMP->next = NULL;
    copy = TEMP;
}
0
noMAD

リンクリストのcopyが必要なため、元のリストをトラバースしながら、ループ内に新しいノードを作成する必要があります。

Listnode *startCopyNode = copy;

while (current != NULL) {
   *(copy->student) = *(current->student);
    copy->next = new Listnode;
    copy = copy->next;
    current = current->next;
}

copy->next = NULL;
return startCopyNode;

リンクリストのノードをdeleteすることを忘れないでください。

0
Mahesh

@pat、メモリを1回だけ作成するため、seg_faultが発生すると思います。すべてのノードに対してメモリを作成する必要があります(基本的には「new」と呼びます)。 'new'キーワードを使用して、すべてのノードのメモリを作成する必要がある場所を見つけます。

これが完了したら、前のノードにリンクする必要があります。これは、単一リンクリストであるため、前のノードへのポインターを維持する必要があります。あなたが学びたいと思っていて、すべての人生を思い出すことができるはずであるならば、上記のコードのどれも見ないでください。上記の要因を考えて、独自のコードを考え出すようにしてください。

0

他の人が指摘しているように、コピー用のスペースを割り当てるには、元のリストのeachノードに対してnewを呼び出してから、古いノードを新しいノードにコピーして、ポインターを更新する必要があります。コピーされたノードで。

この関数で私が遭遇しているもう1つの要因は、ローカル変数へのポインターを返すという考えです。

ローカル変数へのポインタを返していません。 newを呼び出すと、ヒープにメモリが割り当てられ、そのポインタが返されます(もちろん、作業が終了したら、deleteを呼び出してメモリを解放することを忘れないでください。新しいリスト、外部関数から)。

0
Synetech