java链表实现

ref:

链表的概念

什么是链表,链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。

链表的入口节点称为链表的头结点也就是head。

java链表有三种类型,分别是单链表、双链表、和循环链表

以下用java定义了一个双链表节点类

//定义一个Node 类,Node 对象 表示双向链表的一个结点
class Node {
    public Object item; //真正存放数据
    public Node next; //指向后一个结点
    public Node pre; //指向前一个结点

    public Node(Object name) {
        this.item = name;
    }

    public String toString() {
        return "Node name=" + item;
    }
}

注意,需要定义一个构造函数,方便直接给数据域赋值

链表的存储方式

数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。

链表是通过指针域的指针链接在内存中各个节点。

所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。

链表和数组的性能对比

203移除元素

题目:给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

自解:

    /**
     * 203移除链表元素(自解)
     * @param head
     * @param val
     * @return
     */
    public ListNode removeElements(ListNode head, int val) {

        ListNode index=head;
        ListNode result=head;
        ListNode pre=null;
        while(index!=null){
            if(index.val==val){
                if(pre==null){
                    result=index.next;
                }else{
                    pre.next=index.next;
                }
            }else{
                pre=index;
            }
            index=index.next;
        }

        return result;
    }

代码随想录提供了一种使用虚结点的方式

     * 添加虚节点方式(随想录)
     * 时间复杂度 O(n)
     * 空间复杂度 O(1)
     * @param head
     * @param val
     * @return
     */
    public ListNode removeElements01(ListNode head, int val) {
        if (head == null) {
            return head;
        }
        // 因为删除可能涉及到头节点,所以设置dummy节点,统一操作
        ListNode dummy = new ListNode(-1, head);
        ListNode pre = dummy;
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == val) {
                pre.next = cur.next;
            } else {
                pre = cur;
            }
            cur = cur.next;
        }
        return dummy.next;
    }

这种方案异常的简洁,就是在原有链表基础上在head节点之前加了一个节点。

这里提供一个主方法方便测试:

public class day03 {
    public static void main(String[] args) {
        //定义一个测试的数据3,2,3,5,3
        ListNode node0=new ListNode(3);
        ListNode node1=new ListNode(1);
        node0.next=node1;
        ListNode node2=new ListNode(3);
        ListNode node3=new ListNode(3);
        node1.next=node2;
        node2.next=node3;
        ListNode node4=new ListNode(1);
        node3.next=node4;
        node4.next=null;
        //203移除链表元素
        ListNode newlianbiao=new day03().removeElements(node0,3);
        new day03().bianli(newlianbiao);

        


    }
    public void bianli(ListNode head){
        ListNode headnew=head;
        while(headnew!=null){
            System.out.print(headnew.val+",");
            headnew=headnew.next;
        }

    }
}

707设计一个链表类

 以单链表为例,设计一个运用了虚节点思想的可操作链表类

//707设计链表
class MyLinkedList {

    int size;

    //虚拟头结点
    ListNode head;


    public MyLinkedList() {
        this.size=0;
        this.head=new ListNode(-1);
    }

    /**
     * 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
     * @param index
     * @return
     */
    public int get(int index) {
        if(index<0||index>size-1){
            return -1;
        }
        ListNode result=this.head;
        for(int i=0;i<index+1;i++){
            result=result.next;
        }
        return result.val;

    }

    public void addAtHead(int val) {
        addAtIndex(0,val);

    }

    public void addAtTail(int val) {
        addAtIndex(size,val);

    }


    /**
     *将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index
     *  等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
     * @param index
     * @param val
     */
    public void addAtIndex(int index, int val) {
        //判断插入条件
        if(index<0){
            return;
        }else if(index>size){
            return;
        }
        size++;
        ListNode newnode=new ListNode(val);

        ListNode pre=this.head;
        ListNode pointer=pre.next;
        for(int i=0;i<index;i++){
            pre=pointer;
            pointer=pointer.next;
        }
        pre.next=newnode;
        newnode.next=pointer;

    }

    public void deleteAtIndex(int index) {
        //判断插入条件
        if(index<0){
            return;
        }else if(index>size-1){
            return;
        }
        size--;
        ListNode pre=this.head;
        ListNode pointer=pre.next;
        for(int i=0;i<index;i++){
            pre=pointer;
            pointer=pointer.next;
        }
        pre.next=pointer.next;
    }
}

206反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

这道题解法是复制每一个链表上的节点,重新造一个反过来的链表

   /**206. 反转链表
     *
     */
    public ListNode reverseList(ListNode head) {
        ListNode pre=null;
        ListNode now=head;
        ListNode newpre=null,newnow=null;
        while(now!=null){
            newnow=new ListNode(now.val);
            newnow.next=newpre;
            newpre=newnow;
            now=now.next;
        }
        return newnow;

    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值