Javaにおけるスタックデータ構造
メニューを表示するにはスワイプしてください
Stackは、後入れ先出し(LIFO)の原則に従うデータ構造。前述のDequeにも同じ原則が適用され、Java開発者はLIFO原則で動作する必要がある場合、Dequeの使用を推奨。Stackデータ構造は時代遅れであり、現代のJava開発では推奨されていない。
ただし、推奨されなくなった、または非推奨となったコレクションも存在。
非推奨
要素が非推奨としてマークされている場合、ライブラリやプログラミング言語の作者が新しいコードでの使用を避けることを推奨し、より安全で効率的、または機能的な新しいメソッド、クラス、アプローチの採用を勧めていることを意味する。
例として、Java の Vector クラスがあります。そのメソッドは、より現代的なコレクションである ArrayList や LinkedList が推奨されるため、非推奨となっています。プログラマーが Vector のメソッドを使用すると、コンパイラが これらのメソッドが非推奨であるという警告を出す場合があります。
Java の例:
Main.java
12345678910111213141516package com.example; import java.util.Vector; public class Main { public static void main(String[] args) { Vector<String> vector = new Vector<>(); // Adding an element (this method is deprecated) vector.addElement("Item"); // Compiler warning about the deprecated method // Note: 'addElement(java.lang.Object)' is deprecated. System.out.println(vector.get(0)); } }
したがって、Stack のようなデータ構造の使用は推奨されませんが、本章ではこのデータ構造について説明します。なぜなら、これは興味深いデータ構造であり、例えば Java の Stack memory などで使用されているためです。
スタック
要点のみ、Stack クラスのメソッドを見ていきます。
メソッド
push(E element): 要素をスタックの一番上に追加。
Main.java
123456789101112package com.example; import java.util.Stack; public class Main { public static void main(String[] args) { Stack<String> stack = new Stack<>(); stack.push("One"); stack.push("Two"); System.out.println("Stack: " + stack); } }
追加は ArrayList と同様に行われるため、このメソッドと pop() メソッドを組み合わせてすぐに見てみましょう。
pop(): スタックのトップから要素を削除し、返す。
Main.java
1234567891011121314package com.example; import java.util.Stack; public class Main { public static void main(String[] args) { Stack<String> stack = new Stack<>(); stack.push("One"); stack.push("Two"); System.out.println("Stack: " + stack); stack.pop(); System.out.println("Stack after the `pop()` method: " + stack); } }
このメソッドはスタックのトップから1つの要素を削除します。pop() メソッドはスタックから最後に追加された要素を削除することに注意してください。これがまさに LIFO 原則の動作です。
また、スタックのトップにある要素を確認することもできます。
peek(): スタックのトップにある要素を削除せずに返す。
Main.java
123456789101112131415package com.example; import java.util.Stack; public class Main { public static void main(String[] args) { Stack<String> stack = new Stack<>(); stack.push("One"); stack.push("Two"); System.out.println("Stack: " + stack); String top = stack.peek(); System.out.println("Top element of the stack: " + top); System.out.println("Stack after the `peek()` method: " + stack); } }
このメソッドでは、スタックの最上部の要素を確認します。
使用例
Stackデータ構造を使用して、ブラウザでページ間を移動する例を考えてみましょう(よく使う進むや戻るの矢印ボタン)。
ブラウザ履歴の実装を計画し、2つのボタン(goBack() と goForward())のメソッドを実装します。
どのボタンか分からない場合は、これらのナビゲーションボタンのことです。
これら2つのボタンを操作するメソッドを持つクラスを、Stackデータ構造を用いて実装します。
動作概要
2つのスタックと1つのString変数を使用します。1つ目のスタックは「戻る」矢印をクリックして移動したリンクを保存します。2つ目のスタックは「進む」矢印をクリックして移動したリンクを保存します。また、現在のページのリンクを保存するString変数も用意します。
このクラスには、visitPage()、goBack()、goForward()、getCurrentPage()の4つのメソッドがあります。それぞれの動作を順に説明します。
visitPage()メソッドは、パラメータで指定されたURLに遷移します。新しいページに移動する際、以前のリンクはbackStackに追加されます。新しいページに移動するとforwardStackはクリアされます。
コードでの実装を見てみましょう:
BrowserHistory.java
1234567891011121314151617181920212223242526import java.util.Stack; public class BrowserHistory { private Stack<String> backStack; private Stack<String> forwardStack; private String currentUrl; public BrowserHistory() { backStack = new Stack<>(); forwardStack = new Stack<>(); currentUrl = "https://codefinity.com/profile/my-home"; } public void visitPage(String url) { // When visiting a new page, add the current page to the "back" stack backStack.push(currentUrl); // Reset the "forward" stack as we moved to a new page forwardStack.clear(); // Set the current page to the new URL currentUrl = url; System.out.println("Visited page: " + url); } }
このようにして、新しいページに移動した際に前のページに戻ることができます。
次に、戻るメソッドを実装します。動作は次の通りです:現在のリンクをforwardStackに追加し、その後backStackからこのリンクを削除し、currentUrlに代入します。
コードでの実装を見てみましょう:
BrowserHistory.java
12345678910public void goBack() { if (!backStack.isEmpty()) { // Navigate to the previous page, move from the backStack to the forwardStack forwardStack.push(currentUrl); currentUrl = backStack.pop(); System.out.println("Went back to: " + currentUrl); } else { System.out.println("Cannot go back. Already at the beginning."); } }
pop() メソッドはスタックのトップから要素を削除し、その要素を返すことを思い出してください。このため、このメソッドを使用することで、URL の値を変数 currentUrl に即座に代入します。
また、backStack が空でないことも確認します。そうでなければ、前のリンクに戻ることができません(単純に存在しないためです)。スタックが空の場合は、対応するメッセージを出力します。
同様にして、進むページへのナビゲーション用メソッドも実装します。スタック内の要素を単純に入れ替えます。
BrowserHistory.java
12345678910public void goForward() { if (!forwardStack.isEmpty()) { // Navigate to the next page, move from the forwardStack to the backStack backStack.push(currentUrl); currentUrl = forwardStack.pop(); System.out.println("Went forward to: " + currentUrl); } else { System.out.println("Cannot go forward. Already at the latest page."); } }
残るは getCurrentPage() メソッドの実装のみであり、これは単純に currentUrl の値を返します。
テスト
次に、これらすべてを main メソッドでテストします。visitPage() メソッドを3回使用して、これらのリンクが履歴に保存されることを確認します。その後、goBack() メソッドを2回、goForward() メソッドを1回使用し、記述したメソッドの機能を検証します。
この過程で、getCurrentPage() メソッドを使って状態を追跡します。以下のコードを実行し、さらに多くのリンクを挿入したり、さまざまなメソッドを使ってこのクラスの機能をテストすることもできます。
Main.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778package com.example; import java.util.Stack; class Main { public static void main(String[] args) { BrowserHistory browser = new BrowserHistory(); System.out.println("Default page: " + browser.getCurrentPage()); browser.visitPage("https://codefinity.com/courses/tracks/7dfbcd35-5cde-49d3-80f1-bf1096487903"); browser.visitPage("https://codefinity.com/courses/v2/8204075c-f832-4cb9-88b1-4e24e74ebdcb/bb00e195-715e-477d-8927-964e6e27cf16/e66c57b4-5f36-43b2-bd3b-e1398044fcab"); browser.visitPage("https://codefinity.com/courses/v2/8204075c-f832-4cb9-88b1-4e24e74ebdcb/bb00e195-715e-477d-8927-964e6e27cf16/1585fb29-47cd-47a6-9fb3-5b391cad24e0"); System.out.println("Current Page after visiting 3 pages: " + browser.getCurrentPage()); browser.goBack(); browser.goBack(); System.out.println("Current Page after going back 2 times: " + browser.getCurrentPage()); browser.goForward(); System.out.println("Current Page after going forward: " + browser.getCurrentPage()); } } class BrowserHistory { private Stack<String> backStack; private Stack<String> forwardStack; private String currentUrl; public BrowserHistory() { backStack = new Stack<>(); forwardStack = new Stack<>(); currentUrl = "https://codefinity.com/profile/my-home"; } public void visitPage(String url) { // When visiting a new page, add the current page to the "back" stack backStack.push(currentUrl); // Reset the "forward" stack as we moved to a new page forwardStack.clear(); // Set the current page to the new URL currentUrl = url; System.out.println("Visited page: " + url); } public void goBack() { if (!backStack.isEmpty()) { // Navigate to the previous page, move from the backStack to the forwardStack forwardStack.push(currentUrl); currentUrl = backStack.pop(); System.out.println("Went back to: " + currentUrl); } else { System.out.println("Cannot go back. Already at the beginning."); } } public void goForward() { if (!forwardStack.isEmpty()) { // Navigate to the next page, move from the forwardStack to the backStack backStack.push(currentUrl); currentUrl = forwardStack.pop(); System.out.println("Went forward to: " + currentUrl); } else { System.out.println("Cannot go forward. Already at the latest page."); } } public String getCurrentPage() { return currentUrl; } }
Stack クラスは非推奨であり、現代のJava開発では推奨されていません。代わりに、より効率的な代替手段である Deque の使用が推奨されます。この例では、Stack はLIFO原則に基づいて実装されていますが、Deque も実装可能であり、これは両端キューとしてFIFOおよびLIFOの両方の原則をサポートします。
1. Stackデータ構造の主な原則は何ですか?
2. Javaでスタックの一番上に要素を追加するために使用されるメソッドはどれですか?
3. 次のうち、Stackのより現代的な代替と考えられているJavaコレクションはどれですか?
4. Javaにおいて、pop()のStackメソッドは何を返しますか?
フィードバックありがとうございます!
AIに質問する
AIに質問する
何でも質問するか、提案された質問の1つを試してチャットを始めてください