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

本文介绍了如何使用Java实现链表的基础操作,包括单链表和双链表的构建、初始化、遍历、获取长度、插入节点以及删除节点的方法。重点讨论了插入和删除操作的关键步骤,强调了顺序的重要性。
摘要由CSDN通过智能技术生成

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

前言

全文代码均以Java语言复现,主要为自己学习做记录,如有问题,还请各位大佬们指点指点。

单链表

组成

由众多的节点(node)构成,而每个节点都是由数据域(data)和指针域(next)组成,其中我们称第一个节点为头结点(head)!!!【这很重要】

public class Node{
    private int data;
    private Node next;

    public Node(int data){
        this.data=data;
    }
    public int getData(){
        return data;
    }
    public Node getNext(){
        return next;
    }
    public void  setData(int data){
        this.data=data;
    }
    public void setNext(Node next){
        this.next=next;
    }
}

img

单链表的基本操作

1. 构建和初始化
class SingleLinkedList{
    // 申明头结点为全局变量
    Node head;
    public SingleLinkedList(){
        head=null;
    }
    /**
     * init & build 构建并初始化单链表
     * @param a
     */
    public void initSingleLinkedList(int a []){
        Node node0 = new Node(a[0]);
        Node node1 = new Node(a[1]);
        Node node2 = new Node(a[2]);
        Node node3 = new Node(a[3]);
        Node node4 = new Node(a[4]);
        // 头部节点依次相连
        head=node0;
        node0.next=node1;
        node1.next=node2;
        node2.next=node3;
        node3.next=node4;
        node4.next=null;
    }
}
2. 获取单链表长度
/**
     * 获取单链表长度
     * @return
     */
    public int getLengthSingleList(){
        Node cur;
        cur=head;
        int len=0;
        while(cur!=null){
            len++;
            cur=cur.next;
        }
        return len;
    }
3. 遍历单链表
/**
     * 遍历单链表
     */
    public void display(){
        Node cur=head;
        while(cur!=null){
            System.out.print(" "+cur.data);
            cur=cur.next;
        }
    }
4. 插入节点
/**
     * 插入节点
     * @param singleLinkedList
     * @param insertNode
     * @param place
     * @return
     */
    public Node insertNode(SingleLinkedList singleLinkedList,Node insertNode, int  place){
        // 判斷插入鏈錶是否為空
        if(head==null){
            System.out.println("此鏈錶為空,不能插入");
            return head;
        }
        // 判斷插入位置是否合法
        int size=singleLinkedList.getLengthSingleList();
        if(place>size+1||place<1){
            System.out.println("位置参数越界");
            return head;
        }
        // 表头位置插入节点
        if(place==1){
            insertNode.next=head;
            // insertNode 作为表头
            return insertNode;
        }
        // 指針指向頭結點
        Node pNode=head;
        // 取頭取尾 (舍零去長度減二)
        // 当pNode走到前一个位置就弹出for循环 即i=place-1
        for(int i =1;i<place-1;i++){
            pNode=pNode.next;
        }
        // 插入节点的关键代码
        insertNode.next=pNode.next; 
        pNode.next=insertNode;
        return  head;
    }

ps:为什么先是insertNode.next=pNode.next 再是pNode.next=insertNode? 两者可以调换顺序吗?

答: 两者是不能调换顺序的!

我们可以这么理解,因为在遍历单链表的时候,是通过指针才能找到下一个节点。如果先是将当前的pNode.next指向insertNode的话,insertNode.next就不知道要指向哪里了,这样就导致单链表发生断裂,从而不无法进行遍历了。

如果是先要插入的insertNode.next指向pNode.next节点,然后再pNode.next=insertNode,这样单链表就不会出现断裂的情况了。

img

5. 删除节点
/**
     * 删除节点
     * @param singleLinkedList
     * @param place
     * @return
     */
    public Node deleteNodeList(SingleLinkedList singleLinkedList,int place){
        int size = singleLinkedList.getLengthSingleList();
        if(place<1||place>size){
            System.out.println("刪除位置不合法");
            return head;
        }
        if(head==null){
            System.out.println("鏈錶為空,無法刪除");
            return null;
        }
        if(place==1){
            return head.next;
        }else{
            Node pNode=head;
            for(int i=1;i<place-1;i++){
                pNode=pNode.next;
            }
            // 删除节点的关键代码
            pNode.next=pNode.next.next;
        }
        return head;
    }
}

img

双链表链表

构成

同样是节点构成,只不过是节点内部的结构发生了变化,多了一个前驱指针。

/**
 * 双向链表的节点结构
 */
public class DoubleNode {

    public  DoubleNode prev;
    public  DoubleNode next;
    public  int data;
    DoubleNode(int data){
        this.data=data;
    }
    public DoubleNode getPrev() {
        return prev;
    }

    public void setPrev(DoubleNode prev) {
        this.prev = prev;
    }

    public DoubleNode getNext() {
        return next;
    }

    public void setNext(DoubleNode next) {
        this.next = next;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }
}

双链表的基本操作

1. 构建和初始化

以first和last作为全局变量的节点,来构建双链表

class DoubleLinkedList{
    // 定义头尾节点
    DoubleNode first;
    DoubleNode last;
    // 构造函数 无节点 头尾指针均指向null
    DoubleLinkedList (){
        first=null;
        last=first;
    }

    /**
     * build & init
     * @param a
     * @return
     */
    public void initDoubleLinkedList(int a[]){

        DoubleNode doubleNode0 = new DoubleNode(a[0]);
        DoubleNode doubleNode1=  new DoubleNode(a[1]);
        DoubleNode doubleNode2 = new DoubleNode(a[2]);
        DoubleNode doubleNode3 = new DoubleNode(a[3]);
        DoubleNode doubleNode4 = new DoubleNode(a[4]);
        // 表頭(指針)
        first=doubleNode0;
        doubleNode0.next=doubleNode1;
        doubleNode1.next=doubleNode2;
        doubleNode2.next=doubleNode3;
        doubleNode3.next=doubleNode4;
        // 錶尾(指針)
        last=doubleNode4;
        doubleNode4.prev=doubleNode3;
        doubleNode3.prev=doubleNode2;
        doubleNode2.prev=doubleNode1;
        doubleNode1.prev=doubleNode0;
        // return last; 逆序 尾部開始
        //return first;// 順序 頭部開始
    }
}

img

2. 遍历双链表
    /**
     * 向前遍历
     */
    public void displayForward(){
        DoubleNode cur;
        cur=first;
        while(cur!=null){
            System.out.print(" "+cur.getData());
            cur=cur.getNext();
        }
    }

    /**
     * 向后遍历
     */
    public void displayBackward(){
        DoubleNode cur;
        cur=last;
        while(cur!=null){
            System.out.print(" "+cur.getData());
            cur=cur.getPrev();
        }
    }
3. 获取双链表长度
/**
     * 获取双链表长度
     * @return
     */
    public int getLengthDoubleLinkedList(){
        DoubleNode pNode;
        pNode=first;
        int len =0;
        while(pNode!=null){
            len++;
            pNode=pNode.next;
        }
        return len;
    }

4. 判空双链表
/**
     * 判空双链表
     * @return
     */
    public boolean isEmpty(){
        if(first==null){
            return true;
        }return false;
    }
5. 插入节点
/**
     * 头部插入
     * @param data
     */
    public void insertNodeFirst(int data){
        DoubleNode newNode = new DoubleNode(data);
        if(isEmpty()){
            // 如果双链表为空
            last=newNode;
        }else{
            // 如果不为空
            first.prev=newNode;
        }
        newNode.next=first;
        // 左移动头指针(first)
        first=newNode;
    }
    /**
     * 尾部插入
     * @param data
     */
    public void insertNodeLast(int data){
        DoubleNode newNode = new DoubleNode(data);
        if(isEmpty()){
            // 如果双链表为空
            first=newNode;
        }else{
            // 如果不为空 左移动头指针first
            last.next=newNode;
        }
        newNode.prev=last;
        // 右移动尾指针(last)
        last=newNode;
    }

    /**
     * 插入中间节点
     * @param data
     * @param pos
     */
    public void insertNode(int data,int pos){
        DoubleNode newNode = new DoubleNode(data);
        DoubleNode cur=first;
        int size=getLengthDoubleLinkedList();
        if(pos<1||pos>size+1){
            System.out.println("插入位置参数错误,无法插入");
        }

        for (int i = 1; i < pos-1; i++) {
            cur=cur.next;
        }
        newNode.next=cur.next;
        cur.next.prev=newNode;
        cur.next=newNode;
        newNode.prev=cur;
    }

同理,在双链表中间插入节点的操作代码中,插入节点(newNode)的连接顺序是和单链表相似的,都是先右后左。

img

6. 删除节点
    /**
     * 删除头部节点
     * @return
     */
    public DoubleNode deleteHead(){
        DoubleNode temp=first;
        if(first.next==null){
            last=null;
        }else{
            first.next.prev=null;
        }
        // 节点删除后 尾部指针需要右移动
        first=first.next;
        return temp;
    }

    /**
     * 删除尾部节点
     * @return
     */
    public DoubleNode deleteLast(){
        DoubleNode temp=last;
        if(last.next==null){
            last=null;
        }else{
            // 删除节点 也就是temp存储的内容
            last.prev.next=null;
        }
        // 节点删除后 尾部指针需要左移动
        last=last.prev;
        return temp;
    }

    /**
     * 删除节点
     * @param pos
     * @return
     */
    public DoubleNode deleteNode(int pos){
        DoubleNode cur = first;
        DoubleNode temp;
        if(isEmpty()){
            System.out.println("链表为空,无法删除");
            return null;
        }else{
            for (int i = 1; i < pos-1; i++) {
                cur=cur.next;
            }
            temp=cur.next;
            cur.next=temp.next;
            temp.next.prev=cur;
        }
        return temp;
    }

在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Brilliant.Louis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值