算法通关村第一关-----链表青铜挑战笔记

1.java(jvm)是如何构造链表的

链表可以形象的表示为

链表的形象表示

上图中的每一个节点可以用java中的一个类来表示,这个类包含两个成员变量,为别是数据域和指针域,数据域负责存储数据,指针域负责存储下一个节点的地址,为了方便,可以将成员变量设置为public

public class LinkedNode {
    public int data;
    public LinkedNode next;

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

jvm包含栈区和堆区,栈区存储对象的引用(地址),堆区存储真正的对象,如下图

算法通关村第一关-----链表青铜挑战笔记_第1张图片

2.单链表增加节点(分为头部、中间、尾部)

 /**
     * 获取链表长度
     * @param head 链表头节点
     * @return 链表长度
     */
    public static int getLength(LinkedNode head) {
        int count = 0;
        LinkedNode node = head;
        while(node != null){
            count++;
            node = node.next;
        }
        return count;
    }

    /**
     * 在链表指定位置插入节点
     * @param head 链表头节点
     * @param node 待插入节点
     * @param insertPosition 插入位置,从1开始
     * @return 链表头节点
     */

    public static LinkedNode insert(LinkedNode head, LinkedNode node,int insertPosition){
        //头节点为空,可以规定如下:
        if(head==null){
            head = node;
            return head;
        }
        //插入位置应在1-length+1
        if (insertPosition<1 || insertPosition>getLength(head)+1){
            System.out.println("插入位置越界");
            return head;
        }
        //头部插入
        if (insertPosition==1){
            node.next = head;
            head = node;
            return head;
        }
        int iter = 1;
        LinkedNode iterNode = head;
        //插入位置的前一个节点
        while (iter < insertPosition - 1){
            iterNode = iterNode.next;
            iter++;
        }
        //插入操作
        node.next = iterNode.next;
        iterNode.next = node;
        return head;
    }

3.单链表删除节点(分为头部、中间、尾部)

/**
     * 删除指定位置节点
     * @param head 链表头节点
     * @param deletePosition 删除位置,从1开始
     * @return 链表头节点
     */
    public LinkedNode delete(LinkedNode head, int deletePosition){
        //头节点为空,可以规定如下:
        if (head == null){
            return head;
        }
        //删除位置应在1-length之间
        if (deletePosition<1||deletePosition>getLength(head)){
            System.out.println("删除位置越界");
            return head;
        }
        //删除头节点
        if (deletePosition == 1){
            head = head.next;
            return head;
        }
        int iter = 1;
        LinkedNode iterNode = head;
        //找到删除位置的前一个节点
        while (iter < deletePosition-1){
            iter++;
            iterNode = iterNode.next;
        }
        //删除操作
        iterNode.next = iterNode.next.next;
        return head;
    }

4.双向链表的构造、插入和删除节点

构造本身也可以看做插入,直接看插入代码,选择头部插入或者尾部插入构造双向链表

双向链表节点

public class DoubleNode {
    public int data;
    public DoubleNode pre;
    public DoubleNode next;

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

双向链表

public class DoubleLinkedList {
    public DoubleNode first;
    public DoubleNode last;

    public DoubleLinkedList() {
        this.first = null;
        last = first;
    }
}

双向链表是否为空

public static boolean isEmpty(DoubleLinkedList doubleLinkedList) {
     return doubleLinkedList.first == null;
}

头部插入

/**
     * 在头部插入
     *
     * @param doubleLinkedList 双向链表
     * @param node             待插入节点
     * @return 双向链表
     */
    public static DoubleLinkedList insertFirst(DoubleLinkedList doubleLinkedList, DoubleNode node) {
        //双向链表为空时,first和last同时指向待插入节点
        if (isEmpty(doubleLinkedList)) {
            doubleLinkedList.first = node;
            doubleLinkedList.last = node;
            return doubleLinkedList;
        }
        //双向链表不为空时,进行插入
        doubleLinkedList.first.pre = node;
        node.next = doubleLinkedList.first;
        //插入后,更新first
        doubleLinkedList.first = node;
        return doubleLinkedList;
    }

在尾部插入

/**
     * 在尾部插入
     *
     * @param doubleLinkedList 双向链表
     * @param node             待插入节点
     * @return 双向链表
     */
    public static DoubleLinkedList insertLast(DoubleLinkedList doubleLinkedList, DoubleNode node) {
        //双向链表为空时,first和last同时指向待插入节点
        if (isEmpty(doubleLinkedList)) {
            doubleLinkedList.first = node;
            doubleLinkedList.last = node;
            return doubleLinkedList;
        }
        //双向链表不为空时,进行插入
        doubleLinkedList.last.next = node;
        node.pre = doubleLinkedList.last;
        //插入后,更新last
        doubleLinkedList.last = node;
        return doubleLinkedList;
    }

在中间插入

/**
     * 在指定值后插入节点
     * @param doubleLinkedList 双向链表
     * @param key 指定值
     * @param node 待插入节点
     * @return 双向链表
     */
    public DoubleLinkedList insertAfterKey(DoubleLinkedList doubleLinkedList, int key, DoubleNode node) {
        //双向链表为空,直接插入
        if (isEmpty(doubleLinkedList)) {
            doubleLinkedList.first = node;
            doubleLinkedList.last = node;
            return doubleLinkedList;
        }
        //遍历寻找插入的前一个节点
        DoubleNode iterNode = doubleLinkedList.first;
        while (iterNode != null && iterNode.data != key) {
            iterNode = iterNode.next;
        }
        //未找到或key对应最后一个节点,均在最后一个节点之后进行插入
        if (iterNode == null || iterNode == doubleLinkedList.last) {
            doubleLinkedList.last.next = node;
            node.pre = doubleLinkedList.last;
            doubleLinkedList.last = node;//
        }else{
            //在中间进行插入,这里可能比较复杂,一定要先处理iterNode.next,在处理iterNode
            //可以简单理解为iterNode肯定是iterNode,但是iterNext是会随着插入改变的
            iterNode.next.pre = node;
            node.next = iterNode.next;
            iterNode.next = node;
            node.pre = iterNode;
        }
        return doubleLinkedList;
    }

头部删除

/**
     * 从头部删除
     * @param doubleLinkedList 双向链表
     * @return 双向链表
     */
    public DoubleLinkedList deleteFirst(DoubleLinkedList doubleLinkedList){
        //双向链表为空,直接返回
        if(isEmpty(doubleLinkedList)){
            return doubleLinkedList;
        }
        //双向链表只有一个节点,设置first=last=null返回,
        if(doubleLinkedList.first.next == null){
            doubleLinkedList.first = null;
            doubleLinkedList.last = null;
            return doubleLinkedList;
        }
        //双向链表有多个节点,第二个节点的pre指针设置为null,first指向第二个节点
        doubleLinkedList.first.next.pre = null;
        doubleLinkedList.first = doubleLinkedList.first.next;
        return doubleLinkedList;
    }

从尾部删除

/**
     * 从尾部删除
     * @param doubleLinkedList 双向链表
     * @return 双向链表
     */
    public DoubleLinkedList deleteLast(DoubleLinkedList doubleLinkedList){
        //双向链表为空,直接返回
        if(isEmpty(doubleLinkedList)){
            return doubleLinkedList;
        }
        //双向链表只有一个节点,设置first=last=null返回,
        if(doubleLinkedList.first.next == null){
            doubleLinkedList.first = null;
            doubleLinkedList.last = null;
            return doubleLinkedList;
        }
        //双向链表有多个节点,倒数第二个节点的next指针设置为null,last指向倒数第二个节点
        doubleLinkedList.last.pre.next = null;
        doubleLinkedList.last = doubleLinkedList.last.pre;
        return doubleLinkedList;
    }

从中间删除

/**
     * 在中间位置删除
     * @param doubleLinkedList 双向链表
     * @param key 待删除节点的key
     * @return 双向链表
     */
    public DoubleLinkedList deleteByKey(DoubleLinkedList doubleLinkedList, int key) {
        双向链表为空,直接返回
        if (doubleLinkedList == null) {
            return null;
        }
        //寻找待删除节点
        DoubleNode iterNode = doubleLinkedList.first;
        while (iterNode != null && iterNode.data != key) {
            iterNode = iterNode.next;
        }
        //未找到,直接返回
        if (iterNode == null){
            return doubleLinkedList;
        }
        //待删除节点是第一个节点
        if (iterNode == doubleLinkedList.first){
            doubleLinkedList.first.next.pre = null;
            doubleLinkedList.first = doubleLinkedList.first.next;
            return doubleLinkedList;
        }
        //待删除节点是最后一个节点
        if(iterNode == doubleLinkedList.last){
            doubleLinkedList.last.pre.next = null;
            doubleLinkedList.last = doubleLinkedList.last.pre;
            return doubleLinkedList;
        }
        //待删除节点是中间节点
        iterNode.pre.next = iterNode.next;
        iterNode.next.pre = iterNode.pre;
        return doubleLinkedList;
    }
    

你可能感兴趣的:(算法训练营,算法,链表,笔记)