数据结构与算法学习笔记(三)链表

本文深入探讨了链表这一基础数据结构,包括链式存储概念、链表的实现原理、分类及其特性。详细介绍了单向链表和双向链表的节点类设计,以及单向链表的插入、删除操作实现。同时,讨论了判断单链表是否存在环的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.概述

链式存储
用一组任意类型的存储单元存储线性表,在逻辑上面相邻的结点在物理位置上面不一定相邻
链表(Linked list)
采用链式存储方法的线性表叫做链表
链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接(“links”)
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)
性质

  • 其节点的存储单元可以不连续,每个节点中除存储原表结点中的数据外,还须存储上一个/下一个节点的地址,以反映节点之间的逻辑关系
  • 获取数据麻烦,需要遍历查找,比数组慢
  • 方便插入、删除

2.实现原理

创建一个节点类,其中节点类包含两个部分,第一个是数据域(你到时候要往节点里面储存的信息),第二个是引用域(相当于指针,单向链表有一个指针,指向下一个节点;双向链表有两个指针,分别指向下一个和上一个节点)
创建一个链表类,其中链表类包含三个属性:头结点、尾节点和大小,方法包含添加、删除、插入等等方法

3.分类

  • 单向链表
    单向链表只有一个指针域,在整个节点中数据域用来存储数据元素,指针域用于指向下一个具有相同结构的节点
    在这里插入图片描述
//单向链表的节点类
public class Node {
     public Object data;
     public Node next;
     
     public Node(Object e){
        this.data = e;
     }
 }

  • 双向链表

在这里插入图片描述

//双向链表的节点类
public class Node {
      public Object e;//每个节点中间位置用来存放你存储的东西
      public Node next;//每个节点的后一个指向
      public Node pre;//每个节点的前一个指向
      public Node(){
  
      }
      public Node(Object e){
          this.e = e;
         next = null;
         pre = null;
     }
 }
  • 环形链表
  • 双向环形链表

在这里插入图片描述

4.单向链表

package com.security.controller;

/**
 * 单向链表
 */
public class MyLink {
    //头节点
    Node head = null;

    /**
     * 链表中的节点
     */
    class Node{
        //节点的引用,指向下一个节点
        Node next = null;
        //节点的对象,即内容
        int data;

        public Node(int data){
            this.data = data;
        }
    }

    /**
     * 向链表中插入数据
     * @param d
     */
    public void addNode(int d){
        //实例化一个节点
        Node newNode = new Node(d);
        if (head == null) {
            head = newNode;
            return;
        }
        Node tmp = head;
        while (tmp.next != null){
            tmp = tmp.next;
        }
        tmp.next = newNode;
    }

    /**
     * 除第index个节点
     * @param index
     * @return
     */
    public boolean deleteNode(int index){
        if (index < 1 || index > length()){
            return false;
        }
        if (index == 1){
            head = head.next;
            return true;
        }
        int i = 1;
        Node preNode = head;
        Node curNode = preNode.next;
        while (curNode != null){
            if (i == index){
                preNode.next = curNode.next;
                return true;
            }
            preNode = curNode;
            curNode = curNode.next;
            i++;
        }
        return false;
    }

    /**
     * 返回节点长度
     * @return
     */
    public int length(){
        int length = 0;
        Node tmp = head;
        while (tmp != null){
            length++;
            tmp = tmp.next;
        }
        return length;
    }

    /**
     * 在不知道头指针的情况下删除指定节点
     * @param n
     * @return
     */
    public boolean deleteNode11(Node n){
        if (n == null || n.next == null){
            return false;
        }
        int tmp = n.data;
        n.data = n.next.data;
        n.next.data = tmp;
        n.next = n.next.next;
        System.out.println("删除成功!");
        return true;
    }

    public void printList(){
        Node tmp = head;
        while (tmp != null){
            System.out.println(tmp.data);
            tmp = tmp.next;
        }
    }

    public static void main(String[] args) {
        MyLink list = new MyLink();
        list.addNode(88);
        list.addNode(66);
        list.addNode(77);
        list.addNode(2);
        list.addNode(55);
        list.addNode(36);
        System.out.println("linkLength:" + list.length());
        System.out.println("head.data:" + list.head.data);
        list.printList();
        list.deleteNode(4);
        System.out.println("After deleteNode(4):");
        list.printList();
    }

}

5.判断单链表是否有环

单链表成环一般有三种情况:

  1. 从头节点指向下个,一直指下去,最后一个结点的next指向null
  2. 从头节点指向下个,一直指下去,最后一个结点的next指向头节点,形成一个首尾相连的环链表
  3. 从头节点指向下个,一直指下去,最后一个结点的next指向局部节点,形成一个局部尾部有环的链表

解法:

  1. 先定义1个结点,先让他等于头节点,然后向后遍历,遍历一次,和头节点对比一次,如果出现相同,说明链表有环,如果没有出现相等情况,则说明没有环

这种算法只能处理,前两种情况,因此缺乏普遍性,不适用

  1. 遍历链表,每遍历一个,把他们的hashcode值,先和数组里面的比较,如果没有再存储到一个数组里,如果找到有重复的,就说明有环
  2. 定义两个指针,一个跑得快,一个跑得慢,有一天他两相遇了,说明有环
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值