【データ構造】LinkedListとLinkedList

著者ホームページ:ペーパージーのブログ

この記事の著者: 皆さんこんにちは、paper jie です。この記事を読んでいただきありがとうございます。Yijiansanlian へようこそ。

この記事は「JAVA データ構造」コラムに収録されており、大学生やプログラミング初心者向けに丁寧に作成されています。著者は、JavaSE の基本的な知識をすべて網羅するために、多大な費用 (時間とエネルギー) を費やして構築しました。

その他コラム:「アルゴリズムの詳細解説」「C言語」「javaSE」など

コンテンツ共有: この号では、データ構造におけるリンク リストの知識を共有します。

目次

リンクされたリスト

リンクリストの概念と構造

一方向リンクリストのシミュレーション実装

特定の実装コード

私のリンクリスト

 インデックス性

リンクリスト

LinkedListのシミュレーション実装

私のリンクリスト

インデックス例外

JavaのLinkedList

LinkedListの使用

LinkedList のさまざまな走査

ArrayList と LinkedList の違い


リンクされたリスト

リンクリストの概念と構造

リンク リストは物理的に不連続なストレージ構造であり、データ要素の論理的順序はリンク リスト内の参照リンク順序によって実現されます。本物の緑色の電車と考えることができます

ここで注意してください:

チェーンは論理的には連続していますが、必ずしも物理的に連続しているとは限りません。

実際には、ノードは通常、ヒープから適用されます。

ヒープから要求された領域は特定の戦略に従って割り当てられるため、2 回適用される領域は連続的である場合もあれば、不連続である場合もあります。

連結リストの構造は多様であり、状況に応じて使い分けることができますが、一般的には次のような構造が使用されます。

一方向または双方向

主導権を握ることと主導権を奪わないこと

周期的と非周期的

これらの構造のうち、次の 2 つのタイプに注目する必要があります。

ヘッドレス一方向非巡回リンク リスト:構造は単純で、一般にデータを単独で保存することはありません。実際、ハッシュ バケットやグラフの隣接リストなど、他のデータ構造の下部構造として使用されることが多くなります。

ヘッドレス双方向リンク リスト: Java コレクション フレームワークでは、LinkedList の下位実装はヘッドレス双方向循環リンク リストです。

一方向リンクリストのシミュレーション実装

以下は、一方向リンク リストで実装する必要があるいくつかの基本関数です。

// 1、无头单向非循环链表实现
public class SingleLinkedList {
//头插法
public void addFirst(int data){
} 
//尾插法
public void addLast(int data){
} 
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
} 
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
return false;
} 
//删除第一次出现关键字为key的节点
public void remove(int key){
}
//删除所有值为key的节点
public void removeAllKey(int key){
} 
//得到单链表的长度
public int size(){
return -1;
}
public void clear() {
}
public void display() {}
}

特定の実装コード

私のリンクリスト
package myLinkedList;

import sun.awt.image.ImageWatched;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sun杰
 * Date: 2023-09-14
 * Time: 10:38
 */
public class MyLinkedList implements IList{

    static class LinkNode {
        public int value;
        public LinkNode next;
        public LinkNode(int data) {
            this.value = data;
        }
    }
    LinkNode head;
    public void createNode() {
        LinkNode linkNode1 = new LinkNode(12);
        LinkNode linkNode2 = new LinkNode(23);
        LinkNode linkNode3 = new LinkNode(34);
        LinkNode linkNode4 = new LinkNode(56);
        LinkNode linkNode5 = new LinkNode(78);
        linkNode1.next = linkNode2;
        linkNode2.next = linkNode3;
        linkNode3.next = linkNode4;
        linkNode4.next = linkNode5;
        this.head = linkNode1;
    }


    @Override
    public void addFirst(int data) {
        //实例化一个节点
        LinkNode firstNode = new LinkNode(data);
        if(this.head == null) {
            this.head = firstNode;
            return;
        }
        //将原第一个对象的地址给新节点的next,也就是将head给新next
        firstNode.next = this.head;
        //将新的对象的地址给head头
        this.head = firstNode;

    }

    @Override
    public void addLast(int data) {
        //实例化一个节点
        LinkNode lastNode = new LinkNode(data);
        //找到最后一个节点
        LinkNode cur = this.head;
        while(cur.next!= null) {
            cur = cur.next;
        }
        cur.next = lastNode;
        //将最后一个节点的next记录插入节点的地址
    }

    @Override
    public void addIndex(int index, int data) throws indexillgality {
        if(index < 0 || index > size()) {
            throw new indexillgality("index不合法");
        }
        LinkNode linkNode = new LinkNode(data);
        if(this.head == null) {
            addFirst(data);
            return;
        }
        if(size() == index ) {
            addLast(data);
            return;
        }
        LinkNode cur = this.head;
        int count = 0;
        while(count != index - 1) {
            cur = cur.next;
            count++;
        }
        linkNode.next = cur.next;
        cur.next = linkNode;
    }

    @Override
    public boolean contains(int key) {
        LinkNode cur = this.head;
        while(cur != null) {
            if(cur.value == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;

    }

    @Override
    public void remove(int key) {
        if(this.head.value == key) {
            this.head = this.head.next;
            return ;
        }
        //找前驱
        LinkNode cur = findprev(key);
        //判断返回值
        if(cur != null) {
            //删除
            LinkNode del = cur.next;
            cur.next = del.next;
            //cur.next = cur.next.next;
        }
    }
    //找删除的前驱
    private LinkNode findprev(int key) {
        LinkNode cur = head;
            while(cur.next != null) {
                if(cur.next.value == key) {
                    return cur;
                }
                cur = cur.next;
            }
        return null;
    }

    @Override
    public void removeAllKey(int key) {
        if(size() == 0) {
            return ;
        }
        if(head.value == key) {
            head = head.next;
        }
        LinkNode cur = head.next;
        LinkNode prev = head;
        while(cur != null) {
            if(cur.value == key) {
                prev.next = cur.next;
            }
            prev = cur;
            cur = cur.next;
        }

    }

    @Override
    public int size() {
        LinkNode cur = head;
        int count = 0;
        while(cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

    @Override
    public void display() {
        LinkNode x = head;
        while(x != null) {
            System.out.print(x.value + " ");
            x = x.next;
        }
        System.out.println();
    }

    @Override
    public void clear() {
        LinkNode cur = head;
        while(cur != null) {
            LinkNode curNext = cur.next;
            cur.next = null;
            cur = curNext;
        }
        head = null;
    }
}
 インデックス性

現時点ではカスタム例外

package myLinkedList;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sun杰
 * Date: 2023-09-14
 * Time: 12:55
 */
public class indexillgality extends RuntimeException {
    public indexillgality(String message) {
        super(message);
    }
}

リンクリスト

LinkedListのシミュレーション実装

これは、ヘッドレス二重リンク リストの実装と同等であり、必要な基本機能は次のとおりです。

// 2、无头双向链表实现
public class MyLinkedList {
//头插法
public void addFirst(int data){ }
//尾插法
public void addLast(int data){}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){}
//删除第一次出现关键字为key的节点
public void remove(int key){}
//删除所有值为key的节点
public void removeAllKey(int key){}
//得到单链表的长度
public int size(){}
public void display(){}
public void clear(){}
}

私のリンクリスト

package myLinkedList;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sun杰
 * Date: 2023-09-20
 * Time: 18:49
 */
public class MyLinkedList implements IList {

    //单个节点
    public static class ListNode {
        private int val;
        private ListNode prev;
        private ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }

    ListNode head;
    ListNode last;
    @Override
    public void addFirst(int data) {
        ListNode cur = new ListNode(data);
        if(head == null) {
            cur.next = head;
            head = cur;
            last = cur;
        }else {
            cur.next = head;
            head.prev = cur;
            head = cur;
        }

    }

    @Override
    public void addLast(int data) {
        ListNode cur = new ListNode(data);
        if(head == null) {
            head = cur;
            last = cur;
        } else {
            last.next = cur;
            cur.prev = last;
            last = cur;
        }
    }

    @Override
    public void addIndex(int index, int data) throws Indexexception {
        ListNode cur = new ListNode(data);
        if(index < 0 || index > size()) {
            throw new Indexexception("下标越界");
        }

        //数组为空时
        if(head == null) {
            head = cur;
            last = cur;
            return ;
        }

        //数组只有一个节点的时候
        if(head.next == null || index == 0) {
            head.prev = cur;
            cur.next = head;
            head = cur;
            return;
        }

        if(index == size()) {
            last.next = cur;
            cur.prev = last;
            return ;
        }

        //找到对应下标的节点
        ListNode x = head;
        while(index != 0) {
            x = x.next;
            index--;
        }

        //头插法
        cur.next = x;
        cur.prev = x.prev;
        x.prev.next = cur;
        x.prev = cur;

    }

    @Override
    public boolean contains(int key) {
        ListNode cur = head;
        while(cur != null) {
            if(cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    @Override
    public void remove(int key) {
        if(head == null) {
            return;
        }
        ListNode cur = head;
        while(cur != null) {
            if(cur.val == key) {
                if(cur.next == null && cur.prev == null) {
                    head = null;
                    last = null;
                    return;
                }else if(cur.next == null){
                    cur.prev.next = null;
                    last = cur.prev;
                    return;
                }else if(cur.prev == null) {
                    head = cur.next;
                    cur.next.prev = null;
                    return ;
                }else {
                    ListNode frone = cur.prev;
                    ListNode curnext = cur.next;
                    frone.next = curnext;
                    curnext.prev = frone;
                    return ;
                }

            }
            cur = cur.next;
        }

    }

    @Override
    public void removeAllKey(int key) {
        if(head == null) {
            return;
        }
        ListNode cur = head;
        while(cur != null) {
            if(cur.val == key) {
                if(cur.next == null && cur.prev == null) {
                    head = null;
                    last = null;
                } else if(cur.next == null){
                    cur.prev.next = null;
                    last = cur.prev;
                }else if(cur.prev == null) {
                    head = cur.next;
                    cur.next.prev = null;

                }else {
                    ListNode frone = cur.prev;
                    ListNode curnext = cur.next;
                    frone.next = curnext;
                    curnext.prev = frone;
                }
            }
            cur = cur.next;
        }

    }

    @Override
    public int size() {
        int count = 0;
        ListNode cur = head;
        while(cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

    @Override
    public void display() {
        ListNode cur = head;
        while(cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    @Override
    public void clear() {
        if(head == null) {
            return;
        }
        ListNode cur = head.next;
        while(cur != null) {
            head = null;
            head = cur;
            cur = cur.next;
        }
        head = null;
    }
}

インデックス例外

これもカスタム例外です

package myLinkedList;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sun杰
 * Date: 2023-09-21
 * Time: 9:47
 */
public class Indexexception extends RuntimeException{
    public Indexexception(String message) {
        super(message);
    }
}

JavaのLinkedList

LinkedList の最下層は二重リンクリスト構造となっており、リンクリストは連続した空間に要素を格納しないため、要素は別々のノードに格納され、ノード間は参照によって接続されます。このため、任意の位置に要素を挿入したり削除したりする際に、要素を移動する必要がなくなり効率的になります。 

コレクション フレームワークでは、LinkedList は List インターフェイスも実装します。

知らせ:

LinkedList は List インターフェイスを実装します

LinkedList の基礎となる層は二重リンク リストを使用します

Linked は RandomAccess インターフェイスを実装していないため、LinkedList はランダム アクセスをサポートしません。

LinkedList は、ランダムな位置で要素を挿入および削除する場合に効率が高く、複雑さは O(1) です。

LinkedList は、任意の位置に挿入するのに適しています。

LinkedListの使用

LinkedList の構築:

一般的に、次の 2 つの方法があります。

引数のない構造:

List<Integer> list = new LinkedList<>();

他のコレクション コンテナーの要素を使用してリストを構築します。

public LinkedList(Collection<? extends E> c)

栗:

public static void main(String[] args) {
// 构造一个空的LinkedList
        List<Integer> list1 = new LinkedList<>();
        List<String> list2 = new java.util.ArrayList<>();
        list2.add("JavaSE");
        list2.add("JavaWeb");
        list2.add("JavaEE");
// 使用ArrayList构造LinkedList
        List<String> list3 = new LinkedList<>(list2);
    }

LinkedList の基本メソッド:

public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
list.add(1); // add(elem): 表示尾插
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
System.out.println(list.size());
System.out.println(list);
// 在起始位置插入0
list.add(0, 0); // add(index, elem): 在index位置插入元素elem
System.out.println(list);
list.remove(); // remove(): 删除第一个元素,内部调用的是removeFirst()
list.removeFirst(); // removeFirst(): 删除第一个元素
list.removeLast(); // removeLast(): 删除最后元素
list.remove(1); // remove(index): 删除index位置的元素
System.out.println(list);
// contains(elem): 检测elem元素是否存在,如果存在返回true,否则返回false
if(!list.contains(1)){
list.add(0, 1);
}
list.add(1);
System.out.println(list);
System.out.println(list.indexOf(1)); // indexOf(elem): 从前往后找到第一个elem的位置
System.out.println(list.lastIndexOf(1)); // lastIndexOf(elem): 从后往前找第一个1的位置
int elem = list.get(0); // get(index): 获取指定位置元素
list.set(0, 100); // set(index, elem): 将index位置的元素设置为elem
System.out.println(list);
// subList(from, to): 用list中[from, to)之间的元素构造一个新的LinkedList返回
List<Integer> copy = list.subList(0, 3);
System.out.println(list);
System.out.println(copy);
list.clear(); // 将list中元素清空
System.out.println(list.size());
}

LinkedList のさまざまな走査

対象:

public static void main(String[] args) {
        List<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(3);
        list.add(5);
        list.add(2);
        list.remove(1);
        for (int x:list) {
            System.out.print(x + " ");
        }
    }

イテレータを使用してトラバースします。

ListIterator<Integer> it = list.listIterator();
        while(it.hasNext()) {
            System.out.println(it.next() + " ");
        }
    }

ArrayList と LinkedList の違い


おすすめ

転載: blog.csdn.net/paperjie/article/details/133240159