java-----单链表

Posted 小鹿可可乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java-----单链表相关的知识,希望对你有一定的参考价值。

1.单链表基本操作

链表是一个有序的列表
链表不同于数组,链表是以结点的形式存储,在物理空间上不一定连续
链表的每个结点的内部包含value(数据)域,next(指针)域,指针域指向下一个结点的位置

1.1代码

public class SingleLink<E extends Comparable<E>> implements List<E> {
    private Node<E> head;
    private Node<E> tail;//尾部  尾插的时间复杂度O(1)
    private int size;

    public SingleLink(){
        this.head = null;//空链表
        this.tail = null;
    }

    @Override
    public void addHead(E value) {//O(1)
        Node<E> node = new Node<>(value);
        if(head ==null && tail == null){
            head = node;
            tail = node;
        }else {

            //新节点的next = head
            node.next = head;
        }
        //更新新头节点位置
        head = node;
        size++;
    }

    @Override
    public void addTail(E value) {//O(1)
        //申请value节点
        Node<E> node = new Node<>(value);
        if(head==null ){//链表不存在有效节点
            head = node;
            tail = node;//唯一node    既是头又是尾
        }else{
            tail.next = node;
        }
        size++;
    }


    @Override
    public void removeHead() {
        if(head ==null){
            return;
        }
        else if(size==1){//head.next = null 只有一个节点
            tail=null;
        }
            head.value=null;
            Node<E> p = head.next;//p只保存地址
            head.next=null;
            head=p;
            size--;

    }

    @Override
    public void removeTail() {
        if(head == null){//链表为空
            return;
        }else if(size == 1){//一个节点
            head.value=null;
            head=null;
            tail = null;
        }else{//>=两个节点
            //找链表尾巴前趋
            Node<E> p =head;
            for(;p.next.next==null;p=p.next){
                ;
            }
                p.next = null;
                tail.value = null;//防止内存泄漏
                tail = p;//更新尾巴指向
        }
        size--;
    }

    @Override
    public void removeValue(E value) {
        if(head == null){
            return;
        }else if(head.value.compareTo(value) == 0){
            removeHead();
        }else{
            //找待删节点的前驱
            Node<E> p= head;
            for(;p.next.value.compareTo(value) != 0;p = p.next){
                ;
            }
            Node<E> q = p.next.next;
            p.next.value = null;//防止内存泄漏
            //p.next=q.next;
            //q.next=null;q.value=null;
            p.next.next = null;
            p.next = q;
            size--;
        }

    }

    @Override
    public boolean contains(E value) {
        for(Node<E> p = head;p!=null;p = p.next){
            if(p.value.compareTo(value) == 0){
                return true;
            }
        }
        return false;
    }

    @Override
    public void change(E srcValue, E aimValue) {
        for(Node<E> p = head;p!=null;p = p.next) {
            if (p.value.compareTo(srcValue) == 0) {
                p.value = aimValue;
            }
        }
    }

    @Override
    public void show(){
        for(Node<E> p = head;p!=null;p=p.next){
            System.out.print(p.value+" ");
        }
        System.out.println();
    }

    public Node<E> getHead() {
        return head;
    }

    public void setHead(Node<E> head) {
        this.head = head;
    }

    public void setTail(Node<E> tail) {
        this.tail = tail;
    }

    public Node<E> getTail() {
        return tail;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    //Node类型
    //当前类里边this以外,不用包含外部类对象引用
     static class Node<T>{
        T value;
        Node<T> next;

        public Node(T value) {
            this.value = value;
        }
    }

}

2.单链表练习题

2.1 逆置单链表

/*
    一、逆置单链表
     */
    public void reverseLink(){
        if(head == null || size == 1){
            return;
        }
        Node<E> p=head;
        Node<E> q=p.next;
        Node<E> s=q.next;
        head.next=null;//原来头节点->尾巴节点
        while(q != null){
            q.next=p;
            p = q;
            q = s;
            if(s!=null) {
                s = s.next;
            }
        }
        tail = head;//新尾巴用原来head更新
        head = p;//循环结束  p标志的使新头

    }

2.2 假设两个链表相交,输出相交节点

 //二、假设两个链表相交,输出相交节点
    public Node<E> getMeetNode(SingleLinkTest<E> link){
        //1.让长链表走差值步,长短链表一起向后遍历,
        int curSize = size;
        int linkSize = link.size;
        int diff = curSize-linkSize;
        Node<E> longLinkP = diff > 0 ? head : link.head;//longLinkP遍历长链表
        Node<E> shortLinkP = diff > 0 ? link.head : head;
        //长链表遍历差值步
        diff = Math.abs(diff);//取绝对值
        while(diff>0){
            longLinkP = longLinkP.next;
            diff--;
        }
        while(longLinkP != shortLinkP){
            longLinkP = longLinkP.next;
            shortLinkP = shortLinkP.next;
        }
        return longLinkP;
    }

2.3 给定一个链表,删除指定节点,O(1)时间复杂度删除指定节点

//三、给定一个链表,删除指定节点,O(1)时间复杂度删除指定节点
    public static <E extends Comparable<E>>boolean removeNode(SingleLink<E> link,SingleLink.Node node){
        //参数安全检测
        if(link == null || node == null){
            return false;
        }
        if(node == link.getTail()){
            link.removeTail();
        }else{
            node.value = node.next.value;//将当前节点node,下一个节点value赋值给当前节点
            node.next = node.next.next;//删除node的下一个节点
        }
        link.setSize(link.getSize()-1);//size--
        return false;
    }

2.4两个有序单链表合并为一个有序单链表


    //四、两个有序单链表合并为一个有序单链表
    public void mergeLink(SingleLinkTest<E> link){//this   link
        if(link == null || head == null && link.head == null){
            return;
        }
        if(this.head == null){
            this.head = link.head;
            this.tail = link.tail;
        }

        Node<E> p = this.head,q = link.head;
        //this.head 更新  两个链表开始的头部value,谁小谁作为起始
        this.head = this.head.value.compareTo(link.head.value)<0 ? this.head:link.head;
        if(p == head){
            p = p.next;
        }else{
            q = q.next;
        }
        Node<E> s = head;//新链表尾部  连接动作
        while(p != null && q != null){
            if(p.value.compareTo(q.value) < 0){
                s.next = p;
                p = p.next;
            }else{
                s.next = q;
                s = q;//更新到链表尾巴
                q = q.next;
            }
        }
        if(p == null){
            q = q.next;
        }else{
            p = p.next;
        }

        while(s.next != null){
            s = s.next;
        }
        this.tail = s;

    }

2.5 判断链表是否有环,并输出相交节点

 //五、判断链表是否有环,并输出相交节点
    private Node<E> isLoop0(){
        Node<E> fast = head,slow = head;
        do{
            if(fast == null || fast.next == null){
                return null;
            }
            fast = fast.next.next;
            slow = fast.next;

        }while(fast != slow);
            return fast;

    }

    public boolean isLoop(){
       return !(isLoop0() == null);
    }

    //环的入口点
    public Node<E> loopNode(){
        Node<E> fast = isLoop0();//获得相遇点
        Node<E> p = head,q = fast;
        while(p != q){
            p = p.next;
            q = q.next;
        }
        return p;
    }

今天也要好好学习呀~

以上是关于java-----单链表的主要内容,如果未能解决你的问题,请参考以下文章

java-----单链表

java数据结构:单链表常见操作代码实现

单链表java简易实现

Java实现单链表(步骤详解+源码)

反向单链表Java [重复]

Java带头节点单链表的增删融合以及是否有环