小さな電気ロバに乗っていても、一生懸命働かなければなりません
目次
2.3.8 リンクされたリストに指定されたデータがあるかどうかを調べる
1.連結リスト
1.1 リンクリストの概念
リンクリストは、物理ストレージ構造内の不連続なストレージ構造であり、データ要素の論理順序は、リンクリスト内の参照リンク順序によって実現されます。
連結リストの特徴: ①空間的には、空間はオンデマンドで与えられる ②物理的な空間は連続している必要がない、先頭と途中の挿入と削除はデータを移動する必要がない
1.2 リンクリストの論理構造図と物理構造図
1.2.1 リンクリストの論理構造図
上記の論理構造図を通して、連結リストはノードで構成され、各ノードにはデータ フィールドとポインタ フィールドの2 つの部分が含まれていることがわかります. ポインタ フィールドは次のノードを指し、ノード間の接続を完了します. 接続済み
- データフィールド: データの保存に使用
- ポインタ フィールド: 次のノードを指すために使用されます
1.2.2 リンクリストの物理構造図
上記の物理構造図から、最後のノードのポインタがnullを指していることを除いて、残りのポインタフィールドは次のノードのアドレスを格納していることがわかります。したがって、ポインタフィールドは次のノードのアドレスを格納するために使用されますのリンクを 完成させる
1.3 リンクリスト構造の分類
1.3.1 リンクリストの構造は?
リンク リストは、次の表の 6 つの状況を組み合わせて構造を分類します。
一方向 | 双方向 |
誘導して | 主導権を握らない |
サイクル | 非環状 |
次の 8 つの構造に分けることができます。
頭のない一方向循環連結リスト |
一方向非先行非循環連結リスト |
一方向循環連結リスト |
頭のない一方向循環連結リスト |
双方向無頭循環連結リスト |
双方向非リーディング非循環リンクリスト |
双方向の頭付き循環連結リスト |
双方向の非循環連結リスト |
1.3.2 異なる連結リスト構造の論理図
①片道
一方向: 1 つのポインター フィールドのみが次のノードのアドレスを格納します。
②双方向
双方向: 2 つのポインター フィールドがあり、フロント ポインター フィールドは前のノードのアドレスを格納するために使用され、バック ポインター フィールドは次のノードのアドレスを格納するために使用されます。
③主導権を握る
主導権を握る: センチネル ノード (ヘッド) があり、データ フィールドは通常、ヘッド ノードとして無効な値を与えます。
④主導権を握らない
リーダーなし: センチネル ノードなし
⑤ループ
ループ: 最後のノードは最初のノードだけを指している
⑥非環状
非循環: 最後のノードは空を直接指します
2.一方向リンクリストの実装をシミュレートする
連結リストとは何か、連結リストの分類がわかったので、整数データを格納する一方向非先行非循環連結リストをシミュレートして実装します。
まず、このようなリンク リストを実装するクラスを作成する必要があります。
public class MyLinkedList {
}
次に、リンク リストを実装するすべてのプロセスをMyLinkedListクラスに配置する必要があります。
2.1 MyLinkedList クラスの内部クラス
リンクされたリストはノードを使用してデータを保存し、ノードを使用してノード間のリンクを実現することがわかっています
次に、 MyLinkedList クラス にノード クラスとして 内部クラスを作成する必要があります。
private class Node {
private int data;//数据域
private Node next;//链接域
private Node(int data) {
this.data = data;
}
}
- data: データの保存に使用
- next: ノード間のリンクを実現するために、次のノードのアドレスを格納するために使用されます
- 構築メソッド: ノード クラスがインスタンス化されるたびに、構築メソッドを呼び出してデータをデータ フィールドに入れる必要があります。
2.2 MyLinkedList クラスのメンバー属性
最初のノードをヘッド ノードとして設定する必要があります。これにより、リンク リストの開始位置をユーザーが認識できるようになり、単一リンク リストが指定されていないために再利用されなくなります。
private Node head;//记录第一个结点
注: 最初のノードがリサイクルされない限り、他のノードはリサイクルされません。これは、前のノードの次のノードが次のノードのアドレスを格納し、前のノードのポインター フィールドが次のノード ノードを指すためです。
2.3 MyLinkedList クラスのメンバーメソッド
2.3.1 リンクリストの先頭に新しいノードを挿入する
リンク リストの先頭にノードを挿入するには、まず、データdata に基づいてノードをインスタンス化する必要があります。次に、この新しいノードの次のポインタ フィールドにheadのアドレスを格納して、新しいノードが次のノードにリンクされるようにし、最後にhead をこの新しいノードと等しくして、この新しいノードが最初のノードになるようにします。
//头插法
public void addFirst(int data) {
Node nodeTmp = new Node(data);
nodeTmp.next = this.head;
this.head = nodeTmp;
}
2.3.2 連結リストの最後のノードを取得する
まず、ヘッドを移動することはできません.最初のノードを移動すると、それは指されていないためリサイクルされ、後続のノードも指されていないためリサイクルされます.したがって、作成する必要がありますノード型の一時変数 src, これはheadが指しているノードがそれに割り当てられるため、 headとsrcは同時に最初のノードを指します. src が他のノードに移動しても、最初のノードはそのままになります.頭で指摘される。srcは常にループを介して次のノードと等しく、srcに格納されているノードの次がnullの場合、それは最後のノードです
//获取链表的最后一个结点
private Node lastNode() {
Node src = this.head;
while (src.next != null) {
src = src.next;
}
return src;
}
注: このメソッドはプライベートに変更されているため、 MyLinkedListクラスでのみ使用できます。
2.3.3 リンクリストの最後に新しいノードを挿入する
リンク リストの最後にノードを挿入するには、まずリンク リストが空であるかどうかが必要です. リンク リストがnullの場合 、最後にノードを挿入することは、リンク リストの最初にノードを挿入することと同じです. リンクされたリストがnullでない場合、最後にノードを挿入するには、データdata に従ってノードをインスタンス化し、 lastNodeメソッドを介して最後のノードを取得し、最後のノードの次のノードに新しいノードのアドレス。
//尾插法
public void addLast(int data) {
if (head == null) {
addFirst(data);
return;
}
Node nodeTmp = new Node(data);
Node last = lastNode();
last.next = nodeTmp;
}
2.3.4 指定された位置の前のノードを返す
最初に位置が正当かどうかを判断し、そうでない場合は直接nullを返し、そうでない場合はheadが指すノードに等しい一時ノード変数を使用し、 index - 1回ループして指定された位置にある前のノードを見つけます。
//返回指定位置的前一个结点
private Node prevNode(int index) {
if (index > size() || index < 0) {
return null;
}
Node src = this.head;
while(index != 1) {
src = src.next;
index--;
}
return src;
}
2.3.5 リンクリストの指定位置に新しいノードを挿入する
最初のステップは、指定された場所が合法かどうかを判断し、そうでない場合はfalse を直接返すことです。そうでない場合は、2 番目のステップに進み、挿入された位置が最初のノード位置であるかどうかを判断し、そうであれば、ヘッド挿入メソッドを使用して連結リストの先頭にノードを直接挿入します。そうでない場合は、3 番目のステップに進み、挿入された位置が最後のノードの次の位置であるかどうかを判断し、そうであれば、末尾挿入メソッドを使用して連結リストの最後にノードを直接挿入します。それ以外の場合は、データデータ ノードをインスタンス化し、 preNodeメソッドを呼び出して、指定された位置にある前のノードを取得し、一時変数を使用して前のノードの次のノードを格納し、前のノードの次のノードに新しいノードを格納させます。ノードのノードアドレス、そしてこの新しいノードの次のノードアドレスに次のノードアドレスを格納させます
//任意位置插入,第一个数据结点为0号下标
public boolean addIndex(int index,int data) {
if (index > size() || index < 0) {
return false;
} else if (index == 0) {
addFirst(data);
} else if (index == size()) {
addLast(data);
} else {
Node nodeTmp = new Node(data);
Node prev = prevNode(index);//指定位置前一个结点
Node tmp = prev.next;//指定位置的结点
prev.next = nodeTmp;
nodeTmp.next = tmp;
}
return true;
}
注: if...else if...else if...else... この種の複数判断は、そのうちの 1 つだけを実行します。
2.3.6 最初のノードを削除するかどうかの決定
データ キーが最初のノードのデータ フィールド内のデータと同じかどうかを判断し、同じ場合は、head が次のノードを指すように head.next と等しくし、最初のノードが削除されるようにします。
//判断第一个结点是否是指定的结点,如果是则删除第一个结点
private boolean judgeFistNode(int key) {
if (key == this.head.data) {
this.head = this.head.next;
return true;
}
return false;
}
2.3.6 初めて出現する指定データのノードを削除する
最初に連結リストがnull l であるかどうかを判断し、そうでない場合は、指定されたデータのノードが連結リストの最初のノードであるかどうかを判断し、そうでない場合は、2 つのノード変数を使用してデータ ノードとその前のノードを見つけ、最初に指定されたデータ出力を持つノードのみが削除されるため、前のノードの次は次のノードのアドレスを格納し、直接戻ります。走査後にデータノードが見つからない場合、そのようなデータノードはありません
//删除第一次出现关键字为key的节点
public void remove(int key) {
if (this.head == null) {
return;
}
boolean judge = judgeFistNode(key);
if (judge == true) {
return;
}
Node src = this.head;
Node slow = this.head;
while (src != null) {
if (src.data != key) {
slow = src;
src = src.next;
} else {
slow.next = src.next;
return;
}
}
}
2.3.7 指定されたデータを持つすべてのノードを削除する
最初に連結リストがnull lかどうかを判断し、そうでない場合は2つのノード変数を通じてデータノードとその前のノードを見つけ、見つけた後の次のノードのアドレスを前のノードの次のノードに格納させます。指定したデータのノードをすべて削除する必要があるためです。トラバース後、最初のノードが空かどうかを判断します。これは、最初のノードが削除するノードである場合と同等であり、最初に無視し、最初のノードを削除した後に最初のノードを削除します
//删除所有值为key的节点
public void removeAllKey(int key) {
if (this.head == null) {
return;
}
Node src = this.head;
Node slow = this.head;
while (src != null) {
if (src.data != key) {
slow = src;
src = src.next;
} else {
slow.next = src.next;
src = src.next;
}
}
judgeFistNode(key);
}
2.3.8 リンクされたリストに指定されたデータがあるかどうかを調べる
リンクされたリストを直接トラバースし、存在する場合は true を直接返し、そうでない場合は false を返します
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key) {
Node src = this.head;
while (src != null) {
if (src.data == key) {
return true;
}
src = src.next;
}
return false;
}
2.3.9 連結リストの長さを取得する
このリンクされたリストをトラバースし、整数変数を使用してカウントするだけです
//得到单链表的长度
public int size() {
Node src = this.head;
int count = 0;
while (src != null) {
count++;
src = src.next;
}
return count;
}
2.3.10 リンクリストの印刷
最初にリンクされたリストが null かどうかを判断し、空の場合は null を直接出力します。それ以外の場合は、リンクされたリストをトラバースし、各ノードのデータ フィールドにデータを出力します。
//打印链表
public void display() {
if (this.head == null) {
System.out.print("null");
}
Node src = head;
while (src != null) {
System.out.print(src.data + " ");
src = src.next;
}
System.out.println();
}
2.3.11 リンクされたリストをクリアする
head が直接nullを指すようにします。これにより、最初のノードが指されなくなり、コンパイラによって直接リサイクルされます。最初のノードはリサイクルされ、2 番目のノードは指定されていないため、リンクされたリスト全体がリサイクルされるまでリサイクルされます。
//清除链表
public void clear() {
this.head = null;
}