• ベストアンサー

Singly linked listで最後から二番目に挿入

先週、テストがありました。 結構自信があったんですが、教授によるとすごく悪かったそうです…(結果はまだもらっていません)。 それで「問題全部、もう一度家でやり直してこい」と言われました。 下がその問題の一つです。 Write a method to insert a new node into a singly linked list before the tail node. If the list is empty, then the new node will be both the head and the tail node. This method will be a member of IntSLList class given on page 74. public void addBeforeTail(int el) { // ブランク そのIntSLList.javaはIntNode.javaとセットで使われます(でもどちらもmainがないんです)。 そしてここ↓にあります。 http://www.mathcs.duq.edu/drozdek/DSinJava/. (きっと)基となるメソッド(IntSLList.java内) public void addToTail(int el) { if (!isEmpty()) { tail.next = new IntNode(el); tail = tail.next; } else head = tail = new IntNode(el); } 私自作のメソッド public void addBeforeTail(int el) { if (!isEmpty()) { tail = new IntNode(el); tail.next = tail; } else head = tail = new IntNode(el); } リストの最後の一つ手前に挿入するんでしょうが Double linked listならnextとpreviousがあって tail.previous = new IntNode(el); tail = tail.previous; にすれば解決だと思うのですが、 Singlyだとnextしかないのでどうすればいいのかはっきり分かりません。 勘で基となるだろうメソッドを逆にしてみました。 上の私自作のメソッドであってますでしょうか? Javaの神様、どうかお助け下さい。m(__)m

  • ginkgo
  • お礼率94% (132/139)
  • Java
  • 回答数4
  • ありがとう数5

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

  • ベストアンサー
  • takaP-
  • ベストアンサー率79% (83/105)
回答No.4

public void addBeforeTail(int el) {  if (isEmpty()) {   addToHead(el);  }  else if (head==tail) {   head=new IntNode(el,tail);  }  else {   IntNode tmp;   for (tmp=head; tmp.next!=tail; tmp=tmp.next);   tmp.next=new IntNode(el,tail);  } } ↑の訂正です↓ public void addBeforeTail(int el) {  if (isEmpty() || head==tail) {   addToHead(el);  }  else {   IntNode tmp;   for (tmp=head; tmp.next!=tail; tmp=tmp.next);   tmp.next=new IntNode(el,tail);  } } 空でも1つでも addToHead() でいけますね。 失礼。

ginkgo
質問者

お礼

ありがとうございます。 間違いには気付きましたがもうだめぽいです。 忙しすぎて咀嚼せずに飲み込むような勉強しかできないんですよね、明日もまた授業が…。 もういっそ回線切って首[以下略]

その他の回答 (3)

  • takaP-
  • ベストアンサー率79% (83/105)
回答No.3

>public int addBeforeTail() { >int el = tail.info; >if (head == tail) // if only one node in the >list; >head = tail = null; >else { // if more than one node in the list, >IntNode tmp; // find the predecessor of tail; >for (tmp = head; tmp.next != tail; tmp = >tmp.next); >tail = new IntNode(el); >tail.next = tail; >} >return el; >} ん?? public void addBeforeTail(int el) {  if (isEmpty()) {   addToHead(el);  }  else if (head==tail) {   head=new IntNode(el,tail);  }  else {   IntNode tmp;   for (tmp=head; tmp.next!=tail; tmp=tmp.next);   tmp.next=new IntNode(el,tail);  } } こんな感じじゃないでしょうか(もっと綺麗に書けるかもしれないけど・汗) そもそも、引数無しではどうにもやり様がないはずですよ。 他にも。。。 public void addBeforeTail(int el) {  if (isEmpty()) {   addToHead(el);  }  else {   int i=deleteFromTail();   addToTail(el);   addToTail(i);  } } という手もありますが、厳密な意味での連結リストの挿入法からは外れるでしょうから、やはり最初のような処理が良さそうな気がしますね(継承を使うならこれになるでしょうけど) 間に合えば良いのですが。。。

ginkgo
質問者

お礼

あーっ、tail.nextではなくて、tmp.nextだっとわぁーっ!! せっかく最後から二番目の位置見つけたのに使ってない…。 小さい勘違い、大きな減点…ああ、激しく鬱です。 もう提出したので逆立ちしても間に合いません(泣)。 崖っぷちはもう通り越して落っこちたようです。 はぁー…鬱です、鬱です、欝です。 ありがとうございました。

noname#30871
noname#30871
回答No.2

 図でも描いて落ち着いて考えれば簡単です。  単方向連結リストの先頭要素をH、末尾要素をTとすれば H→…→T    ...(a) と表現できます。これは大丈夫でしょうか。 また、「末尾の一つ前の要素」をPとすれば、(a)は H→…→P→T     ...(b) と描くことができます。  さて、上記の連結リストに新たな要素Nを挿入します。Nはどこに入るでしょうか。答は H→…→P→N→T     ...(c) となりますね。つまり、今回のメソッドでは(c)を作ればよいのです。もう少し噛み砕いて言えば、メソッドの中では (1) Pを求める。 (2) Nをnewする。 (3) PとNを連結する。 (4) NとTを連結する。 という手順になります。Pの求め方は、#1のご回答のとおり。  ところで、そんなに回答を求めているのであれば、せめて問題文の和訳を付けるべきです。Javaができる人が英語を読めるとは限りません。

ginkgo
質問者

お礼

>問題文の和訳 すみませんでした。 以前「みんな英語が読めるはずだから和訳なんかつけるな」ってクレームがついたんで(しかもその人、回答もせずにクレームだけでした)、書かないことにしたんです。 でも、プログラムのが得意な人がみんな英語が出来るとは限りませんよね。 次回は付けます。 私の成果のほどはどうでしょうか? 正直、まだ慣れてないのでコピーして修正するのが精一杯です。 間違っていたらご指摘下さい。 ありがとうございました。

ginkgo
質問者

補足

只今、奮戦中です。しばらくお待ち下さい。m(__)m

  • m_hagizo
  • ベストアンサー率65% (31/47)
回答No.1

>上の私自作のメソッドであってますでしょうか? はっきり言ってしまうと、間違っています。 考え方としては、どうにかしてtailの1個前のノードのnextを書き換えてあげなければいけません。 では、previousが無いのにどうやってtailの1個前のノードを知るのか、というと、そのヒントはIntSLListのdeleteFromTailというメソッドにあります。 deleteFromTailでは、tailの1個前のノードを発見し、そのノード自体をtailにセットすると共に、nextにnullをセットすることで、「次のノードはなくなっている」ということを認識させています。 これを応用すれば、tailの1個前のノードに新しいノードを追加することは容易でしょう。 敢えてズバリな回答は控えておきます。 ちなみに、このクラスにmainメソッドがないのは、様々なプログラムで利用されることを前提にしているためです。自分で、以下のような感じに、このクラスをテストするクラスを作って試してみるとよいでしょう。 public class RunTest { public static void main(String[] args) { IntSLList list = new IntSLList(); list.addToTail(30); list.addToTail(50); list.addToTail(100); list.printAll(); System.out.println(); list.addToHead(10); list.printAll(); System.out.println(); list.addBeforeTail(80); list.printAll(); System.out.println(); } }

ginkgo
質問者

お礼

出来ましたーっ(多分)。 では成果のほどを。 public int addBeforeTail() { int el = tail.info; if (head == tail) // if only one node in the list; head = tail = null; else { // if more than one node in the list, IntNode tmp; // find the predecessor of tail; for (tmp = head; tmp.next != tail; tmp = tmp.next); tail = new IntNode(el); tail.next = tail; } return el; } 最後から二番目を見つけるまではdeleteFromTailとまったく同じです。 それからは普通に現在のtailに新しいノードを追加してtail.nextをtailにしました。 これでいいんですよね? 実はもう提出しました。 時間がなかったので焦って 最後のreturn el;と}、忘れちゃいました… 教授、そんな細かいことで点ばっさり引かないでね(と祈る私)。 もう一日だけ締め切らずにおきます。 あっているようであれば返事はいりませんが、 間違っているようであれば指摘してやって下さい。 ありがとうございました。

ginkgo
質問者

補足

基にすべきだったのはdeleteFromTailだったんですね! 只今、奮戦中です。しばらくお待ちください。m(__)m

関連するQ&A

  • 今度はcircular singly linked listです…

    度々、すみません。切羽詰っています(汗)。 Write a method to insert a node at the front of a circular singly linked list. The circular list maintains only one reference to the tail node as shown in figure 3.15 on page 91.                     tail                     ↓  →|10|→...→|5|→|20|- |                        |  ----------------- Add 100                             tail                             ↓  →|100|→|10|→...→|5|→|20|- |                              |  --------------------- (きっと)基となるメソッド public void addToTail(int el) { if (isEmpty()) { tail = new IntNode(el); tail.next = tail; else { tail.next = new IntNode(el, tail.next); tail = tail.next; } } 私自作のメソッド public void addToFront(int el) { if (isEmpty()) { tail = new IntNode(el); tail.next = tail; else { tail = new IntNode(el, tail); tail.next = tail; } } if文のisEmptyの部分は正解だそうです。 ただ、else文の中が間違っているそうです。 勘でtailとtail.nextをそっくり逆にしたんですけど 駄目だったようです。 でも他にもう案は浮かびません。 リンクの神様、どうかお助け下さい。m(__)m

    • ベストアンサー
    • Java
  • 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; } }

  • リストがわかりません。

    下のプログラムはリストに昇順になるように 入力された要素を挿入するプログラムですが、うまくいきません。どうか教えてください。 #include<stdio.h> static int count; struct node_tag{ int data; struct node_tag *next; }; typedef struct node_tag node_t; node_t *insert_node( node_t *t, int d ); node_t *print_list( node_t *r ); int main( void ) { node_t root; int data; root.next = NULL; for ( ;; ) { printf( "> " ); if ( scanf( "%d", &data ) != 1 ) break; insert_node( &root, data ); print_list( &root ); } return; } node_t *insert_node( node_t *t, int d ) { node_t *new_node; new_node = (node_t *)malloc( sizeof(node_t) ); if( new_node == NULL ) return NULL; if(count == 0) { new_node -> data = d; new_node -> next = NULL; t -> next = new_node; count++; } else { for(; t -> next != NULL; t = t -> next) { if(t -> next -> data >= d) break; } if(t -> next -> data == d) return; else if(t -> next -> data > d) { new_node -> data = d; new_node -> next = t -> next; t -> next = new_node; } else if(t -> next == NULL) { new_node -> data = d; t -> next = new_node; new_node -> next = NULL; } } return new_node; } node_t *print_list( node_t *r ) { node_t *p; printf("[ "); for( p = r -> next; p != NULL; p = p -> next) { printf("%d ", p -> data); } printf("]\n"); }

  • Javaで単方向リスト作成に行き詰まり

    Javaで単方向リストを作成しようとしているのですが、append()で1件目のvalueやnextの値をアクセスするにはどうしたらいいか分かりません。ちなみにmain関数は変更しなくていいようです。 class Chain{ public static void main(String args[]){ //1件目のノードの作成 if(args.length == 0){ System.out.println("パラメータを指定してください"); return; } Node start = new Node(Integer.parseInt(args[0])); //2件目のノード作成 for(int i = 1; i < args.length; i++){ start.append(Integer.parseInt(args[i])); } } } class Node{ //メンバ変数(インスタンス変数) private int value; private Node next; //コンストラクタ public Node(int value, Node next){ this.value = value; this.next = next; } public Node(int value){ this.value = value; } public Node(){ this.value = 0; this.next = null; } //アクセスメソッド(setter, getter) public int getValue(){ return value; } public void setValue(int value){ this.value = value; } public Node getNext(){ return next; } public void setNext(Node n){ this.next = n; } //通常のメソッド //追加する public void append(int v){ Node chain = new Node(); chain.value=chain.getValue(); System.out.println(chain.value); } }

    • ベストアンサー
    • Java
  • 今度はdoubly linked listの問題です…

    今日はかなり崖っぷちなのでどんどん質問します、すみません。 今回はdoubly linked listの質問です。 Consider the doubly linked list below. After each of the following statements, redraw the list to show the changes that have been made. Process the statements in sequence, that is, each statement should make changes in the list modified by the previous statement. head->|10| |/|            ↓ ↑       | 5| | |            ↓ ↑       |20| | |            ↓ ↑ tail ->|30| | | 1. head.next.next.prev.info = 100; 2. head.next.next.next = tail.prev.prev; 3. heat.next.prev = head.next.next.next.next; ※/はヌル(=Null)の意味です。 (これで分かってくださるといいんですが) 1.と2.は正解だそうです: 1.は上から二番目の5を100に変えました。 2.は上から三番目のnextが今変えたばかりの100を参照するようにしました。 そして問題の3.です。 head.next.prevですからnext(一番目)が二番目を参照して、 prevが今度は一番目を参照するので今現在"/"があるところを… head.next.next.next.nextに変更ですから 最初のnext(一番目)が二番目を参照して、 二番目のnextが三番目を参照して、 三番目のnextは2.で変更したとおり、二番目を参照して、 四番目のnextは三番目を参照するので… "/"のprevがずーーーっと伸びて20を参照するように書きました。 でも、間違っているらしいです。 どこがおかしいのでしょうか? プログラミングの神様、どうかお助け下さい。m(__)m

  • list構造。。。

    リストの末尾にデータを追加すると、最後に追加したデータで今までのリストのデータが上書きされてしまいます。。 以下に、ソースを掲載させていただきます。 void SetNode(List* node_first, List* node_second, int *data) { node_first->move = data; node_first->next = node_second; return ; } /*末尾に挿入*/ void Insert_Tail(List **head, int* data) { List *ptr = *head; if(ptr == NULL){ *head = (List*)calloc(1,sizeof(List)); SetNode(*head, NULL, data); return ; }else{ while(ptr->next != NULL){ ptr = ptr->next; } ptr->next = (List*)calloc(1,sizeof(List)); SetNode(ptr->next, NULL, data); } return ; } void show_list(List *list) { List *ptr = list; while(ptr != NULL){ printf("%d\n",*(ptr->move)); ptr = ptr->next; } return ; } int main(int argc, char** argv) { /*宣言*/ Node* root; /**/ List* top; /* 手順のリスト */ int judge; top = NULL; do{ printf("num:"); scanf("%d",&judge); switch(judge){ case 1: /*データを末尾に追加*/ printf("mem:"); scanf("%d",mem); root->board = mem; Insert_Tail(&top, root->board); break; case 2: /*リストを頭から表示*/ show_list(top); break; default: break; } }while(judge != 0); return 0; } 自分は最後のリストまでたどって、callocしたつもりなのですが、どうもそうではないようで、困っています。 どうか、御指導の程、お願いします。

  • List構造

    Listの尻にノードを追加する関数で困っています。 以下に、ソースの一部を掲載させていただきます。 typedef struct __node{ int data; struct __node *next; }Node; ... /*リストの尻にノードを追加する関数 * 引数: head. リストの先頭ノードのポインタ data. リストの尻に追加したいint型の変数*/ void Insert_Tail(Node *head, int data) { Node *ptr = head; if(ptr == NULL){ /*<ノードが存在しない時には追加されない>*/ /*領域の確保*/      head = (Node*)calloc(1,sizeof(Node)); /*データをセット*/ head->data = data; head->next = NULL; return ; }else{ /*<ノードが存在するときには正常に動作>*/ while(ptr->next != NULL){ ptr = ptr->next; } /*領域の確保*/ ptr->next = (Node*)calloc(1,sizeof(Node));      /*データのセット*/ ptr->next->data = data; ptr->next->next = NULL; } } コメントアウトにも書かせていただきましたが、ノードがすでに存在するときには、正常にノードの最後に追加してくれるのですが、ノードが存在しない時にはリストに追加してくれません。 どうかご指導、ご指摘の程お願いします。

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

    線形リストのコードでどーしても理解できない個所があります。 (以下、コード部分) 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の基本的な部分(ポインタも含めて)については充分に理解しているつもりです。 どなたか御教授頂けないでしょうか。 長々と書いてしまいましたがよろしくお願いします。

  • 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); }

  • C++ 連結リストの結合について

    現在、C++で連結リストの結合を実現しようとしているのですが、自分のやり方ではどうしてもエラーになってしまい、他にうまい実現方法が思いつかないので質問させていただきます。 以下が私が作ったプログラムなのですが、どこをどう変えたらうまく行くのか、具体的に教えて頂けたら嬉しいです。結合関数はaddAll(List &l)です。よろしくお願いします。 #include <iostream> using namespace std; class Cell{ private: int data; Cell *next; public: Cell(int d, Cell *n = NULL){ data = d; next = n; } friend class List; }; class List{ private: Cell *head; public: List(){ head = NULL; } ~List(){ while (head != NULL)removeFirst(); } void addLast(int data); void removeFirst(); void print(); void addAll(List &l); }; void List::addLast(int data){ if (head == NULL){ head = new Cell(data); } else{ Cell *p = head; while (p->next != NULL){ p = p->next; } p->next = new Cell(data); } } void List::removeFirst(){ if (head == NULL){ return; } else if (head->next == NULL){ delete head; return; } Cell *removed = head; head = head->next; delete removed; } void List::print(){ if (head == NULL){ return; } for (Cell *p = head; p != NULL; p = p->next){ cout << p->data << ' '; } cout << endl; } void List::addAll(List &l){ if (l.head == NULL){ return; } else if (head == NULL){ if (l.head == NULL){ return; } else{ head = l.head; return; } } else{ Cell *p = head; while (p->next != NULL){ p = p->next; } p->next = l.head; } return; } int main(){ List l1; l1.addLast(1); l1.addLast(2); l1.addLast(3); l1.print(); List l2; l2.addLast(4); l2.addLast(5); l2.addLast(6); l1.addAll(l2); l1.print(); return 0; } 実行結果は 1 2 3 1 2 3 4 5 6 と表示されればOKです

専門家に質問してみよう