アプリケーション:LRUキャッシュ除去アルゴリズム
リンクされたリストも線形リストです。
リンクリストのメモリ構造は不連続なメモリ空間であり、不連続なメモリ空間のグループが直列に接続されて、データを格納するためのデータ構造を形成します。
リンクリストの各メモリブロックはノードと呼ばれ、データを格納するだけでなく、リンクリストの次のノードのアドレス、つまり次のポインタを次に記録する必要もあります。
リンクリストの機能
1.データ効率O(1)レベルを挿入、削除します(ポインターを変更するだけです)。
ランダムアクセス効率O(n)レベル。(リストの先頭からチェーンの最後までトラバースする必要があります)
2.配列と比較して、データを格納する各ノードは後続のポインタを格納するために追加の領域を必要とするため、メモリ領域の消費量は大きくなります。
一般的に使用されるリンクリスト:シングルリンクリスト、循環リンクリスト、ダブルリンクリスト
1.単一のリンクリスト:
(1)各ノードには、1つのポインター(後続ポインター)のみが含まれています。
(2)最初のノードと最後のノードの2つの特別なノードがあります。リンクリストのアドレスは最初のノードのアドレスで表され、テールノードの後続ポインタはNULLです。
(3)パフォーマンス特性:挿入と削除の時間の複雑度O(1)、検索時間の複雑度O(n)。
2.循環リンクリスト
(1)末尾ノードの後続ポインタが最初のノードを指すことを除いて、単一リンクリストと一致します。
(2)ジョセフ問題などの周期的特性を持つデータの保存に適しています。
3.二重リンクリスト
(1)データの格納に加えて、前のノードアドレスと次のノードアドレスへの2つのポインタがあります。
(2)最初のノードのプリカーサーポインターとテールノードのサクセサーポインターの両方がNULLを指している。
(3)単一リンクリストと比較して、同じデータを保存するにはより多くのストレージスペースが必要です。挿入および削除操作は、単一リンクリストよりも効率的です。
配列とリンクリストの比較
1.アレイの欠点
(1)100Mなどの大きなメモリスペースを申請したが、メモリスペースに100Mの連続スペースがない場合、メモリの使用可能スペースが100Mを超えていても、アプリケーションは失敗します。
(2)サイズが固定されているため、空き容量が足りない場合は容量を拡張する必要があり、容量を拡張するとデータの複製が必要となり、非常に時間がかかります。
2.リンクリストの欠点
(1)ポインタ情報を格納するために追加のスペースが必要になるため、メモリスペースの消費量が多くなります。
(2)リンクリストで頻繁に挿入および削除操作を行うと、メモリの適用と解放が頻繁に行われ、メモリの断片化が発生しやすくなります。
CPUキャッシュメカニズム
配列はシンプルで使いやすいです。実装は連続メモリ空間を使用します。CPUのキャッシュメカニズムを使用してグループ内のデータを事前に読み取ることができるため、アクセス効率が高くなります。リンクされたリストはメモリに継続的に保存されないため、CPUキャッシュに適しておらず、効果的に先読みする方法がありません。
CPUがメモリからデータを読み取るとき、最初に読み取ったデータをCPUのキャッシュにロードします。CPUがメモリからデータを読み取るたびに、アクセスする特定のアドレスを読み取るだけでなく、データブロックを読み取り(このサイズは不明です...)、CPUキャッシュに保存して、次にメモリにアクセスしますデータが見つかった場合は、CPUキャッシュから開始されますが、見つかった場合は、メモリからフェッチする必要はありません。このようにして、CPUキャッシュの存在の意味である、メモリアクセス速度よりも速いメカニズムが実現されます。メモリアクセス速度の違いを埋め合わせるために導入されたものは、遅すぎ、CPU実行速度が速いです。
以下のためのアレイ、ストレージ・スペースが連続している添字をロードするための時間はので、将来的にいくつかのインデックス要素を置くことができ、また、CPUのキャッシュにロードされ、実行速度となるように高速ストレージスペース不連続なチェーン店より。
リンクリスト作成スキル
1.ポインターまたは参照の意味を理解する
ポインタに変数を割り当てると、実際には変数のアドレスがポインタに割り当てられます。または、逆に、ポインタは変数のメモリアドレスを格納し、変数をポイントします。変数はポインタを通じて見つけることができます。
p->次= q。このコード行は、ノードpの次のポインタがノードqのメモリアドレスを格納することを示しています。
p->次= p->次->次。このコード行は、pノードの次のポインタがpノードの次のノードのメモリアドレスを格納することを示しています。
変数は値を格納し、各変数にはアドレスがあります。
ポインタの値は変数のアドレスです。
ポインタを使用すると、変数名を知らなくても、変数の値を間接的に読み取ったり更新したりできます。
言語の行き方:
変数var x int式&x(xのアドレス)を宣言して、型が整数ポインター(* int)である整数変数へのポインターを取得します。
ポインターの値がpと呼ばれる場合、pがxを指すか、pがxのアドレスを含むと言います。
pが指す変数は* pと記述され、式* pは変数の値が整数として取得されることを示します。
* pは変数を表します。これは、代入演算子の左側に表示され、変数の値を更新するために使用されます。
x:= 1
p:=&x // pは変数xのアドレスへのポインター
fmt.Println(* p)// * p、ポインタpが指す変数の値、つまりxの値を取得する
* p = 2 //つまり、x = 2、ポインタpを通じて変数xの値を変更する
fmt.Println(x)//出力2
構造体のメンバーまたは配列の要素は変数です。
ポインタ型のゼロ値はnil、test p!= Nilであり、結果は真であり、pが変数を指していることを示します。
現在、2つのポインターが等しいのは、それらが同じ変数を指している場合、または両方がnilの場合のみです。
2.ポインタの損失とメモリリークに注意する
たとえば、リンクされたリストに新しいノードを挿入する操作シーケンス
x-> next = p-> next
p-> next = x
3. Sentinelを使用して実現の難しさを簡素化する
4.境界条件の処理に焦点を合わせる
リンクされたリストが空の場合、コードは正しく機能しますか?
リンクされたリストに含まれるノードが1つだけの場合、コードは正しく機能しますか?
リンクされたリストに含まれるノードが2つだけの場合、コードは正しく機能しますか?
ヘッドノードとテールノードを処理するときに、コードロジックは正しく機能しますか?
5.描くことを学ぶ
フローチャートを描き、図にロジックを描きます
6.もっと書いて練習しよう
単一リンクリストの反転
リンクリスト内のリングの検出
2つの順序付けられたリンクリストがマージされます
リンクリストのn番目の最後のノードを削除します
リンクされたリストの中間ノードを見つける