Maison > Java > javaDidacticiel > le corps du texte

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

WBOY
Libérer: 2022-11-25 21:16:32
avant
1398 Les gens l'ont consulté

Cet article vous apporte des connaissances pertinentes sur java, qui présente principalement le contenu pertinent sur les tables de séquence et les listes chaînées. Une table de séquence est un tableau qui utilise une unité de stockage avec une adresse physique continue pour stocker des éléments de données en séquence. jetez un œil à la structure linéaire, j’espère que cela sera utile à tout le monde.

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

Apprentissage recommandé : "Tutoriel vidéo Java"

1. Liste linéaire

Une liste linéaire (liste linéaire) est une séquence finie de n éléments de données ayant les mêmes caractéristiques. Les tableaux linéaires sont une structure de données largement utilisée en pratique. Tableaux linéaires courants : listes séquentielles, listes chaînées, piles, files d'attente, chaînes...

Les tableaux linéaires sont des structures logiquement linéaires, c'est-à-dire une ligne droite continue. Cependant, la structure physique n'est pas nécessairement continue. Lorsque les tableaux linéaires sont physiquement stockés, ils le sont généralement sous forme de tableaux et de structures liées.

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

2. La liste de séquences

est en fait un tableau . [Ajouter, supprimer, vérifier et modifier] Alors pourquoi écrivez-vous toujours une table de séquence en utilisant simplement un tableau ? C'est différent. Si vous l'écrivez dans une classe, vous pourrez devenir orienté objet à l'avenir.

2.1 Concept et structure

Une table de séquence est une structure linéaire qui utilise une unité de stockage avec des adresses physiques continues pour stocker des éléments de données en séquence. Généralement, le stockage en tableau est utilisé. Terminez l'ajout, la suppression, la vérification et la modification des données sur la baie.

Les tables de séquence peuvent généralement être divisées en :

  • Tables de séquence statiques : utilisez un stockage en tableau de longueur fixe.
  • Table de séquence dynamique : utilisez le stockage de tableau ouvert dynamiquement.

La table de séquence statique convient aux scénarios dans lesquels vous savez combien de données doivent être stockées.

Le tableau de longueur fixe de la table de séquence statique entraîne la fixation de N à une taille trop grande et une perte d'espace excessive. trop peu d'espace n'est pas suffisant.

En revanche, les tables de séquence dynamiques sont plus flexibles et peuvent allouer dynamiquement de l'espace en fonction des besoins

2.2 Implémentation de l'interface

Implémentons une table de séquence dynamique. doivent être pris en charge.

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

Ici, nous les démontons un par un. Out :

public class MyArrayList {

    public int[] elem;
    public int usedSize;//有效的数据个数

    public MyArrayList() {
        this.elem = new int[10];
    }
    // 打印顺序表public void display() {
    
    }
    System.out.println();}// 获取顺序表长度public int size() {
    return 0;}// 在 pos 位置新增元素public void add(int pos, int data) {}// 判定是否包含某个元素public boolean contains(int toFind) {
    return true;}// 查找某个元素对应的位置public int search(int toFind) {
    return -1;}// 获取 pos 位置的元素public int getPos(int pos) {
    return -1;}// 给 pos 位置的元素设为 valuepublic void setPos(int pos, int value) {}//删除第一次出现的关键字keypublic void remove(int toRemove) {}// 清空顺序表public void clear() {}}
Copier après la connexion

C'est la structure de base de notre table de séquence. Décomposons les fonctions de la table de séquence une par une :

Imprimez la table de données :

public void display() {
    for (int i = 0; i < this.usedSize; i++) {
        System.out.print(this.elem[i] + " ");
    }
    System.out.println();}
Copier après la connexion

Obtenez la longueur de la table de séquence :

public int size() {
    return this.usedSize;}
Copier après la connexion

Ajoutez un élément à la position pos :

public void add(int pos, int data) {
    if(pos < 0 || pos > this.usedSize) {
        System.out.println("pos 位置不合法");
        return;
    }
    if(isFull()){
        this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
    }
    for (int i = this.usedSize-1; i >= pos; i--) {
        this.elem[i + 1] = this.elem[i];
    }
    this.elem[pos] = data;
    this.usedSize++;}//判断数组元素是否等于有效数据个数public boolean isFull() {
    return this.usedSize == this.elem.length;}
Copier après la connexion

Jugez si un certain élément est inclus :

public boolean contains(int toFind) {
    for (int i = 0; i < this.usedSize; i++) {
        if (this.elem[i] == toFind) {
            return true;
        }
    }
    return false;}
Copier après la connexion

Trouver la position correspondant à un élément :

public int search(int toFind) {
    for (int i = 0; i < this.usedSize; i++) {
        if (this.elem[i] == toFind) {
            return i;
        }
    }
    return -1;}
Copier après la connexion

Obtenir l'élément en position pos :

public int getPos(int pos) {
    if (pos < 0 || pos >= this.usedSize){
        System.out.println("pos 位置不合法");
        return -1;//所以 这里说明一下,业务上的处理,这里不考虑
    }
    if(isEmpty()) {
        System.out.println("顺序表为空!");
        return -1;
    }
    return this.elem[pos];}//判断数组链表是否为空public boolean isEmpty() {
    return this.usedSize == 0;}
Copier après la connexion

Définir l'élément en position pos comme valeur :

public void setPos(int pos, int value) {
    if(pos < 0 || pos >= this.usedSize) {
        System.out.println("pos 位置不合法");
        return;
    }
    if(isEmpty()) {
        System.out.println("顺序表为空!");
        return;
    }
    this.elem[pos] = value;}//判断数组链表是否为空public boolean isEmpty() {
    return this.usedSize == 0;}
Copier après la connexion

Supprimer la première occurrence du mot clé clé :

public void remove(int toRemove) {
    if(isEmpty()) {
        System.out.println("顺序表为空!");
        return;
    }
    int index = search(toRemove);//index记录删除元素的位置
    if(index == -1) {
        System.out.println("没有你要删除的数字!");
    }
    for (int i = index; i < this.usedSize - 1; i++) {
        this.elem[i] = this.elem[i + 1];
    }
    this.usedSize--;
    //this.elem[usedSize] = null;引用数组必须这样做才可以删除}
Copier après la connexion

Effacer la liste de séquences :

public void clear() {
    this.usedSize = 0;}
Copier après la connexion

2.3 Problèmes et réflexions sur les tables de séquence

  1. Insertion et suppression au milieu/en tête de la table de séquence, la complexité temporelle est O(N)

  2. Augmentation la capacité nécessite de demander un nouvel espace et de copier les données. Il y aura beaucoup de consommation.

  3. L'expansion de la capacité augmente généralement de 2 fois, et il y aura forcément une certaine quantité d'espace gaspillé. Par exemple, la capacité actuelle est de 100, et lorsqu'elle est pleine, la capacité passe à 200. Nous continuons à insérer 5 données, et aucune donnée ne sera insérée plus tard, donc 95 espaces de données sont gaspillés.

Réflexion : Comment résoudre les problèmes ci-dessus ? La structure de la liste chaînée est donnée ci-dessous pour y jeter un œil.

3. Liste chaînée

3.1 Le concept et la structure de la liste chaînée

Une liste chaînée est une structure de stockage physique non continue L'ordre logique des éléments de données passe par des références. dans la liste chaînée, les liens sont implémentés dans l'ordre.

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

En réalité, les structures des listes chaînées sont très diverses. Si elles sont généralement divisées, il existe quatre types :

  • Liste chaînée à sens unique

  • Liste chaînée double

  • Liste chaînée circulaire.

  • Liste chaînée circulaire bidirectionnelle

Si elle est subdivisée, il existe 8 types de structures de liste chaînée dans les situations suivantes :

    Unidirectionnel, bidirectionnel
  • leader, non leader
  • cyclique, non cycliques
Ces huit types sont :

  • Boucle menant à sens unique

  • Boucle menant à sens unique

  • Non-boucle menant à sens unique

  • Non-boucle menant à sens unique -loop

  • Boucle principale bidirectionnelle

  • Pas de direction dans les deux sens Boucle

  • Non-boucle bidirectionnelle

  • Non-boucle bidirectionnelle non principale

Remarque : les mots en gras ci-dessus sont ce que nous devons apprendre ! ! !

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

虽然有这么多的链表的结构,但是我们重点掌握两种:

  • 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

head:里面存储的就是第一个节点(头节点)的地址

head.next:存储的就是下一个节点的地址

尾结点:它的next域是一个null

  • 无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

最上面的数字是我们每一个数值自身的地址。

prev:指向前一个元素地址

next:下一个节点地址

data:数据

3.2 链表的实现

3.2.1无头单向非循环链表的实现

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

上面地址为改结点元素的地址

val:数据域

next:下一个结点的地址

head:里面存储的就是第一个结点(头结点)的地址

head.next:存储的就是下一个结点的地址

无头单向非循环链表实现:

class ListNode {
    public int val;
    public ListNode next;//ListNode储存的是结点类型

    public ListNode (int val) {
        this.val = val;
    }}public class MyLinkedList {
    public ListNode head;//链表的头引用

    public void creatList() {
        ListNode listNode1 = new ListNode(12);
        ListNode listNode2 = new ListNode(23);
        ListNode listNode3 = new ListNode(34);
        ListNode listNode4 = new ListNode(45);
        ListNode listNode5 = new ListNode(56);
        listNode1.next = listNode2;
        listNode2.next = listNode3;
        listNode3.next = listNode4;
        listNode4.next = listNode5;
        this.head = listNode1;
    }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key) {
        
        return true;
    }
    //得到单链表的长度
    public int size(){
        return -1;
    }
    //头插法
    public void addFirst(int data) {

    }
    //尾插法
    public void addLast(int data) {

    }
    //任意位置插入,第一个数据节点为0号下标
    public boolean addIndex(int index,int data) {
        return true;
    }
    //删除第一次出现关键字为key的节点
    public void remove(int key) {

    }
    //删除所有值为key的节点
    public ListNode removeAllKey(int key) {

    }
    //打印链表中的所有元素
    public void display() {

    }
    //清除链表中所有元素
    public void clear() {
        
    }}
Copier après la connexion

上面是我们链表的初步结构(未给功能赋相关代码,大家可以复制他们到自己的idea中进行练习,答案在下文中) 这里我们将他们一个一个拿出来实现 并实现!

打印链表中所有元素:

public void display() {
    ListNode cur = this.head;
    while(cur != null) {
        System.out.print(cur.val + " ");
        cur = cur.next;
    }
    System.out.println();}
Copier après la connexion

查找是否包含关键字key是否在单链表当中:

public boolean contains(int key) {
    ListNode cur = this.head;
    while (cur != null) {
        if (cur.val == key) {
            return true;
        }
        cur = cur.next;
    }
    return false;}
Copier après la connexion

得到单链表的长度:

public int size(){
    int count = 0;
    ListNode cur = this.head;
    while (cur != null) {
        count++;
        cur = cur.next;
    }
    return count;}
Copier après la connexion

头插法(一定要记住 绑定位置时一定要先绑定后面的数据 避免后面数据丢失):

public void addFirst(int data) {
    ListNode node = new ListNode(data);
    node.next = this.head;
    this.head = node;
    /*if (this.head == null) {
        this.head = node;
    } else {
        node.next = this.head;
        this.head = node;
    }*/}
Copier après la connexion

尾插法:

public void addLast(int data) {
    ListNode node = new ListNode(data);
    if (this.head == null) {
        this.head = node;
    } else {
        ListNode cur = this.head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = node;
    }}
Copier après la connexion

任意位置插入,第一个数据结点为0号下标(插入到index后面一个位置):

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

/**
 * 找到index - 1位置的节点的地址
 * @param index
 * @return
 */public ListNode findIndex(int index) {
    ListNode cur = this.head;
    while (index - 1 != 0) {
        cur = cur.next;
        index--;
    }
    return cur;}//任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data) {
    if(index < 0 || index > size()) {
        System.out.println("index 位置不合法!");
        return;
    }
    if(index == 0) {
        addFirst(data);
        return;
    }
    if(index == size()) {
        addLast(data);
        return;
    }
    ListNode cur = findIndex(index);
    ListNode node = new ListNode(data);
    node.next = cur.next;
    cur.next = node;}
Copier après la connexion

注意:单向链表找cur时要-1,但双向链表不用 直接返回cur就好

删除第一次出现关键字为key的结点:

/**
 * 找到 要删除的关键字key的节点
 * @param key
 * @return
 */public ListNode searchPerv(int key) {
    ListNode cur = this.head;
    while(cur.next != null) {
        if(cur.next.val == key) {
            return cur;
        }
        cur = cur.next;
    }
    return null;}//删除第一次出现关键字为key的节点public void remove(int key) {
    if(this.head == null) {
        System.out.println("单链表为空");
        return;
    }
    if(this.head.val == key) {
        this.head = this.head.next;
        return;
    }
    ListNode cur = searchPerv(key);
    if(cur == null) {
        System.out.println("没有你要删除的节点");
        return;
    }
    ListNode del = cur.next;
    cur.next = del.next;}
Copier après la connexion

删除所有值为key的结点:

public ListNode removeAllKey(int key) {
    if(this.head == null) {
        return null;
    }
    ListNode prev = this.head;
    ListNode cur = this.head.next;
    
    while(cur != null) {
        if(cur.val == key) {
            prev.next = cur.next;
            cur = cur.next;
        } else {
            prev = cur;
            cur = cur.next;
        }
    }
        //最后处理头
    if(this.head.val == key) {
        this.head = this.head.next;
    }
    return this.head;}
Copier après la connexion

清空链表中所有元素:

public void clear() {
    while (this.head != null) {
        ListNode curNext = head.next;
        head.next = null;
        head.prev = null;
        head = curNext;
    }
    last = null;}
Copier après la connexion
Copier après la connexion

3.2.2无头双向非循环链表实现:

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

上面的地址0x888为该结点的地址

val:数据域

prev:上一个结点地址

next:下一个结点地址

head:头结点 一般指向链表的第一个结点

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

class ListNode {
    public int val;
    public ListNode prev;
    public ListNode next;

    public ListNode (int val) {
        this.val = val;
    }}public class MyLinkedList {
    public ListNode head;//指向双向链表的头结点
    public ListNode last;//只想双向链表的尾结点
    //打印链表
    public void display() {

    }
    //得到单链表的长度
    public int size() {
        return -1;
    }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key) {
        return true;
    }
    //头插法
    public void addFirst(int data) {

    }
    //尾插法
    public void addLast(int data) {

    }
    //删除第一次出现关键字为key的节点
    public void remove(int key) {

    }
    //删除所有值为key的节点
    public void removeAllKey(int key) {

    }
    //任意位置插入,第一个数据节点为0号下标
    public boolean addIndex(int index,int data) {
        return true;
    }
    //清空链表
    public void clear() {

    }}
Copier après la connexion

上面是我们链表的初步结构(未给功能赋相关代码,大家可以复制他们到自己的idea中进行练习,答案在下文中) 这里我们将他们一个一个拿出来实现 并实现!

打印链表:

public void display() {
    ListNode cur = this.head;
    while (cur != null) {
        System.out.print(cur.val + " ");
        cur = cur.next;
    }
    System.out.println();}
Copier après la connexion

得到单链表的长度:

public int size() {
    ListNode cur = this.head;
    int count = 0;
    while (cur != null) {
        count++;
        cur = cur.next;
    }
    return count;}
Copier après la connexion

查找是否包含关键字key是否在单链表当中:

public boolean contains(int key) {
    ListNode cur = this.head;
    while (cur != null) {
        if (cur.val == key) {
            return true;
        }
        cur = cur.next;
    }
    return false;}
Copier après la connexion

头插法:

public void addFirst(int data) {
    ListNode node = new ListNode(data);
    if (this.head == null) {
        this.head = node;
        this.last = node;
    } else {
        node.next = this.head;
        this.head.prev = node;
        this.head = node;
    }}
Copier après la connexion

尾插法:

public void addLast(int data) {
    ListNode node = new ListNode(data);
    if (this.head == null) {
        this.head = node;
        this.last = node;
    } else {
        ListNode lastPrev = this.last;
        this.last.next = node;
        this.last = this.last.next;
        this.last.prev = lastPrev;
        /**
         * 两种方法均可
         * this.last.next = node;
         * node.prev = this.last;
         * this.last = node;
         */
    }}
Copier après la connexion

注:第一种方法是先让last等于尾结点 再让他的前驱等于上一个地址 而第二种方法是先使插入的尾结点的前驱等于上一个地址 再使其等于尾结点

删除第一次出现关键字为key的结点:

public void remove(int key) {
    ListNode cur = this.head;
    while (cur != null) {
        if (cur.val == key) {
            if (cur == head) {
                head = head.next;
                if (head != null) {
                    head.prev = null;
                } else {
                    last = null;
                }
            } else if (cur == last) {
                last = last.prev;
                last.next = null;
            } else {
                cur.prev.next = cur.next;
                cur.next.prev = cur.prev;
            }
            return;
        }
        cur = cur.next;
    }}
Copier après la connexion

删除所有值为key的结点:

public void removeAllKey(int key) {
    ListNode cur = this.head;
    while (cur != null) {
        if (cur.val == key) {
            if (cur == head) {
                head = head.next;
                if (head != null) {
                    head.prev = null;
                } else {
                    last = null;
                }
            } else if (cur == last) {
                last = last.prev;
                last.next = null;
            } else {
                cur.prev.next = cur.next;
                cur.next.prev = cur.prev;
            }
            //return;
        }
        cur = cur.next;
    }}
Copier après la connexion

注:他和remove的区别就是删除完后是不是直接return返回,如果要删除所有的key值则不return,让cur继续往后面走。

任意位置插入,第一个数据节点为0号下标:

public void addIndex(int index,int data) {
    if (index < 0 || index > size()) {
        System.out.println("index 位置不合法");
    }
    if (index == 0) {
        addFirst(data);
        return;
    }
    if (index == size()) {
        addLast(data);
        return;
    }
    ListNode cur = searchIndex(index);
    ListNode node = new ListNode(data);
    node.next = cur;
    cur.prev.next = node;
    node.prev = cur.prev;
    cur.prev = node;}public ListNode searchIndex(int index) {
    ListNode cur = this.head;
    while (index != 0) {
        cur = cur.next;
        index--;
    }
    return cur;}
Copier après la connexion

思路:先判断 在头位置就头插 在尾位置就尾插 在中间就改变四个位置的值。

注意:单向链表找cur时要-1,但双向链表不用 直接返回cur就好

清空链表:

public void clear() {
    while (this.head != null) {
        ListNode curNext = head.next;
        head.next = null;
        head.prev = null;
        head = curNext;
    }
    last = null;}
Copier après la connexion
Copier après la connexion

3.3 链表面试题

3.3.1反转链表:

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

这里的

cur = this.head;

prev = null;

curNext = cur.next;

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

public ListNode reverseList() {
    if (this.head == null) {
        return null;
    }
    ListNode cur = this.head;
    ListNode prev = null;
    while (cur != null) {
        ListNode curNext = cur.next;
        cur.next = prev;
        prev = cur;
        cur = curNext;
    }
    return prev;}
Copier après la connexion

3.3.2找到链表的中间结点:

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

public  ListNode middleNode() {
    if (head == null) {
        return null;
    }
    ListNode fast = head;
    ListNode slow = head;
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        if (fast == null) {
            return slow;
        }
        slow = slow.next;
    }
    return slow;}
Copier après la connexion

3.3.3输入一个链表 返回该链表中倒数第k个结点

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

public ListNode findKthToTail(ListNode head,int k) {
    if (k <= 0 || head == null) {
        return null;
    }
    ListNode fast = head;
    ListNode slow = head;
    while (k - 1 != 0) {
        fast = fast.next;
        if (fast == null) {
            return null;
        }
        k--;
    }
    while (fast.next != null) {
        fast = fast.next;
        slow = slow.next;
    }
    return slow;}
Copier après la connexion

3.3.4合并两个链表 并变成有序的

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

public  static  ListNode mergeTwoLists(ListNode headA,ListNode headB) {
    ListNode newHead = new ListNode(-1);
    ListNode tmp = newHead;
    while (headA != null && headB != null) {
        if(headA.val <headB.val) {
            tmp.next = headA;
            headA = headA.next;
            tmp = tmp.next;
        } else {
            tmp.next = headB;
            headB = headB.next;
            tmp = tmp.next;
        }
    }
    if (headA != null) {
        tmp.next = headA;
    }
    if (headB != null) {
        tmp.next = headB;
    }
    return newHead.next;}
Copier après la connexion

最后返回的是傀儡结点的下一个 即newHead.next

3.3.5 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。(即将所有小于x的放在x左边,大于x的放在x右边。且他们本身的排序不可以变)

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

//按照x和链表中元素的大小来分割链表中的元素public ListNode partition(int x) {
    ListNode bs = null;
    ListNode be = null;
    ListNode as = null;
    ListNode ae = null;
    ListNode cur = head;
    while (cur != null) {
        if(cur.val < x){
            //1、第一次
            if (bs == null) {
                bs = cur;
                be = cur;
            } else {
                //2、不是第一次
                be.next = cur;
                be = be.next;
            }
        } else {
            //1、第一次
            if (as == null) {
                as = cur;
                as = cur;
            } else {
                //2、不是第一次
                ae.next = cur;
                ae = ae.next;
            }
        }
        cur = cur.next;
    }
    //预防第1个段为空
    if (bs == null) {
        return as;
    }
    be.next = as;
    //预防第2个段当中的数据,最后一个节点不是空的。
    if (as != null) {
        ae.next = null;
    }
    return be;}
Copier après la connexion

3.3.6 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。(有序的链表中重复的结点一定是紧紧挨在一起的)

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

public ListNode deleteDuplication() {
    ListNode cur = head;
    ListNode newHead = new ListNode(-1);
    ListNode tmp = newHead;
    while (cur != null) {
        if (cur.next != null && cur.val == cur.next.val) {
            while (cur.next != null && cur.val == cur.next.val) {
                cur = cur.next;
            }
            //多走一步
            cur = cur.next;
        } else {
            tmp.next = cur;
            tmp = tmp.next;
            cur = cur.next;
        }
    }
    //防止最后一个结点的值也是重复的
    tmp.next = null;
    return newHead.next;}
Copier après la connexion

3.3.7 链表的回文结构。

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

public boolean chkPalindrome(ListNode head) {
    if (head == null) {
        return true;
    }
    ListNode fast = head;
    ListNode slow = head;
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
    }
    //slow走到了中间位置
    ListNode cur = slow.next;
    while (cur != null) {
        ListNode curNext = cur.next;
        cur.next = slow;
        slow = cur;
        cur = curNext;
    }
    //反转完成
    while (head != slow) {
        if(head.val != slow.val) {
            return false;
        } else {
            if (head.next == slow) {
                return true;
            }
            head = head.next;
            slow = slow.next;
        }
        return true;
    }
    return true;}
Copier après la connexion

3.3.8 输入两个链表,找出它们的第一个公共结点。

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

他是一个Y字形

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    if (headA == null || headB == null) {
        return null;
    }
    ListNode pl = headA;
    ListNode ps = headB;
    int lenA = 0;
    int lenB = 0;
    //求lenA的长度
    while (pl != null) {
        lenA++;
        pl = pl.next;
    }
    pl = headA;
    //求lenB的长度
    while (ps != null) {
        lenB++;
        ps = ps.next;
    }
    ps = headB;
    int len = lenA - lenB;//差值步
    if (len < 0) {
        pl = headB;
        ps = headA;
        len = lenB - lenA;
    }
    //1、pl永远指向了最长的链表,ps永远指向了最短的链表   2、求到了插值len步
    //pl走差值len步
    while (len != 0) {
        pl = pl.next;
        len--;
    }
    //同时走直到相遇
    while (pl != ps) {
        pl = pl.next;
        ps = ps.next;
    }
    return pl;}
Copier après la connexion

3.3.9 给定一个链表,判断链表中是否有环。

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

提问:为啥么fast一次走两步,不走三步?

答:如果链表只有两个元素他们则永远相遇不了(如上图的示例2),而且走三步的效率没有走两步的效率高。

public boolean hasCycle(ListNode head) {
    if (head == null) {
        return false;
    }
    ListNode fast = head;
    ListNode slow = head;
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow) {
            return true;
        }
    }
    return false;}
Copier après la connexion

3.3.10 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

Explication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemplesExplication détaillée de la liste de séquences Java et de la liste chaînée avec des exemples

public ListNode detectCycle(ListNode head) {
    if (head == null) {
        return null;
    }
    ListNode fast = head;
    ListNode slow = head;
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow) {
            break;
        }
    }
    if (fast == null || fast.next == null) {
        return null;
    }
    fast = head;
    while (fast != slow) {
        fast = fast.next;
        slow = slow.next;
    }
    return fast;}
Copier après la connexion

4. 顺序表和链表的区别和联系

4.1顺序表和链表的区别

顺序表:一白遮百丑

白:空间连续、支持随机访问

丑:

  • 中间或前面部分的插入删除时间复杂度O(N)

  • 增容的代价比较大。

链表:一(胖黑)毁所有

胖黑:以节点为单位存储,不支持随机访问

所有:

  • 任意位置插入删除时间复杂度为O(1)

  • 没有增容问题,插入一个开辟一个空间。

组织:

1、顺序表底层是一个数组,他是一个逻辑上和物理上都是连续的

2、链表是一个由若干结点组成的一个数据结构,逻辑上是连续的 但是在物理上[内存上]是不一定连续的。

操作:

1、顺序表适合,查找相关的操作,因为可以使用下标,直接获取到某个位置的元素

2、链表适合于,频繁的插入和删除操作。此时不需要像顺序表一样,移动元素。链表的插入 只需要修改指向即可。

3、顺序表还有不好的地方,就是你需要看满不满,满了要扩容,扩容了之后,不一定都能放完。所以,他空间上的利用率不高。

4.2数组和链表的区别

链表随用随取 要一个new一个

而数组则不一样 数组是一开始就确定好的

4.3AeeayList和LinkedList的区别

集合框架当中的两个类

集合框架就是将 所有的数据结构,封装成Java自己的类

以后我们要是用到顺序表了 直接使用ArrayList就可以。

推荐学习:《java视频教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:csdn.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal