java数据结构:链表

链表的概念:

链式结构 在逻辑上连续 在物理上不一定连续
现实中节点都是从堆上申请出来的
从堆上申请的空间,按照一定策略分配,两次申请的空间可能连续,也可能不连续。

结构:

单向 双向
在这里插入图片描述

带头节点 (head不会变,而我们后面用的那不叫带头结点,叫head头指针)不带头节点
在这里插入图片描述

循环 不循环
在这里插入图片描述

无头单向非循环链表的实现

MySingleLinkedList

public class MySingleLinkedList {//链表

    //首先创建一个静态内部类来描述节点
    static class ListNode {//静态内部类,List是由ListNode组成的,它有哪些属性
        public int val;//节点的值域
        public ListNode next;//next域,因为他是引用类型,存放的是下一个节点的地址

        public ListNode(int val) {
            this.val = val;
            //value域构造方法可以放一个初始值,而next域没有构造就是null,因为一开始也不知道我的下一个节点是谁。
        }
    }

    public ListNode head;//节点引用类型 表示当前链表的头节点  链表的成员属性,不是节点的属性
    public int usedSize;//记录链表里的节点个数

    public void createList() {//创建链表
        ListNode node1 = new ListNode(12);//创建节点
        ListNode node2 = new ListNode(23);
        ListNode node3 = new ListNode(34);
        ListNode node4 = new ListNode(45);
        ListNode node5 = new ListNode(56);

        node1.next = node2;//node1的next域存放的是node2的地址,相当于将node1和node2连接起来了。
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        this.head = node1;//注意:得写成head=node1,不能写成node1=head
    }


    public void display(){
        ListNode cur = head;
        while (cur != null) {//cur == null表示把链表遍历完了
            System.out.print(cur.val + " ");
//            head = head.next;不用head,不然到时候找不到头节点去哪儿了
            cur = cur.next;//每次向后走一步
        }

    }

    public int size(){//得到链表的长度
        ListNode cur = head;
        int count = 0;
        while (cur != null){
            count++;
            cur = cur.next;
        }
        return count;
    }

    public boolean contains(int key){//查找是否包含key
        ListNode cur = head;
        while (cur != null) {//cur 而不是cur.next
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    public void addFirst(int data) {
        //头插法:这里不需要考虑链表是否为空
        ListNode node = new ListNode(data);
        node.next = head;//这两行代码不可交换
        head = node;
    }

    //cur == null表示遍历完了每一个节点
    //cur.next == null 表示cur是最后一个节点的位置
    public void addEnd(int data) {
        ListNode node = new ListNode(data);
        ListNode cur = head;
        if(cur == null) {//得判断,不然cur没有next,报空指针异常,空链表
            head = node;
            return;//要有这句,不然还会往后执行
        }
        while (cur.next != null) {//尾巴节点的next域不为空
            cur = cur.next;
        }
        cur.next = node;
    }

    public void addIndex(int index, int data){
        if(index < 0 || index > size()) {
            System.out.println("index不合法");//可以抛出一个自定义异常
            return;
        }
        if(index == 0) {
            addFirst(data);//头插
            return;
        }
        if(index == size()) {
            addEnd(data);//尾插
            return;
        }
        ListNode node = new ListNode(data);
        ListNode cur = findIndexSubOne(index);//找到要插入位置的前一个节点
        node.next = cur.next;
        cur.next = node;
    }

    private ListNode findIndexSubOne(int index) {//封装
        ListNode cur = head;
        while (index-1 != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }


    private ListNode searchPrev(int key) {//找到你要删除节点的前一个节点
        ListNode cur = head;
        while(cur.next != null) {//不会到最后一个节点,最多到最后一个节点的前一个节点
            if(cur.next.val == key) {
                return cur;
            }
            cur = cur.next;
        }
        return null;//一个都没找到
    }

    //删除第一个出现关键字为key的节点
    public void remove(int key){//1.找到你要删除节点的前一个节点
        if(head == null) {//空链表   //得考虑
            return;
        }
        if(head.val == key) {     //得考虑
            //单独删除头节点
            head = head.next;
        }
        ListNode cur = searchPrev(key);
        if(cur == null) {
            System.out.println("没找到你要删除的数字");
            return;
        }
        ListNode del = cur.next;
        cur.next = del.next;
    }

    public void removeAllKey(int key) {
        if(head == null) {
            return;
        }
        ListNode cur = head.next;
        ListNode prev = head;
        while(cur != null) {
            if(cur.val == key){
                prev.next = cur.next;
                cur = cur.next;
            }else {
                prev = cur;
                cur = cur.next;
            }
        }
        if(head.val == key) {//如果头节点为key
            head = head.next;//不能放在一开始,因为有可能前面几个都是key,放前面必须用循环。
        }
    }

    public void clear(){
        this.head = null;
    }
}

Test类

 public static void main(String[] args) {
        MySingleLinkedList mySingleLinkedList = new MySingleLinkedList();//实例化一个对象,
        mySingleLinkedList.createList();

        mySingleLinkedList.display();

        System.out.println(mySingleLinkedList.size());

        mySingleLinkedList.createList();
        System.out.println(mySingleLinkedList.contains(23));
        System.out.println(mySingleLinkedList.contains(99));

        mySingleLinkedList.addFirst(12);
        mySingleLinkedList.addFirst(9);
        mySingleLinkedList.addFirst(8);
        mySingleLinkedList.display();

        mySingleLinkedList.addEnd(19);
        mySingleLinkedList.addEnd(20);
        mySingleLinkedList.display();

        mySingleLinkedList.createList();
        mySingleLinkedList.addIndex(0,100);
        mySingleLinkedList.addIndex(5,200);
        mySingleLinkedList.addIndex(2,300);
        mySingleLinkedList.display();

        mySingleLinkedList.createList();
        mySingleLinkedList.remove(23);
        mySingleLinkedList.remove(34);
        mySingleLinkedList.display();
    }

LinkedList的模拟实现( 无头双向链表)

MyLinkedList

public class MyLinkedList {

    static class ListNode{//静态内部类
        private int val;
        private ListNode prev;
        private ListNode next;
        public ListNode(int val){
            this.val = val;
        }
    }

    public ListNode head;//双向链表的头节点
    public ListNode last;//双向链表的尾巴节点

    public int size(){//得到链表长度
        ListNode cur = head;
        int count = 0;
        while(cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

    public void display(){
        ListNode cur = head;
        while(cur != null) {
            System.out.println(cur.val + " ");
            cur = cur.next;
        }
    }

    public boolean contains(int key) {//查找链表中是否包含关键字key
        ListNode cur = head;
        while(cur != null) {
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    //头插法
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        if(head == null) {
            head = node;
            last = node;
        }else{
            node.next = head;
            head.prev = node;
            head = node;
        }
    }

    //尾插法
    public void addLast(int data){
        ListNode node = new ListNode(data);
        if(head == null) {
            head = node;
            last = node;
        }
        last.next = node;
        node.prev = last;
        last = last.next;
    }

    //固定位置插入
    public void addIndex(int pos, int data){
        checkIndex(pos);

        if(pos == 0) {
            addFirst(data);
            return;
        }

        if(pos == size()) {
            addLast(data);
            return;
        }

        ListNode node = new ListNode(data);
        ListNode cur = searchIndex(pos);

        node.next = cur;
        cur.prev.next = node;
        node.prev = cur.prev;
        cur.prev = node;
    }
    private void checkIndex(int index) {//判断位置的合法性
        if(index < 0 || index > size()) {
            throw new IndexOutOfException("index不合法!" + index);
        }
    }
    private ListNode searchIndex(int index){//找到index位置的节点
        ListNode cur = head;
        while(index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }

    //删除第一次出现关键字为key的节点
    public void remove(int key) {
        ListNode cur = head;
        while(cur != null){
            if(cur.val == key){
                if(cur == head) {//1.处理头节点
                    head = head.next;
                    if(head != null) {
                        删除之后呢,还剩一个节点
                        head.prev = null;
                    }else {
                        //删除之后没有节点了
                        last = null;
                    }
                }else {
                    //2.处理中间节点
                    if(cur.next != null) {
                        cur.prev.next = cur.next;
                        cur.next.prev = cur.prev;
                    }else {
                        //3.处理尾巴节点
                        cur.prev.next = cur.next;//将前一个节点的next置为null
                        last = last.prev;
                    }
                }
                return;//不写这个会造成空指针异常   删完这个之后就走人
            }else {//如果节点的值不是key,继续往下走
                cur = cur.next;
            }
        }
    }

    //删除所有值为key的节点
    public void removeAllKey(int key) {
        ListNode cur = head;
        while(cur != null){
            if(cur.val == key) {
                if (cur == head) {//1.处理头节点
                    head = head.next;
                    if (head != null) {
                        删除之后呢,还剩一个节点
                        head.prev = null;
                    } else {
                        //删除之后没有节点了
                        last = null;
                    }
                } else {
                    //2.处理中间节点
                    if (cur.next != null) {
                        cur.prev.next = cur.next;
                        cur.next.prev = cur.prev;
                    } else {
                        //3.处理尾巴节点
                        cur.prev.next = cur.next;//将前一个节点的next置为null
                        last = last.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }

    //清空链表
    public void clear(){
        ListNode cur = head;
        while (cur != null) {
            ListNode curNext = cur.next;
            cur.prev = null;
            cur.next = null;
            cur = curNext;
        }
        head = null;//这两个引用还在,得置空
        last = null;
    }
}

Test类

public static void main(String[] args) {
        MyLinkedList myLinkedList = new MyLinkedList();
        myLinkedList.addFirst(10);
        myLinkedList.addFirst(20);
        myLinkedList.addFirst(20);
        myLinkedList.addFirst(20);
        myLinkedList.addFirst(50);
        myLinkedList.addFirst(60);

        myLinkedList.addLast(90);
        myLinkedList.addLast(70);
        myLinkedList.addLast(80);

        myLinkedList.remove(10);
        myLinkedList.remove(80);
        myLinkedList.removeAllKey(20);

        myLinkedList.display();

//        myLinkedList.remove(10);
//        myLinkedList.remove(60);
//        myLinkedList.removeAllKey(20);


//        myLinkedList.clear();
//        myLinkedList.display();
    }

异常类

public class IndexOutOfException extends RuntimeException{
    public IndexOutOfException() {
    }
    public IndexOutOfException(String message) {
        super(message);
    }
}

LinkedList的使用

底层是双向链表,
适合任意位置插入和删除,时间复杂度为O(1)
未实现RandonAccess接口,不支持随机访问
在这里插入图片描述

public class Test{
    public static void main(String[] args) {
       LinkedList<Integer> list = new LinkedList<>();//构造一个空的LinkedList
       list.add(10);
       list.add(20);
       list.add(30);
       list.add(40);
       list.add(50);
//         System.out.println(list.size());//还有多少个有效元素
//         System.out.println(list);



//         list.add(20);//尾插
//         list.add(1,50);//指定位置插入
//        System.out.println(list);



//        list.remove(2);//删除2位置上的元素
//        list.remove();//删除第一个元素
//        list.removeFirst();//删除第一个元素
//        list.removeLast();//删除最后一个元素
//        System.out.println(list);


//        System.out.println(list.contains(30));//是否包含30?

//        System.out.println(list.indexOf(30));//从前往后数30的位置在哪里
//        System.out.println(list.lastIndexOf(30));//从后往前数30的位置在哪里


//        int ret = list.get(0);//获取0位置上的元素
//        System.out.println(ret);
//
//        list.set(0,100);//将0位置设置为100
//        int ret1 = list.get(0);
//        System.out.println(ret1);

//        List<Integer> list1 = list.subList(2,5);//左闭右开[2,5)
//        System.out.println(list1);

//        list.clear();
//        System.out.println(list.size());
        
        
        
//       List<Integer> list = new LinkedList<>();
        
//       List<String> list1 = new ArrayList<>();
//       list1.add("free solo");
//       list1.add("climb");
//
//       List<String> list2 = new LinkedList<>(list1);//用ArrayList构造LinkedList
    }
}

LinkedList的遍历

        //1.使用foreach遍历
        for (int e: list) {
            System.out.print(e + " ");
        }
        System.out.println();

        //2.使用迭代器遍历
        ListIterator<Integer> it = list.listIterator();
        while(it.hasNext()) {
            System.out.print(it.next() + " ");
        }
        System.out.println();
        
        //从后往前遍历
        ListIterator<Integer> it1 = list.listIterator(list.size());
        while (it.hasPrevious()){
            System.out.print(it.previous() + " ");
        }
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值