まず、プライマー
ブラウザの前方と後方の機能は、私はあなたがそれに非常に精通している必要がありますと思いますか?
あなたはターン完成ABC内のページの束を訪問すると、ページがBの前に見ると、ブラウザの戻るボタンをクリックして、あなたが見ることができます。あなたが戻ってページAに、進むボタンをクリックすると、再度ページを表示bとcできます。あなたは、ページBにバックアップ場合は、
新しいページdにクリックし、それはもはや、ページCを表示するために、前方後方の機能を渡すことはできません。
あなたはこの機能を実現する方法を、あなたはエンジニアのChromeブラウザを開発していると仮定?
私たちの話のようなデータ構造今日の「スタック」にこの使用。この問題では、我々は今日の内容を学ぶ必要があります。
第二には、スタックをどのように理解します
図1に示すように、スタックの特性
1、アウト後に進んだ最後で、最初のうちは、これは典型的な「スタック」構造です。
図2に示すように、スタックは、一端のみに「制限動作」線状、挿入、削除されたデータです。
2を比較し、リンクリストの配列
1、相対的な配列やリンクリスト、私の唯一の制限をもたらすためにスタック、および利点はありません。
2、私は直接配列またはリストが好きではないでしょうか?なぜ平均この「限られた操作」と「スタック」を使用?
3.なぜスタックが必要なのか
実際には、配列やリンクリストの機能の点から、本当にスタックを置き換えることはできますが、特定のデータ構造は、特定のシーンの抽象化である、知っている、
そして配列またはリストは、柔軟な運用確かに自由あまりにも多くのユーザーインターフェースを公開しかし、エラーが発生しやすいもちろんの比較的制御不能の使用、。
だから、データセットの特性が一端のみでデータの挿入や削除を含み、そして最後のアウト、LIFOを満たすようにするとき、私たちは、このデータ構造の「スタック」を優先しなければなりません。
スタックを実装する方法第三に、
1、配列に基づいて達成します
アレイベースの実装の//スタック順序 パブリッククラスArrayStack { プライベート文字列[]アイテム; //配列 プライベートINTカウント; //スタック内の要素の数 プライベート整数N; //スタックサイズ //サイズを適用し、配列を初期化空間的な配列N 公共ArrayStack(int型N){ this.items =新しい新しいString [N]; this.n = N; this.count = 0; } //スタック操作 パブリックブールプッシュ(項目文字列){ //配列ない十分なスペース、直接返す偽、スタックは失敗します。 falseにIF(カウント== N-)のリターン; //は1つのでインデックス位置カウント、カウントでアイテムを置く 項目=項目[カウント]を; ++数える; trueに復帰; } //ポップ操作 パブリック文字列のポップ(){ //スタックが空である、プロセスは直接NULLを返します IF(COUNT == 0)リターンヌル。 //戻りカウント1標識された配列要素、およびスタック数の要素の数から1つのを引いた 文字列アイテムTMP = [COUNT-1]; --count; 戻りTMP; } }
2、複雑分析
ソリューションおよび基本操作の定義が、その時はその操作、スペースの複雑さはどのくらいですか?
スタックまたはチェーンスタックのためかどうか、我々は唯一のサイズnは十分のデータ配列を格納する必要があります。押すと、1つまたは2つの一時変数記憶ポッピングの過程において
、記憶空間を空間複雑にO(1)です。
この法律は、空間複雑さはO(N)であると言うことではない、サイズのデータ記憶アレイを必要とするn個あることに注意してください。n個のスペースが必要とされているので、これを省略することができません。だから
、データ・ストレージ・スペースの元の手段に加えて、アルゴリズムを実行すると、我々はそのスペースの複雑さを言っても、余分なストレージ容量を必要とします。
宇宙の複雑さの解析は非常に単純ではないのですか?時間の複雑さは、難しいことではありません。スタック又はチェーンスタック、スタック、スタックポップ操作の順序のみ個人データを含むかどうか、時間複雑度はO(1)です。
第四に、スタックのための動的な拡張をサポート
スタックの動的拡張の順序を実装する方法1、
動的配列のサポートにそれを動的に拡張を実装する方法?
配列のスペースが十分でない場合には、我々は、配列の過去に大きなメモリ、すべてのデータの元のコピーを再申請する必要があります。ダイナミックアレイ拡張のサポートのこの実現。
あなたは、スタックのダイナミックサポートダイナミックな展開を実現したいのであれば、我々はそれだけのサポートのダイナミックな展開の基礎となるの配列に依存する必要があります。
スタックがいっぱいになると、私たちはより大きな配列のために適用される、新しい配列に古いデータを移動します。私はあなたが輝くそれを理解することができ、図を描きます。
2、スタックの複雑さ分析のアウト
スタック時の複雑さがまだあるので、ポップ操作については、我々は、メモリとのデータのために再適用する移動伴わないであろうO(1)。
- しかし、着信動作のために、状況が異なっています。
- スタック内の空きスペースがある場合、スタック操作の時間計算量はO(1)です。
- スペースが十分でない場合でも、あなたはデータの移動やメモリを申請する必要があり、時間の複雑さはO(n)になります。
3、償却分析
ポップ操作のために、最良の場合の時間複雑度はO(1)であり、最悪の場合の時間複雑度はO(N)です。当時の複雑さは、平均的な場合どのくらいですか?
分析は、それを置くために、私たちは事前と定義でいくつかの仮定を行う必要があります。
- スタック領域が十分でない場合には、我々はオリジナルのもののために再適用する必要が配列の2倍のサイズです。
- 分析を単純化するために、我々は運転操作を押すとポップだけではないことを前提としています。
- 定義は、START、単純なプッシュ動作のためにメモリ・スタック・オペレーションを移動伴わない、時間複雑度は、O(1)です。
現在のスタックサイズは、K、およびフルの場合、とき新しいデータスタックにする場合:
図1は、それが再適用倍メモリの量、及びKデータ行う移動操作、及び、スタックする必要があります。
2は、しかし、次回はK-1のスタック操作は、我々は、スタック操作は単純なプッシュ操作を必要とし、このK-1回を完了することができますので、メモリおよび移動データのために、適用直す必要はありません。
3は、あなたにこのプロセスのより直感的な理解を作るために、私は絵を描きました。
あなたはそれを見ることができるはずです
K回スタック操作、データKを移動さの合計を含む、及びK回の単純なプッシュ操作である1。、均等スタック動作K倍を共有するK個のデータを移動し
、各プッシュ操作のみデータ移動と単純プッシュ操作することを必要とする、2。だから、スタッキング操作に時間の複雑さを償却O(1)です。
この例の実際の分析により、
1だけでなく、上述したフロント、償却時間複雑度が最良の時間複雑さにほぼ等しくされている確認します。
図2に示すように、ほとんどの場合、時間複雑度はO Oスタック操作であるので、(1)のみ特定の時間で、O(N)に還元される
。図3に示すように、複数の時間のスタック操作を消費するように他のスタックに等しく共有、時間のかかるO(1)の平均ケース近いです。
関数呼び出しスタック内のV.アプリケーション
私たちは、このメモリは、関数呼び出しの一時的な変数を格納するために使用されるこのような構造の「スタック」に編成され、各スレッドへのオペレーティングシステムは別のメモリ領域を割り当てられていることを知っています。
各機能に入る、それが呼び出された関数の戻り、スタックのスタックフレームに対応する機能の実行が完了した後、スタック上のスタックフレームとして一時変数であろう。
あなたのより良い理解を与えるために、我々は、このコードの実行を見て:
INTのmain(){ int型、A = 1。 int型RET = 0; int型のres = 0; RET =追加(3、5)。 RES = A + RET。 printf( "%dの"、RES)。 reuturn 0; } int型の追加(int型のx、int型Y){ int型の和= 0。 合計= X + Y。 合計を返します。 }
私たちは、コードから見ることができます:
1、main()関数は、add()関数を呼び出して、計算結果を取得し、一時変数で添加し、最後にRESの値を印刷します。
図2は、あなたが明確にスタック内の関数のスタック、スタック操作に対応するプロセスを見ることができるようにするために、私は絵を描きました。()関数、関数呼び出しスタックを追加するために実行され、図に示します。
第六に、アプリケーションの発現評価スタック
実際には、コンパイラは、2つのスタックを実現することです。前記スタックオペランド記憶装置、及び他の保持オペレータスタック。
;私達に直接オペランドスタックの上に、数に直面したとき私たちは、左から右に式を横断し、オペレータが遭遇したときに、より多くのそれは、スタック演算子の先頭の要素と比較されます。
図1に示すように、上部要素のオペレータよりも高い優先順位場合、スタック電流オペレータにプッシュされ、
図2に示すように、オペレータスタックのスタックオペレータの上部から採取した上部要素または同一のオペレータ、より低い優先度の場合、
3、オペランドスタック上に2つのオペランドをとり、次に計算するスタックからオペランドスタック、および、計算結果の端、比較が継続されます。
私は、あなたは私が言ったの図の計算と併せて理解することができ、3 + 5 * 8-6この計算式はマップに引き込まれるだろう。
七つのスタックブラケットマッチングアプリケーション
式の評価を達成するために、スタックを使用して加えて、我々はまた、括弧内の式が援助スタックと一致して確認することができます。
我々はまた、いくつかの背景を簡素化:
1、我々は、発現のわずか3種類のブラケット、括弧()、ブラケット[]やブレース{}を含み、それらは任意に入れ子にすることができると仮定する。
図2に示すように、例えば、{[{}]}または[{()}([])]これ正当フォーマットとして
3、{[}()]または[({)]は、法的形式ではありません。
私は今、それが合法であるかどうかを確認する方法を、文字列式には3角かっこが含まれている⼀あなたを与えますか?
ここでは、また解決するために、スタックを使用することができます。
1、我々は左から右に文字列をスキャンし、比類のない左括弧を保存するためにスタックを使用しています。左括弧をスキャンするとき、それはスタックにプッシュされ、
右のブラケット場合、スキャン、2、左括弧がスタックから除去されます。そのようなマッチ、「{」と「}」一致「[」と「]」マッチ「(」と「)」のようなパターンマッチは、走査ストリングの残りの部分を続行する場合。
図3は、スキャン処理、右括弧遭遇ペアリング、またはスタックがデータでない場合、フォーマットが不正です。
全てのブラケットがスキャンされるときに、スタックが空である場合、その文字列は、法的形式であり、そうでない場合、左括弧が一致しない示し、不正形式
八、答えが始まります
まあ、私はあなたが、スタックの概念を完全に理解している今だと思います。私たちは、前方のブラウザのバック機能を移動する方法、反射質問の開口部を見に戻ってきますか?
実際には、あなたがこの問題には2つの完璧なソリューションを使用してスタックすることができます。
1は、我々は2つのスタック、XとYを使用して、我々はあなたが最初のページがスタックX、にプッシュターン閲覧入れ
2、[戻る]ボタンをクリックすると、その後、スタックXからスタックをオンにし、データをスタックに順次ですスタックY.
3、我々は前進ボタンをクリックしたとき、我々はスタックからYデータを消し、スタックはXに配置され スタックXは、データが存在しない場合は、以下のページが戻って閲覧し続けることはできないことを示しています。
4、スタックYデータなしには、それは何の側が前方参照するには、ボタンをクリックすることはできません示していたとき。
たとえば、シーケンスA、Bを参照してください、3つのページC、我々は、この時、スタックにプッシュ、B、Cには、このようなデータの2つのスタックを回します
あなたは、ブラウザの戻るボタンからページcにページから撤退すると、我々はスタックXからCとBポップに向けると、スタックに変身Y. 今回、このようなデータの2つのスタック:
この彼らはページB君を見たい時、[前方]ボタンをクリックしますページBに戻り、Bとし、我々は、スタック上に置かれ、Y、Xにスタックからポップ置きます。このようなデータのこの時点で2つのスタック:
今回は、新しいページのD bにページを介してジャンプする必要があり、cは、前方と後方のボタンによるページには、スタックY.を空にする必要があるので、繰り返し参照することができません このようなデータのこの時点で、2つのスタック
九、コンテンツの概要
内容については、今日のレビューしてみましょう:
図1に示すように、操作は、プッシュとポップ操作をサポート制限されたスタックデータ構造です。LIFOは、その最大の特徴です。
図2に示すように、スタックはアレイによって達成することができる、それはまた、リンクされたリストによって達成することができます。
図3は、関係なく、アレイまたはリンクされたリストベース、スタックのスタックは、O(1)の時間計算量です。
4は、加えて、我々はまた、サポートスタックのシーケンシャルダイナミックな展開を話した、あなたはその償却時間複雑分析をマスタリングに焦点を当てる必要があります。
テン、放課後の思考
1.私たちは、関数呼び出しがなぜ一時変数を保存するために「スタック」を使用し、一時的な変数を格納するためのコールスタックについて話したアプリケーションスタック、について話していますか?他のデータ構造はIすることはできませんでは?
関数の実行順序は後発とライン、ファーストアウト、最後のアウトこれらの機能の中で呼び出すため。
たとえば、ローカル変数の関数のライフサイクルの長さが短いライフサイクルの定義の後、長いライフサイクルを定義することで、
関数は関数を呼び出すだけでなくて、あまりにも、機能し始めたように、他の機能の実行が終了した内部コールを実行するまでの間だけ、この機能は、エンドを実行することができます。
これは、データ構造によれば、これらの特徴の関数呼び出しであることは抽象的原則の具体的なアプリケーションのシナリオで、私たちの優先スタック構造。
2.私たちは、すべてのことを知っている、の「スタック」のコンセプトでJVMのメモリ管理。スタックメモリはローカル変数やメソッドの呼び出しを格納するために使用される、ヒープメモリは、Javaでのストアオブジェクトに使用されています。
それはすべてのJVMは、ここで私たちとの「スタック」内の「スタック」と言っていることではないですか?そうでない場合、それはそれの「スタック」と呼ばれる理由
スタック内のJVMと我々は一つのこと、方法はスタックと呼ばれていると言うためにここにいます。前回の関数呼び出しの影響は、ローカル変数の保存方法についても同様です。