大阪環状線のような円環リストをつくる(Java)
大阪環状線のような終わりのない円環状リストをつくってみた。
まず、構成要素となる駅クラスを以下のように作成した。
package railway;
import java.util.Objects;
public class Eki {
String name;
Eki next = null;
Eki prev = null;
public Eki(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Eki other = (Eki) obj;
return Objects.equals(name, other.name);
}
@Override
public String toString() {
return name;
}
}
nextフィールド と prevフィールド を用意しておいた。
これは、たとえば「大阪」なら、nextが「天満」になり、
prevが「福島」になる。
次は、これを円環状にする EkiListクラスである。
package railway;
public class EkiList {
// 最初 EkiList のインスタンスを生成したときは、
// この head には、next も prev も null である
// Eki インスタンスが代入されている。
// しかし、EkiListがadd()コマンドにより生成されてのちは
// この head には、next には歳1番目の Eki インスタンスが
// 代入されている。
private Eki head = new Eki(null);
private int length = 0;
public Eki get(String name) {
Eki eki = head;
while (eki.next != null) {
eki = eki.next;
if (eki.name.equals(name)) {
return eki;
}
}
return null;
}
public void add(int num, String name) {
int i = 0;
Eki eki = head;
while (i < num) {
eki = eki.next;
i++;
}
// System.out.println(eki.next.name);
Eki nextEki = eki.next;
eki.next = new Eki(name);
eki.next.next = nextEki;
this.length++;
}
public void add(String name) {
Eki eki = head;
while (eki.next != null) {
eki = eki.next;
}
Eki newEki = new Eki(name);
eki.next = newEki;
newEki.prev = eki;
this.length++;
}
public int size() {
return this.length;
}
/**
* ekilist.add(福島) のあとで、ekilist.close("大阪") とすれば、
* ekilistは閉じられる。
* @param name
*/
public void close(String name) {
Eki eki = head;
while (eki.next != null) {
eki = eki.next;
}
Eki end = get(name);
eki.next = end;
end.prev = eki;
}
public void remove(String name) {
Eki eki = head;
while (!eki.next.name.equals(name)) {
eki = eki.next;
}
// System.out.println(eki.name);
Eki nextEki = eki.next.next;
eki.next = nextEki;
this.length--;
}
public String toString() {
StringBuilder sb = new StringBuilder();
Eki eki = head;
String headNextName = eki.next.name;
while(eki.next != null) {
eki = eki.next;
sb.append(eki.name + " ");
if (eki.next.name.equals(headNextName)) break;
}
return sb.toString();
}
}
EkiListクラスのインスタンスを作成したときに、
まず Eki型の head を宣言し、nameがnull、
nextもprevもnull というインスタンスを代入しておく。
private Eki head = new Eki(null);
ポイントとなるのは、add()メソッドである。
このメソッドは引数に String型の name をとる。
public void add(String name) {
Eki eki = head;
while (eki.next != null) {
eki = eki.next;
}
Eki newEki = new Eki(name);
eki.next = newEki;
newEki.prev = eki;
this.length++;
}
まず、Eki型のフィールドeki に headを代入している。
この head は name もnull であり、nextもprevも null である。
(1) EkiList作成の最初の駅「大阪」を add()した場合
headが代入された eki の eki.next は、当然nullなので、while(){} は実行
されない。
そして、新しいEkiインスタンス newEki を作成する。
Eki newEki = new Eki(name); // nameは"大阪"である
headが代入されている ekiのnextフィールドに このnewEkiを代入する。
また、大阪がセットされている newEkiのprevフィールドに
headが代入されいる eki を代入する。
head.name = null
head.next = newEki(大阪)
head.prev = null
newEki.name = "大阪"
newEki.next = null
newEki.prev = head
現時点では newEkiのprevには “head” がセットされているが、
将来 Eki「福島」が作成されれば、このprevにはEki「福島」が
セットされることになる。
(2) EkiListで駅「京橋」を add()した場合
「京橋」をadd()できる場所(Eki)まで移動する必要がある。
Eki eki に head を代入すると、そこが起点になる。
このheadは EkiListのクラス変数なので、EkiListを作成した
ときのheadになっている。
すなわち、headのnextフィールドには「大阪」がセットされている。
また、Eki「大阪」のnextフィールドには「天満」がセットされている。
そして、Eki「天満」のnextフィールドには「桜宮」がセットされている。
だから、while()文で、eki.nextがnullになるところ、すなわち「桜宮」
まで Eki をすすめているのである。
while (eki.next != null) {
eki = eki.next;
}
そして、「京橋」のEkiインスタンスを作成し、それを「桜宮」Ekiインスタンス
のnextフィールドにセットしている。
また、「京橋」のprevフィールドに「桜宮」をセットしている。
Eki newEki = new Eki(name);
eki.next = newEki;
newEki.prev = eki;
ほかにもいろいろとあるが、骨格となるのは、以上。
main()メソッドの例
public class Main {
static EkiList ekiList;
public static void main(String[] args) {
ekiList = new EkiList();
ekiList.add("大阪");
ekiList.add("天満");
ekiList.add("桜ノ宮");
ekiList.add("京橋");
...
ekiList.add("福島");
ekiList.close("大阪");
}
}
close()メソッドで、Eki「福島」のnextフィールドにEki「大阪」を、
Eki「大阪」のprevフィールドにEki「福島」をセットしている。
カテゴリー: Java, memo
タグ: LinkedList, 円環状リスト
カウント: 116