リストへの書き込み・削除に先頭/最後尾ノードを使わない方法とデストラクタの実装方法

このQ&Aのポイント
  • リストへの書き込みや削除に先頭/最後尾ノードを使わないプログラムに変更する方法を教えてください。
  • ディープコピーコンストラクタやoperator=を含むプログラムにデストラクタを実装する方法を教えてください。
  • ディープコピーコンストラクタやoperator=を含むプログラムにデストラクタをどのように追加すれば良いかわかりません。デストラクタの追加方法を教えてください。
回答を見る
  • ベストアンサー

先頭・最後尾ノードを使わないプログラムに変更。

下記のプログラムは、リストへの書き込み・削除のために先頭/最後尾ノードを利用していますが、このプログラムを先頭/最後尾ノードを使わない形のプログラムに変更するにはどうしたらいいですか? それと、プログラムはディープコピーコンストラクタとoperator=を含んでいるのですが、デストラクタをどう入れていいのかわからずにいます。デストラクタの入れ方も教えていただきたいです。よろしくお願いします。 #include <iostream> #include <string> using namespace std; class Node { public: Node(string s = ""); string name; Node *next; }; class LList { public: LList(); LList(LList& here); // ディープコピーコンストラクタ void Insert (string s); void Delete (string s); void Display (); void operator= (LList& here); private: Node *head; Node *Copy (); }; Node::Node(string s) { name = s; next = NULL; } LList::LList() { head = new Node ("AAAAA"); head -> next = new Node ("zzzzz"); } LList::LList (LList& here) { head = here.Copy(); } void LList::Insert (string s) { Node *here = head->next; Node *prev = head; while (s > here->name) { prev = here; here = here->next; } Node *newnode = new Node (s); newnode->next = here; prev->next = newnode; } void LList::Delete (string s) { Node *here = head->next; Node *prev = head; while (s != here->name && here->next != NULL) { prev = here; here = here->next; } if (here->next != NULL) { prev->next = here->next; delete here; } } void LList::Display() { Node *here = head->next; while (here->next != NULL) { cout << here -> name << endl; here = here -> next; } } Node* LList::Copy() { Node *start, *loc, *temp; temp = head; start = loc = new Node(temp->name); temp = temp->next; while(temp != NULL) { loc->next = new Node(temp->name); loc = loc->next; temp = temp->next; } return start; } void LList::operator= (LList& here) { head = here.Copy(); } int main() { LList list, copy; char option; string thisname; while (1) {cout << "Options: (I)nsert, (D)isplay, (R)emove, (E)xit"; cin >> option; cin.ignore(); switch (option) {case 'I': case 'i': cout << "Enter name: "; cin >> thisname; list.Insert(thisname); break; case 'D': case 'd': list.Display(); break; case 'R': case 'r': cout << "Enter name: "; cin >> thisname; list.Delete(thisname); break; case 'E': case 'e': copy = list; list.Insert("frank"); list.Insert("zebedee"); cout << "\n list: \n"; list.Display(); cout << "\n copy: \n"; copy.Display(); exit(0); } } }

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

とりあえず、どこまで理解しているのかソースにコメント付けるところから始めてみては?

参考URL:
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1037846585

関連するQ&A

  • 線形リストのコードでどーしても理解できない個所があります。

    線形リストのコードでどーしても理解できない個所があります。 (以下、コード部分) typedef struct __node { char name[20]; char tel[16]; struct __node *next; } Node; typedef struct { Node *head; Node *tail; } List; Node *AllocNode(void) { return ((Node *)calloc(1, sizeof(Node))); } /*--- 新たに生成したノードを先頭へ挿入 ---*/ void InsertNode(List *list, const char *name, const char *tel) { Node *ptr = list->head; list->head = AllocNode(); strcpy(list->head->name, name); strcpy(list->haed->tel, tel); list->head->next = ptr; } /*--- pが指すノードの直前にノードを挿入 ---*/ void PutNodeP(List *list, Node *p, const char *name, const char *tel) { if (p == list->head) InsertNode(list, name, tel); else { Node *temp = AllocNode(); if (p == list->tail) list->tail = temp; else *temp = *p; strcpy(p->name, name); strcpy(p->tel, tel); temp->next = p; } } 上の29行目以降の≪pが指すノードの直前にノードを挿入≫についてです。 if文部分については理解できますが、else文部分について、何をやっているのかわからないです。Cの基本的な部分(ポインタも含めて)については充分に理解しているつもりです。 どなたか御教授頂けないでしょうか。 長々と書いてしまいましたがよろしくお願いします。

  • java教えてください。

    双方向リストをjavaで書きたいんですけどここまで書いて双方向リストになってるか不安になってきました。 これは双方向リストになっていますか? class MyListw{ int data; MyListw next = null; //次のノードへのポインタ MyListw prev = null; //前のノードへのポインタ MyListw(int data){ this.data = data; } void insertTail(MyListw node){ //リストの最後へ追加 MyListw tmp = this; while(tmp.next != null){ tmp = tmp.next; } tmp.next = node; node.prev = tmp.next; } void insertHead(MyListw node){ //リストの先頭へ追加 node.next = this.next; this.next = node; node.prev = this.next; } void insert(int head, MyListw node){ //リストの途中へ新規データを挿入 MyListw tmp = this; while(tmp != null){ if(tmp.data == head){ break; } tmp = tmp.next; } node.next = tmp.next; tmp.next = node; node.prev = tmp.next; } void delete(int here, MyListw node){ //リストからデータを1つ削除 MyListw tmp = this; while(tmp != null){ if(tmp.data == here){ break; } tmp = tmp.next; } node = tmp.next; tmp.next.prev = node; tmp.next = node.next; node.next.prev = tmp.next; node.next = null; node.prev = null; } void deleteHead(){ //先頭のノードを削除 MyListw tmp = next; this.next = tmp.next; tmp.next.prev = this.next; tmp.next = null; tmp.prev = null; } void deleteTail(){ //最後のノードを削除 MyListw tmp = this; MyListw lastList = null; while(tmp.next != null){ lastList = tmp; tmp = tmp.next; } lastList.next = null; lastList.prev = null; } void show(){ MyListw tmp = next; while(true){ System.out.print(tmp.data); if(tmp.next == null) break; tmp = tmp.next; } System.out.println(""); } void showTail(){ } } class MyListwApp{ public static void main(String[] args){ MyListw list = new MyListw(0); //初期ダミー System.out.println("最後に追加"); list.insertTail(new MyListw(1)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insertTail(new MyListw(5)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("先頭に追加"); list.insertHead(new MyListw(8)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insertHead(new MyListw(9)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("途中からデータを追加"); list.insert(1, new MyListw(2)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insert(2, new MyListw(3)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("リストからデータを削除"); list.delete(8, new MyListw(1)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("先頭のノードを削除"); list.deleteHead(); //先頭のノードを削除 list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.deleteHead(); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("最後のノードを削除"); list.deleteTail(); //最後のノードを削除 list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.deleteTail(); list.show(); System.out.println("逆順に表示"); list.showTail(); } }

    • ベストアンサー
    • Java
  • C言語 二分木探索

    今、int型の二分木にデータを追加する関数(引数は二分木へのポインタと追加する値、追加されたノードへのポインタを返す)をつくろうとしてます。 以前リストにデータを追加する関数をつくったのでそれを変更してつくろうとしているのですが途中までいってつまってしまいました。 つくりかたを教えてください。 よろしくお願いします! struct BinaryTreeNode{ int data; struct BinaryTreeNode *l_next; struct BinaryTreeNode *r_next; }; struct BinaryTree{ int node_num; struct BinaryTreeNode *root; }; BinaryTreeNode *BinaryTreeNodeAlloc(void) { BinaryTreeNode *node; node = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode)); if (node == NULL) { return (NULL); } node->l_next = NULL; node->r_next = NULL; return (node); } BinaryTreeNode *BinaryTreeDataAdd(BinaryTree *list, int x) { BinaryTreeNode *ptr; BinaryTreeNode *prev; BinaryTreeNode *new_node; ptr = list->root; prev = NULL; while (ptr) {       ←?? if (ptr->data < x) { prev = ptr; ptr = ptr->next; } else if (ptr->data == x) { return (NULL); } else { new_node = BinaryTreeNodeAlloc(); if (new_node == NULL) { exit (0);                ←?? } new_node->data = x; new_node->next = ptr; if (prev != NULL) { prev->next = new_node; } else { list->head = new_node; } list->node_num++; return (new_node); } } new_node = BinaryTreeNodeAlloc(); if (new_node == NULL) { exit (0); } new_node->data = x; new_node->r_next = NULL; new_node->l_next = NULL; if (prev != NULL) { prev->next = new_node; } else { list->head = new_node; } list->node_num++; return (new_node); }

  • 教えて。

    双方向リストを書いているのですが、指定したノードの次に新たなノード追加以降からどうしてもうまくできません。 できればソースで教えてもらえれば助かります。 class MyListw{ int data; //データ MyListw next = null; MyListw prev = null; MyListw firstNode = null; MyListw lastNode = null; MyListw(int data){ this.data = data; } void insertTail(MyListw newNode){ if(lastNode == null) insertHead(newNode); else insertAfter(lastNode, newNode); } void insertHead(MyListw newNode){ if(firstNode == null){ firstNode = newNode; lastNode = newNode; newNode.prev = null; newNode.next = null; }else{ insertBefore(firstNode, newNode); } } void insertAfter(MyListw node, MyListw newNode){ //指定したノードの次に新たなノード追加 newNode.prev = node; newNode.next = node.next; if(node.next == null) lastNode = newNode; else node.next.prev = newNode; node.next = newNode; } void insertBefore(MyListw node, MyListw newNode){ //指定したノードの前に新たなノード newNode.prev = node.prev; newNode.next = node; if(node.prev == null) firstNode = newNode; else node.prev.next = newNode; node.prev = newNode; } void delete(MyListw node){ //リストからデータを1つ削除 if(node.prev == null) firstNode = node.next; else node.prev.next = node.next; if(node.next == null) lastNode = node.prev; else node.next.prev = node.prev; } void deleteHead(){ //先頭のノードを削除 delete(firstNode.next); } void deleteTail(){ //最後のノードを削除 delete(lastNode.prev); } void show(){ MyListw node = firstNode; while(node != null){ System.out.print(node.data); node = node.next; } System.out.println(""); } void showTail(){ MyListw node = lastNode; while(node != null){ System.out.print(node.data); node = node.prev; } } } class MyListwApp{ public static void main(String[] args){ MyListw list = new MyListw(0); //初期ダミー System.out.println("最後に追加"); list.insertTail(new MyListw(1)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insertTail(new MyListw(5)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("先頭に追加"); list.insertHead(new MyListw(8)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insertHead(new MyListw(9)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("指定したノードの次に新たなノード追加"); list.insertAfter(new MyListw(1), new MyListw(2)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insertAfter(new MyListw(2), new MyListw(3)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("指定したノードの前に新たなノード"); list.insertBefore(new MyListw(1), new MyListw(0)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("リストからデータを削除"); list.delete(new MyListw(1)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("先頭のノードを削除"); list.deleteHead(); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.deleteHead(); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("最後のノードを削除"); list.deleteTail(); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.deleteTail(); list.show(); System.out.println("逆順に表示"); list.showTail(); } }

  • なぜこの関数で、先頭ノードの次に挿入できるのかわからない。

    柴田さんのC言語による「アルゴリズムとデータ構造」の中に出てくるハッシュ表に線形リストを用いてデータを挿入するチェイン法のプログラムでわからない処理があります。 ハッシュ表のバケット(リストの先頭ノードを持つポインタ)に対してデータを追加していきます。 絵を添付しようと思ったのですが、なぜか添付できなかったので、柴田さんの本をお持ちの方やご存知の方にご回答お願いします。 ハッシュ表の7のバケットには13で割った余りが7になる値を次々に挿入していきます。すでに、33と20が挿入されている状態です。そこに、13で割ったあまりがこれも7になるリストを挿入します。挿入するときは、イメージにあるように、バケットの次に挿入します。 この新しいノードを挿入する処理を行っているのは関数InsertNodeです。 /*引数にハッシュ表と追加するx(この場合46)をもらってくる。*/ int InsertNode(Hash *h,Data x) { /*ハッシュ値(データを13で割った余り)をkeyに設定する。hashはそういう仕様の関数です。*/ int key=hash(x.no); /*Node型とはハッシュ表からつながっているリストのノード同士をつないだり、ノード自体のデータを格納する構造体型です。任意のノードであるpにハッシュ表の先頭要素であるバケットを挿入しています。*/ Node *p = h->table[key]; /*tempは新しく設定するノードの入れ物です。*/ Node *temp; /*このループ処理により任意のノードpをデータがないところまで移動させます。この場合、20→33と伝って次のNULLまで行きます。これはすでにデータが登録済みかどうかをチェックするための処理です。たとえば20を関数InsertNodeの引数として持ってきたとすればメイン関数に1を返します。*/ while(p!=NULL) { if(p->data.no ==x.no) { return 1; } p=p->next; } /ここまで/ /*46は登録済みではないので、tempに新しい領域を設定します。もしも確保に失敗すればメイン関数に2を返します。*/ if((temp = (Node*)calloc(1,sizeof(Node)))==NULL) { return 2; } /*わからないのはこの処理です。*/ SetNode(temp,x,h->table[key]); h->table[key] = temp; /*ここまで*/ /*関数SetNodeの仕様としてはこの場合で言えば新しく挿入するノードtempに対して値46を設定する。それに加えて、次のノードに引数でもらってきたh->table[key]をさすようにするというものです。ところが私の解釈では、h->table[key]は先頭要素の値であり、挿入させてもらった絵のイメージとは違ってきてしまうと思うのです。SetNodeに渡す引数として、(temp,x,先頭の次の要素)でセットするのではないでしょうか。SetNodeの呼び出しの次の行で先頭要素であるバケットに新しく挿入する値46を挿入しておりますますわけがわからなくなってしまっています。*/ void SetNode(Node *n,Data x,Node *next) { n->data=x; n->next=next; } return 0; } ところが、柴田氏の本に書かれているように記述すると私のイメージどおりに動いているようです。つまり私の解釈は間違っていることになります。上記の処理を解説していただきたいです。お手数ですが、よろしくお願いいたします。

  • スタックとキューの違いを示すプログラム。

    学校でスタックとキューの違いを示せという課題が出たのですが、どうしてもわからなかったので、苦し紛れに質問させていただきました…。 いろいろ情報を集めて分からないながらにも以下のプログラムを書いてみたのですがスタックはできてもキューが実現できません。 あまり内部の処理を書き変えずに以下のスタックのプログラムをキューに書き換えたいのですがどうしたらいいでしょうか? ポインタを利用した連結リスト構造です。 #include <stdio.h> #include <stdlib.h> struct Cell//構造体Cellの定義 { int element; Cell* p_prev; Cell* p_next; }; void Cell_Initialize(Cell* p)//要素を初期化用 { p->element = -1; p->p_next = NULL; p->p_prev = NULL; } void Push(Cell* p, int val) { Cell* p_temp = p; while(1) { if(p != NULL) { if(p_temp->p_next == NULL) { p_temp->p_next = (Cell*)malloc(sizeof(Cell));//新しいセルを作成するときのメモリの確保 Cell_Initialize(p_temp->p_next);//初期化 p_temp->p_next->element = val; p_temp->p_next->p_prev = p_temp; break; } else { p_temp = p_temp->p_next; } } } } int Pop(Cell* p) { Cell* p_temp = p; int temp; while(1) { if(p != NULL) { if(p_temp->p_next == NULL) { break; } else { p_temp = p_temp->p_next; } } } if(p_temp->p_prev != NULL) { temp = p_temp->element; p_temp->p_prev->p_next = NULL; free(p_temp); p_temp = NULL; return temp; } else if(p_temp->element != -1) { temp = p_temp->element; Cell_Initialize(p_temp); return temp; } return -1; } void main() { Cell* p_list = NULL; p_list = (Cell*)malloc(sizeof(Cell)); Cell_Initialize(p_list); for(int i = 1; i < 7; i++) { int temp; printf("%d文字目入力してください:",i); scanf("%d",&temp); Push(p_list, temp); } while(1) { int temp = Pop(p_list); if(temp != -1) { printf("[%d]\n\n",temp); } else { break; } } } 長文になってしまいすみません。 どなたかよろしくお願いします。

  • 双方向リストのバブルソートについて

    双方向リストをバブルソートを用いてソートしたいです。 下記がプログラム(一部)ですが、ソートした後にリスト表示すると 無限ループに陥ります。 どこがいけないのでしょうか。 #include <stdio.h> #include <stdlib.h> struct cell{ int data; struct cell *next, *prev; }; void insert_head(struct cell **head, int num){ struct cell *p, *p1; p = *head; p1 = make_cell(); *head = p1; p1->data = num; p1->next = p; if(p1->next != (struct cell *)NULL){ p1->next = p; p->prev = p1; } } void print_list(struct cell *head){ struct cell *p; p = head; printf("data = \n"); while(p != (struct cell *)NULL){ printf("%d\n", p->data); p = p->next; } } void sort_list(struct cell **head){ struct cell *p, *p2; int i, n; n = 0; p = *head; while(p->next != (struct cell *)NULL){ p = p->next; n++; } for(i = 0, p = *head; i < n-2; i++){ if(p->data > p->next->data){ if(p == *head){ *head = p->next; }else{ p->prev->next = p->next; } p2 = p->next; p->next = p->next->next; p->next->next = p; p->next->next->prev = p; p->next->prev = p->prev; p->prev = p2; }else p = p->next; } } int main(void){ struct cell *head = (struct cell *)NULL; int n; while(1){ printf("1:Insert head 2:Insert tail 3:Delete 4:List 5:Sort 6:Exit\n"); scanf("%d", &n); switch(n){ case 1: printf("num = "); scanf("%d", &n); insert_head(&head, n); break; case 2: printf("num = "); scanf("%d", &n); insert_tail(&head, n); break; case 3: printf("num = "); scanf("%d", &n); delete_cell(&head, n); break; case 4: print_list(head); break; case 5: sort_list(&head); break; case 6: return 0; break; } } }

  • データ構造のプログラム

    #include <stdio.h> struct node{ char no; struct node *next; }; struct node head; int main(void) { struct node *new, *cur; char n; while(1){ scanf("%s", &n); if(n=='-'){ break; } new=(struct node*)malloc(sizeof(struct node)); if(new==NULL){ printf("error\n"); return(0); } new->no=n; new->next=head,next; head.next=new; } cur=head.next; while(cur!=NULL); printf("%s",cur); putchar('\n'); cur=cur->next; } free(new); new=free; return(0); } 上のプログラムを書き換えて (1),’-’が入力されたとき文字の入力を終了しそれまでに格納された文字を出力せよ。 ただし、リストに格納する際リストの最後に格納するようにせよ。 例 a(入力) b(入力) c(入力) -(入力) a(出力) b(出力) c(出力) (2),’-’が入力された後,次に入力された文字を持つ要素をリストから削除し、 最後にリスト中の全て文字を出力するようにせよ 例 a(入力) b(入力) c(入力) -(入力) b(入力) c(出力) a(出力) このような問題なのですが、分かりません。 どなたか教えてください。

  • C言語の自己参照型プログラムについて

    #include <stdio.h> #include <string.h> #include <stdlib.h> struct list { int key; /* キー */ char name[20]; /* 名前 */ struct list *next; /* 次のデータへのポインタ */ }; struct list *add_list(int key, char *name, struct list *head); void show_list(struct list *p); void free_list(struct list *p); int main(void) { struct list *head; /* 先頭ポインタ */ char name[20]; int key = 0; head = NULL; /* 先頭ポインタにNULLを設定 */ printf("キーと名前(MAX:19文字)を入力(終了:CTRL+Z)\n"); while (scanf("%d %s", &key, name) != EOF) { /* リストにデータを登録 */ head = add_list(key, name, head); } /* リストの表示 */ show_list(head); /* リストの開放 */ free_list(head); return 0; } /*** リストにデータを登録 ***/ struct list *add_list(int key, char *name, struct list *head) { struct list *p; /* 記憶領域の確保 */ if ((p = (struct list *) malloc(sizeof(struct list))) == NULL) { printf("malloc error\n"); exit(EXIT_FAILURE); } /* リストにデータを登録 */ p->key = key; strcpy(p->name, name); /* ポインタのつなぎ換え */ p->next = head; /* 今までの先頭ポインタを次ポインタに */ head = p; /* 新たな領域を先頭ポインタに */ return head; } /*** リストの表示 ***/ void show_list(struct list *p) { while (p != NULL) { /* 次ポインタがNULLまで処理 */ printf("%3d %s\n", p->key, p->name); p = p->next; } } /*** リストの開放 ***/ void free_list(struct list *p) { struct list *p2; while (p != NULL) { /* 次ポインタがNULLまで処理 */ p2 = p->next; free(p); p = p2; } } これを実行すると、 新しく入力された順にリストが表示されます。 そうではなく、キーの昇順に表示したいです。 どなたかそのように実行できるようにプログラムを書き換えてくれませんか? 図々しいですがよろしくお願いいたします。m(_ _)m

  • C#の連結リストがわかりません。

    最近、C#をちゃんとやろうと思い、勉強のためのコードを見ていたのですが以下の連結リストについてわかりません。わからないところにコメントをつけました。呼び出しメソッドはList.Add(2);です。よろしくお願いいたします。 using System; using System.IO; class Node { public int elem; public Node next; public Node() : this(0, null){}//このメソッドがある意味がわかりません。 public Node(int val, Node next) { this.elem = val; this.next = next;//なぜか最初にnextにデバッグするとnullになりますが2回目デバッグからはNodeになります。そもそもなぜクラスにクラスを代入しているかもわかりません。 } } /// <summary> /// 連結リストクラス /// </summary> class List { public Node head; public List() { head = null; } public void Add(int val) { Node node = new Node(val, this.head); this.head = node; } }

専門家に質問してみよう