Java:数据结构-链表

本文详细探讨了Java中的链表数据结构,包括单链表、带头结点的单链表、循环链表及其各种操作,如合并有序链表、逆序输出、逆置、查找倒数k个节点、查找相交节点、插入节点和检测环并找到入环节点。还简要介绍了双向链表的基本操作。
摘要由CSDN通过智能技术生成

一、单链表

1.不带头节点的单链表:

主体:

public class LianBiaowithoutHead <E> {

    protected Node<E> head;			//声明第一个结点(并不是头结点)

    class Node<E>{					//创建内部类Node
        protected E element;	
        protected Node<E> next;

        public Node(E data){
            this.element = data;
        }
      }
    }

方法:
不带头结点的单链表在进行操作时,移动指针语句:tmp = tmp.next需要写在操作语句之后,因为head结点保存着第一个结点的元素,不可以跳过它。

增删改查等代码较简单不放上来了,这里放一个show方法做代表。

	public void show(){
	 	Node<E> tmp = head;
        while(tmp != null){
            System.out.print(tmp.element+" ");
            tmp = tmp.next;    //注意在操作语句之后移动tmp,否则会跳过第一个结点,而这里的head是放有数据的
        }
        System.out.println();
	}

2.带头结点的单链表:

主体:

public class LianBiaowithHead <E>{
    protected Node <E> head;

    class Node<E>{
        protected E element;
        protected Node<E> next;

        public Node(E data){
            this.element = data;
        }
    }

    public LianBiaowithHead(){ //需要创立头结点
        head = new Node<>((E)new Object());
    }
 }

方法:
带头结点的单链表在进行删除等操作时,移动指针语句:tmp = tmp.next需要写在操作语句之前,因为head结点的数据域没有东西,需要跳过它再进行打印等操作。

依然放一个show方法做代表。

    public void show(){
        Node<E> tmp = head;

        while(tmp.next != null){
            tmp = tmp.next;      //跳过头结点打印
            System.out.print(tmp.element + " ");
        }
        System.out.println();
    }

3.循环链表

主体:

public class CircleList<E> {//循环单链表(带头结点)

    protected Node<E> head;

    class Node <E>{
        protected E element;
        protected Node<E> next;

        public Node(E data){
            this.element = data;
        }


    }

    public CircleList(){
        this.head = new Node<>((E)new Object());
        head.next = head;
    }

方法:
和上面的2,3一样,记得将最后一个结点的指针域设成head,遍历的循环条件变成 tmp.next != head

以add方法作代表:

    public void addTail(E data){
        Node<E> n = new Node<E>(data);
        Node<E> tmp= head;
        while(tmp.next != head){
            tmp = tmp.next;
        }
        n.next = tmp.next;
        tmp.next = n;
    }

4.单链表的一些其他基本方法

(1)【合并两个有序链表,合并后依然有序】:

思想:
先比较list1,list2的第一个结点元素的大小,小的作合并后newList的头结点,以两个链表的表头同时不为空作循环条件,陆续比较元素大小,小的跟在新表指针后,同时该旧表头往后移动,另一个不动。也就是一个if else语句。

代码实现:

 public <E extends Comparable<E>> Node<E> mergeList(Node<E> head1,Node<E> head2){ 
        Node<E> tmp = null;
        Node<E> curHead;

        if(head1.element.compareTo(head2.element) <0){
            curHead = head1;
            head1 = head1.next;  //别忘了这个的表头要往后移一个
        }
        else {
            curHead = head2;
            head2 = head2.next;
        }
        tmp = curHead;
        while(head1!= null  && head2!= null){
            if(head1.element.compareTo(head2.element)<0){
                tmp.next =head1;
                head1 = head1.next;
            }
            else{
                tmp.next = head2;
                head2 = head2.next;

            }
            tmp = tmp.next;
    }
        if(head1 == null){
            tmp.next = head2;
        }
        if(head2 == null){
            tmp.next = head1;
        }

        return curHead;
    }

tips1:
因为要使用compareTo()方法比较element,所以要在方法声明时在T后extends Comparable,也就是在说:擦除的时候不用擦的那么彻底,擦到还有Comparable,能让我使用它的方法~

tips2:
自己在写代码的时候一遇到泛型就有点乱,不知道怎么写方法声明的顺序了,正确顺序应该是:pubic <T> 返回值 方法名(){}

(2)【逆序输出链表元素】:

思想:
用递归可以简单实现。运行时一层层的进reversePrint方法,每一层都没有走到底,直到最后一层(head指针为空)进入if语句后return,这才返回上一层继续往下走进行打印数据,这一层的方法才算结束,正常return后再往下走打印数据……,直到return到最初进入的一层。最后输出就是逆序的。

代码实现:

    public static <E> void reversePrint(LianBiaowithoutHead<E>.Node<E> head){
        if(head == null)
            return;
        reversePrint(head.next);
        System.out.print(head.element + " ");

    }

(3)【逆置链表】

思想:
设置三个指针,也就是除了普通临时指针cur之外,另外设置一个在当前指针之前的指针p,一个在当前指针之后的指针next,以当前指针不空为条件进行循环,每一次循环都会将p,cur之间的指向调转方向。

代码实现:

   public Node<E> reverseList(Node<E> head){ 
        Node <E> cur = head;
        Node <E> p = null;
        Node <E> newHead =null;

        while(cur!= null){
            Node<E> next = cur.next;
            if(next == null)
                newHead = cur;
            cur.next = p;
            p = cur;
            cur = next;
        }

        return newHead;
    }

(4)【查找单链表中倒数第k个结点】:

思想:
倒数第k个结点和最后一个结点下标差k-1-,所以可以设立两个指针,一个指针p1先走k-1步,再和另一个起点在head的指针p2同时前进,当p1.next为空时,p2也就走到了倒数第k个结点。
看图:
在这里插入图片描述

代码实现:

    public E findTheK(int index){

        if(head == null || index<0)
            return null;
        Node<E> p1 = head;
        Node<E> p2 = head;
        int num = 0;

        while (num != index-1){
            p2 = p2.next;
            num++;
        }

        while(p2.next != null){
            p1 = p1.next;
            p2 = p2.next;
        }

        return p1.element;

    }
<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值