Java リンク リスト|ヘッド ポインタと仮想ヘッド ノードの違い

単方向リンク リストは、ノードで 1 つずつ接続されます. ノードには実際にデータが格納されます. ノードには、データの一部と次のノードへのポインターが含まれます.
Java 言語の一方向リンク リスト環境で、ヘッド ポインターと仮想ヘッド ノードの使用の違いは何ですか?
ここに画像の説明を挿入

ヘッド ポインタはNode head = null存在しないヌル (つまり ) ノードを指しており、
この時点ではリンク リストは空です。仮想ヘッド ノードは実際には存在しますが、それが格納する要素は空であり、それが指す次のノードもまた空です。空。

仮想ヘッド ノードが設定されると、リンクされたリスト全体のすべてのノードが先行ノードを持つようになるため、任意の位置での追加、削除、変更、およびクエリを簡単かつ均一に実行できます。仮想ヘッドノードを設定せずにヘッドポインタを使用する場合は、if-else 論理判定の演算が必要です。

たとえば、単純な Java ファイルを作成して実装し、文字列を追加 (順番に挿入) する要素操作のみを実装します。
この Java ファイルで、リンクされたリスト要素を挿入する 2 つの方法を記述して実装します。

  • リンク リストの要素挿入を実装するには、ヘッド ポインターを使用します。
  • 仮想ヘッド ノードを使用して、リンク リストの要素の挿入を実現します。
/**这里自定义一个链表,仅实现了添加(按照顺序插入)字符串的元素操作 */
public class LinekedList {
    
    

    private Node<String> head;/**头指针*/

    /** 按照顺序依次添加-使用头指针实现链表的元素插入*/
    public void addElement(String value) {
    
    
        Node<String> node = new Node<>(value);
        if (head == null) {
    
    
            node.next = head; // 将node插入到head的前面,完成插入。
            head = node; // 移动head指针到node上(将node作为新的非空head指针)为后续插入做准备。
        } else {
    
    
            node.next = head.next; // 将node指针指向head的后驱节点
            head.next = node; // 将head指针指向node节点,完成插入。

            head = node; // 移动head指针移动到新插入的node节点上,为后续插入做准备。
            // (即将原先指向非空head节点的指针改换指向到node节点上,将node节点作为新的非空头指针)
        }
    }


    /**虚拟头结点*/
    private Node<String> dummyHead = new Node<>(null,null);

    /** 按照顺序依次添加-使用虚拟头结点实现链表的元素插入 */
    public void fillElement(String value) {
    
    
        Node<String> node = new Node<>(value);
        node.next = dummyHead.next; // 将node指针指向dummyHead的后驱节点
        dummyHead.next = node; // 将dummyHead指针指向node节点,完成插入。

        dummyHead = node; // 移动dummyHead指针到新插入的node节点上,为后续插入做准备。
        // (即将原先指向dummyHead的指针改换指向到node节点上,将node节点作为新的虚拟头结点)
    }
	/**虚拟头结点*/
    private Node<String> dummyHeader = new Node<>(null,null);

    /**按照下标插入*/
    public void fillElement(int index, String value) {
    
    
        Node<String> dummyHeaderTemp = dummyHeader;
        while(index-- > 0) {
    
    
            dummyHeader = dummyHeader.next; // 获取到所要添加节点位置的前驱节点
            // (其实就是移动指向虚拟头结点的指针到所要添加节点位置的前驱节点,
            // 然后将该前驱节点作为新的虚拟头结点,此时新的虚拟头结点data和next都非空)
        }

        Node<String> node = new Node<>(value);
        node.next = dummyHeader.next; // 将node指针指向dummyHeader的后驱节点
        dummyHeader.next = node; // 将dummyHeader指针指向node节点,从而完成插入。

        dummyHeader = dummyHeaderTemp; // 将dummyHeader指针指向原虚拟头结点dummyHeader
        // 目的是,再次以下标插入时仍然以虚拟头结点作为开始。
    }
    
    class Node<E> {
    
    
        private E data;
        public Node next;
        public Node(E data){
    
    
            this.data = data;
        }
        public Node(E data, Node<E> next) {
    
    
            this.data = data;
            this.next = next;
        }
    }
}

連結リストのメリット〜

  • リンクされたリストは、メモリ空間を柔軟に割り当てることができます。
  • 要素の前の要素がわかっている場合、要素は O(1) 時間で削除または追加できますが、もちろん、それが単一のリンクされたリストであるか、二重のリンクされたリストであるかにも依存します。要素の次の要素が既知であり、同じ要素は O(1) 時間で削除または追加できます。

リンクリストのデメリット〜

  • 添字によって要素をすばやく読み取ることができる配列とは異なり、配列は毎回リンク リストの先頭から 1 つずつ読み取る必要があります。
  • k 番目の要素のクエリには O(k) 時間がかかります。

適用シナリオ: 発生した問題の多くが迅速なクエリを必要とする場合、連結リストは適切ではない可能性があります; 発生した問題でデータ要素の数が不明であり、データを頻繁に追加および削除する必要がある場合、連結リストは適切ではありません。より適切。ただし、データ要素のサイズが決まっていて、削除操作と挿入操作があまりない場合は、配列の方が適している可能性があります。

(仮想ヘッド ノードを使用して) 問題を解決するアイデアを読み、k 個の反転したリンク リストのセットを再帰的に実装します。

おすすめ

転載: blog.csdn.net/u012827205/article/details/125664934