数据结构的开始——单链表

1.链表的基本概念

首先看一下什么是链表?单向链表就像一个铁链一样,元素之间相互连接,包含多个结点,每个结点有一个指向后继元素的next指针。表中最后一个元素的next指向null。如下图
特点:①缺点:只能连续访问,效率低,但是通过双向链表缓解了该问题②优点:有助于添加元素,扩容方便,没空间限制,不会溢出,可以存储很多个元素。
image.png
节点和头结点
在链表中 ,每个点都由值和指向下一个结点的地址组成的独立的单元,称为一个结点,有时也称为节点,含义都是一样的。
对于单链表,如果知道了第一个元素,就可以通过遍历访问整个链表,因此第一个结点最重要,一般称为头结点
虚拟节点
在做题以及在工程里经常会看到虚拟结点的概念,其实就是一个结点dummyNode,其next指针指向head,也就是dummyNode.next=head。
因此,如果我们在算法里使用了虚拟结点,则要注意如果要获得head结点,或者从方法(函数)里返回的时候,则应使用dummyNode.next。

  1. 虚拟节点可以简化链表的操作,可以不用考虑特殊节点头节点

2.链表的构建

/**
 * 单链表的定义
 * @author NuoMi
 */
public class Node {
    public int value;
    public Node next;

    public Node(int value) {
        this.value = value;
        next = null;
    }
}

3.链表的基本操作

1.遍历:
  /**
     * 获取链表的长度
     * @param head 头节点
     * @return
     */
    public static int getListLength(Node head) {
        int length = 0;
        Node node = head;
        while (node != null) {
            length++;
            node = node.next;
        }
        return length;
    }
2.插入节点:

需要考虑是否是头节点
表头插入:
如果是头节点直接nodeInsert.next = head ,head = nodeInsert
image.png
在中间插入:
不是头节点则需要先遍历到头节点的前一个节点,然后nodeInsert.next = pNode.next,
pNode.next = nodeInsert
image.png

 /**
     * 插入节点
     * @param head 头节点
     * @param nodeInsert 插入节点
     * @param position 位置
     * @return
     */
    public static Node insertNode(Node head, Node nodeInsert, int position) {
        // 如果为空将认为是一个空链表
        if (head == null) {
            return nodeInsert;
        }
        int size = getListLength(head);
        if (position > size + 1 || position < 1 ) {
            throw new RuntimeException("位置越界");
        }
        // 如果插入位置为1时
        if (position == 1) {
            nodeInsert.next = head;
            head = nodeInsert;
            return head;
        }
        Node pNode = head;
        // 注意要从1开始
        int count = 1;
        // 遍历道要插入的前一个节点
        while (count < position - 1) {
            pNode = pNode.next;
            count++;
        }
        // 顺序不能变
        nodeInsert.next = pNode.next;
        pNode.next = nodeInsert;
        return head;
    }

实现插入后仍然保持单调:
同样先考虑是否是头节点?
当值比头节点小时为头节点(head.value > nodeInsert.value)
不是头节点时
同样遍历到要插入的前一个节点
定义一个节点curNode保存遍历的节点,pNode保存遍历的前一个节点
当curNode.value < nodeInsert.value时pNode就是要插入的前一个节点进行插入

/**
     * 插入节点
     * @param head 头节点
     * @param nodeInsert 插入节点
     * @return
     */
    public static Node insertNodeOrder(Node head, Node nodeInsert) {
        // 如果为空将认为是一个空链表
        if (head == null) {
            return nodeInsert;
        }
        // 如果插入位置为1时
        if (head.value > nodeInsert.value) {
            nodeInsert.next = head;
            head = nodeInsert;
            return head;
        }
        Node pNode = null;
        Node curNode = head;
        // 遍历道要插入的前一个节点
        while (curNode != null && curNode.value < nodeInsert.value) {
            pNode = curNode;
            curNode = curNode.next;
        }
        // 顺序不能变
        nodeInsert.next = pNode.next;
        pNode.next = nodeInsert;
        return head;
    }
3.删除节点

同样要考虑是否是头节点
删除表头:

/**
     * 删除节点
     * @param head 头节点
     * @param position 位置
     * @return
     */
    public static Node deleteNode(Node head, int position) {
        if (head == null) {
            throw new RuntimeException("链表不存在");
        }
        int size = getListLength(head);
        if (position < 1 || position > size) {
            throw new RuntimeException("位置过界");
        }
        // 删除头节点
        if (position == 1) {
            head = head.next;
            return head;
        }

        Node pNode = head;
        int count = 1;
        while (count < position - 1) {
            pNode = pNode.next;
            count ++;
        }
        pNode.next = pNode.next.next;
        return head;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值