JAVA链表

链表与数组的区别:

两者区别:
(1)数组静态分配内存,链表动态分配内存。
(2)数组在内存中是连续的,链表是不连续的。
(3)数组利用下标定位,查找的时间复杂度是O(1),链表通过遍历定位元素,查找的时间复杂度是O(N)。
(4)数组插入和删除需要移动其他元素,时间复杂度是O(N),链表的插入或删除不需要移动其他元素,时间复杂度是O(1)。
数组的优点:
(1)随机访问性比较强,可以通过下标进行快速定位。
(2)查找速度快
数组的缺点:
(1)数组需要开发者自己维护下标
(2)数组开辟时必须指定数组的长度,如果存放的元素过多,需要开发者自己扩容数组
(3)当在数组的某些位置增加和删除元素时,还要编写代码处理元素的移动
链表的优点:
(1)插入和删除的效率高,只需要改变指针的指向就可以进行插入和删除。
(2)内存利用率高,不会浪费内存,可以使用内存中细小的不连续的空间,只有在需要的时候才去创建空间。大小不固定,拓展很灵活。
链表的缺点:
查找的效率低,因为链表是从第一个节点向后遍历查找。

链表:

链表是一种物理存储结构上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
单链表:
在这里插入图片描述
链表的节点 = 数据域 + 引用域 节点与节点之间是通过引用域相连
链表物理存储单元是非连续的、非顺序的存储结构
循环单链表:
尾节点的 next 域指向头结点,进行循环操作
在这里插入图片描述
单链表:
(1)链表中每个元素包含一个称为节点的结构
(2)节点 = 数据域 + 引用域
(3)链表是一种物理存储单元上非连续、非顺序的存储结构
(4)链表在插入元素可以达到O(1)的复杂度,相比顺序表更快
(5)查找或访问特定编号的节点则需要O(n)的时间
例:设计一个带头节点的单链表
当删除或者增加一个节点时,只需要改变next的指向(O(1))
查找一个节点或者访问特定编号的节点(O(n))

//带头节点的单链表
class SingleLinkedListTakedHead<E>{
    protected Node<E> head;

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

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

    public SingleLinkedListTakedHead(){
        head = new Node<>((E)new Object());
    }

    //头插法 head之后去添加元素
    public void addHead(E data){
        //创建新节点
        Node<E> newNode = new Node<>(data);

        //绑定新节点的next
        newNode.next = head.next;
        //head.next指向新节点
        head.next = newNode;
    }

    //尾插法
    public void addTail(E data){
        //创建新节点
        Node<E> newNode = new Node<>(data);
        //遍历当前链表,找到最后一个节点
        Node<E> tmp = head;
        while(tmp.next != null){
            tmp = tmp.next;
        }

        //绑定最后的一个节点的next
        tmp.next = newNode;
    }

    public boolean delete(E data){
        //head节点需要单独处理
        if(head.element == data){
            head = head.next;
            return true;
        }
        //删除某一个正常节点
        Node<E> tmp = head;
        while(tmp.next != null){
            if(tmp.next.element == data){
                tmp.next = tmp.next.next;
                return true;
            }
            tmp = tmp.next;
        }
        return false;
    }

    //返回指定位置的节点
    public Node<E> findValue(int index){
        if(index < 0)  return null;
        Node<E> tmp = head;

        while(tmp.next != null && index-- > 0){
            tmp = tmp.next;
        }
        if(index <= 0) {
            return tmp;
        }
        return null;
    }

    //得到当前链表的长度
    public int getLength(){
        int size = 0;
        Node<E> tmp = head;

        while(tmp.next != null){
            size++;
            tmp = tmp.next;
        }
        return size;
    }

    //遍历链表
    public String toString(){
        StringBuilder sb = new StringBuilder();
        Node<E> tmp = head;
        while(tmp.next != null){
            sb.append(tmp.next.element+" ");
            tmp = tmp.next;
        }

        return sb.toString();
    }
}
public class GY20191007 {
    public static void main(String[] args) {
        SingleLinkedListTakedHead<Integer> linkedListTakedHead = new SingleLinkedListTakedHead<>();
        linkedListTakedHead.addTail(1);
        linkedListTakedHead.addTail(2);
        linkedListTakedHead.addTail(3);
        linkedListTakedHead.addTail(4);
        linkedListTakedHead.addTail(5);

        System.out.println(linkedListTakedHead.delete(5));
        System.out.println(linkedListTakedHead.delete(2));
        System.out.println(linkedListTakedHead.delete(10));
        System.out.println(linkedListTakedHead.findValue(5));
        System.out.println(linkedListTakedHead.findValue(4));
        System.out.println(linkedListTakedHead.findValue(1));
        System.out.println(linkedListTakedHead.findValue(3));
        System.out.println(linkedListTakedHead.getLength());
        System.out.println(linkedListTakedHead.toString());
    }
}

不带头结点的单链表:

class SingleLinkedList<E>{
    protected Node<E> head; //永远指向第一个有效节点

    //节点类
    class Node<E>{
        protected E element; //数据域
        protected Node<E> next;//引用域,用来连接链表中的节点

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

逆序输出链表,用两种方法,栈或者递归
用栈的代码段:

//逆序输出链表,用栈
    public void reverse(){
       Stack<Node> stack = new Stack<>();
           Node node = head.next;
        while(node != null){
            stack.push(node);
            node = node.next;
        }
        while (stack.size() > 0) {
            node = stack.pop();
            System.out.print(node.element + " ");
        }
    }

用递归的代码段:

//逆序输出单链表,用递归
    public static <E> void reversePrintList(SingleLinkedList<E>.Node<E> head){
        //递归终止条件
        if(head == null){
            return;//处理办法
        }
        //提取重复逻辑,缩小问题规模
        reversePrintList(head.next);
        System.out.println(head.element + " ");
    }

单链表的逆置代码段:
在这里插入图片描述

//逆置单链表
    public static <E> SingleLinkedList<E>.Node<E> reverseList(SingleLinkedList<E>.Node<E> head){
        SingleLinkedList<E>.Node<E> current = head; //当前节点
        SingleLinkedList<E>.Node<E> prev = null;//当前节点的前一个
        SingleLinkedList<E>.Node<E> newHead = null;//逆置后链表的头节点

        while(current != null){
            //当前节点的下一个
            SingleLinkedList<E>.Node<E> next = current.next;
            if(next == null){
                newHead = current;
            }
            current.next = prev;
            prev = current;
            current = next;
        }

完整代码:

class SingleLinkedList<E>{
    protected Node<E> head; //永远指向第一个有效节点

    //节点类
    class Node<E>{
        protected E element; //数据域
        protected Node<E> next;//引用域,用来连接链表中的节点

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

    //添加
    public void add(E data){
        //创建一个新的节点
        Node<E> newNode = new Node<>(data);
        //分情况:空链表 head == null
        if(head == null){
            head = newNode;
        }else{
            //链表不为空,遍历至尾节点
            Node<E> tmp = head;
            while(tmp.next != null){
                tmp = tmp.next;
            }
            //绑定新节点
            tmp.next = newNode;
        }
    }

    //添加一个新节点至指定位置
    public boolean addPos(E data, int pos){
        if(pos < 0 || pos > getLength()+1){
            return false;
        }
        //创建新节点
        Node<E> newNode = new Node<>(data);
        //插入0号位置需要特殊处理
        if(pos == 0){
            newNode.next = head;
            head = newNode;
            return true;
        }
        //找到pos位置
        Node<E> tmp = head;
        for(int i=0; i<pos-1; i++){
            tmp = tmp.next;
        }
        //tmp指向pos-1位置的节点
        //绑定新节点
        newNode.next = tmp.next;
        tmp.next = newNode;
        return true;
    }

    public boolean delete(E data){
        //head节点需要单独处理
        if(head.element == data){
            head = head.next;
            return true;
        }
        //删除某一个正常节点
        Node<E> tmp = head;
        while(tmp.next != null){
            if(tmp.next.element == data){
                tmp.next = tmp.next.next;
                return true;
            }
            tmp = tmp.next;
        }
        return false;
    }

    public int getLength(){
        int length = 0;
        Node<E> tmp = head;
        while(tmp != null){
            length ++ ;
            tmp = tmp.next;
        }
        return length;
    }

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

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

    public void show(){
        Node<E> tmp = head;
        while(tmp != null){
            System.out.print(tmp.element + " ");
            tmp = tmp.next;
        }
        System.out.println();
    }
}

//循环单链表
class LoopSingleLinkedList<E>{
    protected Node<E> head;

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

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

    public LoopSingleLinkedList(){
        head = new Node((E)new Object());
        head.next = head;
    }



}

public class GY{

//逆序输出链表,用栈
    public void reverse(){
       Stack<Node> stack = new Stack<>();
           Node node = head.next;
        while(node != null){
            stack.push(node);
            node = node.next;
        }
        while (stack.size() > 0) {
            node = stack.pop();
            System.out.print(node.element + " ");
        }
    }

    //逆序输出单链表,用递归
    public static <E> void reversePrintList(SingleLinkedList<E>.Node<E> head){
        //递归终止条件
        if(head == null){
            return;//处理办法
        }
        //提取重复逻辑,缩小问题规模
        reversePrintList(head.next);
        System.out.println(head.element + " ");
    }

    //逆置单链表
    public static <E> SingleLinkedList<E>.Node<E> reverseList(SingleLinkedList<E>.Node<E> head){
        SingleLinkedList<E>.Node<E> current = head; //当前节点
        SingleLinkedList<E>.Node<E> prev = null;//当前节点的前一个
        SingleLinkedList<E>.Node<E> newHead = null;//逆置后链表的头节点

        while(current != null){
            //当前节点的下一个
            SingleLinkedList<E>.Node<E> next = current.next;
            if(next == null){
                newHead = current;
            }
            current.next = prev;
            prev = current;
            current = next;
        }
        return newHead;
    }

    public static void main(String[] args) {
        SingleLinkedList<Integer> list = new SingleLinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
//        list.addPos(10, 2);
//        list.addPos(20, 0);
//        list.show();
        SingleLinkedList<Integer>.Node<Integer> newHead = reverseList(list.getHead());
        list.setHead(newHead);
        System.out.println("逆置后的链表为:");
        list.show();
    }
}

合并两个有序的单链表,保证合并之后依然有序
在这里插入图片描述

public static <E extends Comparable<E>> SingleLinkedList<E>.Node<E> mergeLinkedList(
            SingleLinkedList<E>.Node<E> head1, SingleLinkedList<E>.Node<E> head2){

        //确定新链表的头节点
        SingleLinkedList<E>.Node<E> curHead = null;
        if(head1.element.compareTo(head2.element) < 0) {
            curHead = head1;
            head1 = head1.next;
        }else{
            curHead = head2;
            head2 = head2.next;
        }
        SingleLinkedList<E>.Node<E> 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;
    }
    public static void main(String[] args) {
    //合并两个有序链表
        SingleLinkedList<Integer> list1 = new SingleLinkedList<>();
        SingleLinkedList<Integer> list2 = new SingleLinkedList<>();

        list1.add(1);list1.add(3);list1.add(5);list1.add(7);list1.add(9);

        list2.add(2);list2.add(4);list2.add(6);list2.add(8);

        list1.show();
        list2.show();

        SingleLinkedList<Integer>.Node<Integer> curHead = mergeLinkedList(list1.getHead(), list2.getHead());
        SingleLinkedList<Integer>.Node<Integer> tmp = curHead;
        while(tmp != null){
            System.out.print(tmp.element + " ");
            tmp = tmp.next;
        }
        System.out.println();
    }

查找单链表中倒数第K个元素
在这里插入图片描述

//查找单链表中倒数第K个元素
    public static <E> SingleLinkedList<E>.Node<E> lastK(
            SingleLinkedList<E>.Node<E> head, int k){
        if(head == null || k<0)  return null;
        //控制时间复杂度为O(n),只需要遍历链表一次实现
        SingleLinkedList<E>.Node<E> front = head;
        SingleLinkedList<E>.Node<E> behind = head;

        for(int i=0; i<k-1; i++){
            if(front.next != null){
                front = front.next;
            }else{
                return null;
            }
        }

        while(front.next != null){
            front = front.next;
            behind = behind.next;
        }
        return behind;
    }
     public static void main(String[] args) {
     //倒数第k个节点
        SingleLinkedList<Integer> list = new SingleLinkedList<>();
        list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);list.add(6);list.add(7);
        SingleLinkedList<Integer>.Node<Integer> kNode = lastK(list.getHead(), 7);
        if(kNode != null){
            System.out.println(kNode.element);
        }else{
            System.out.println(kNode);
        }
    }

不允许遍历链表, 在 pos之前插入

//不允许遍历链表, 在 pos之前插入
    public static <E> boolean insertPosBefore(
            SingleLinkedList<E> list,SingleLinkedList<E>.Node<E> pos, E data){
        if(list.getHead() == null || pos == null) return false;

        //创建新节点
        SingleLinkedList<E>.Node<E> newNode = list.createNode(pos.element);

        //插入新节点至pos之后
        newNode.next = pos.next;
        pos.next = newNode;

        //改变pos位置的element为data
        pos.element = data;
        return true;
    }

两个链表相交,输出相交节点

//两个链表相交,输出相交节点
    public static <E> SingleLinkedList<E>.Node<E> commonNode(
            SingleLinkedList<E> list1, SingleLinkedList<E> list2){
        if(list1.getHead() == null || list2.getHead() == null) return null;

        //计算两个链表的差值
        int length1 = list1.getLength();
        int length2 = list2.getLength();
        int lengthDif = Math.abs(length1-length2);

        SingleLinkedList<E>.Node<E> longHead = list1.getHead();
        SingleLinkedList<E>.Node<E> shortHead = list2.getHead();

        if(length1 < length2){
            longHead = list2.getHead();;
            shortHead = list1.getHead();
        }

        //长链表先走
        for(int i=0; i<lengthDif; i++){
            longHead = longHead.next;
        }

        //两个指针同时走
        while(longHead != shortHead){
            longHead = longHead.next;
            shortHead = shortHead.next;
        }
        return longHead;
        }
        public static void main(String[] args) {
        //构造两个相交的链表
        SingleLinkedList<Integer> list1 = new SingleLinkedList<>();
        list1.add(1);list1.add(3);list1.add(5); list1.add(7); list1.add(9);

        SingleLinkedList<Integer> list2 = new SingleLinkedList<>();
        list2.add(0);list2.add(2);list2.add(4);list2.add(6);

        list1.show();
        list2.show();
      }
      SingleLinkedList<Integer>.Node<Integer> head1= list1.getHead();
        while(head1.element != 7){
            head1 = head1.next;
        }

        SingleLinkedList<Integer>.Node<Integer> head2 = list2.getHead();
        while(head2.next != null){
            head2 = head2.next;
        }
        head2.next = head1;
        list1.show();
        list2.show();
        }
        SingleLinkedList<Integer>.Node<Integer> common = commonNode(list1, list2);
        if(common != null){
            System.out.println(common.element);
        }else{
            System.out.println(common);
        }

单链表是否有环,环的入口节点是哪个
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class ClassParacticeTest {

    //单链表是否有环,环的入口节点是哪个
    public static <E> SingleLinkedList<E>.Node<E> ringNode(
            SingleLinkedList<E>.Node<E> head){
        //判断是否存在环,如果存在,则已知环中任意节点
        SingleLinkedList<E>.Node<E> meeetingNode = isRing(head);
        //说明环不存在
        if(meeetingNode == null){
            return null;
        }

        //计算环中节点的个数 length

        while (front.next != front ) {
            length++;
            front = front.next;
        }

        //类比求倒数第k个节点的算法
        front = head;
        SingleLinkedList1<E>.Node<E> behind = head;

        for(int i=0; i<length; i++){
            front = front.next;
        }
        while(front.next != behind){
            front = front.next;
            behind = behind.next;
        }
        return behind;
    }
}

双向链表:
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值