欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > 链表3(LinkedList)

链表3(LinkedList)

2025/2/26 11:28:04 来源:https://blog.csdn.net/CxK6666667/article/details/145845919  浏览:    关键词:链表3(LinkedList)

1、双向不带头链表的实现

1.1 节点成员和构造方法

        双向不带头链表相比于单向多了一个prev域,它能使链表获得前驱节点。

        如上图是双向不带头链表的一个节点,它可以直接找到前驱和后继节点。

        由上面的讲解可得到代码:(注意:节点的类为静态内部类

//静态内部类  
static class ListNode {private int val;//值域private ListNode prev;//前驱private ListNode next;//后继//构造方法public ListNode(int val) {this.val = val;}}

        相比于单向链表的头节点,在双向链表中,多了一个尾巴节点last,方便了尾插法。

1.2 size()、display()、contains()

求链表长度、打印链表、查找链表中是否包含该元素

        这三个方法与单链表相同都是通过头节点遍历链表,这里就不做过多赘述。

        代码如下:

 //得到双链表的长度public int size(){int length = 0;ListNode cur = head;while(cur != null){length++;cur = cur.next;}return length;}
 // 打印链表public void display(){ListNode cur = head;while(cur != null){System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}
    //查找是否包含关键字key是否在单链表当中public boolean contains(int key){ListNode cur = head;while(cur != null){if(cur.val == key){return true;}cur = cur.next;}return false;}

1.3 addFirst()

头插法

        相比于单链表的头插法,双链表的头插法又有什么不同呢?

        如图,要将33头插入当前双链表中,在单链表中,我们只需要绑定后面的元素 ,然后再把头节点给到node,而双链表则还需要改掉原来头节点的前驱。

        由此,有代码如下:

                    node.next = head;head.prev = node;head = node;

        此时,观察代码我们会想:如果我的链表中没有元素,那这里的不就发生空指针异常了吗?

        因此,我们需要判断,当head==null的时候,我们把链表的头节点和尾巴节点都给到node,代码如下:

 if(head == null){head = node;last = node;}

        完整代码:

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;}}

1.4 addLast ()

尾插法

                与头插法大同小异,只需要把原来的last的next改为node,再把当前节点的前驱改为last,再让last = node即可,如果链表中没有元素,就把头和尾巴都给到head。 

        完整代码:

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

1.5 addIndex()

在下标位置插入

   在单链表中,addIndex方法需要找到下标的前一个元素。而在双链表中则可以直接找到该下标的元素(因为我们可以通过前驱来找到前一个元素)。    

          如图所示,我们需要改动4处位置,这里一定要注意这4处的顺序:建议最先改node的prev和next,然后改cur.prev.next,前面的顺序可以改变,但是cur的prev一定是最后改的。 因为是任意位置插入,在0位置我们直接调用头插法函数;在size()位置直接调用尾插法函数;下标不合法,抛异常。

          完整代码: 

//任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data){ListNode listNode = new ListNode(data);if(index < 0 ||index > size()){throw new IndexErrorException(index+"下标错误,无法插入");}if(index == 0){addFirst(data);return;}if(index == size()){addLast(data);return;}int count = 0;ListNode cur = head;while(count != index){cur = cur.next;count++;}listNode.next = cur;listNode.prev = cur.prev;cur.prev.next = listNode;cur.prev = listNode;}

1.6 remove()

删除第一次出现值为key的节点 

    例如:要删除的key为34。

        因为有了前驱和后继,我们可以直接让cur遍历到值为key节点 ,然后让cur.next.prev = cur.prev; cur.prev.next = cur.next;

         细心的同学此时会发现问题:那我如果要删除的元素是头节点或尾节点,不发生空指针异常了吗?

        是的,所以我们需要写两个if语句进行判断来单独删除头节点和尾巴节点:删除头节点head = head.next; head.prev = null;此外,还应考虑链表只有一个节点的情况:只需将last置空即可。删除尾节点:cur.next.prev = null; last = last.prev;

        代码如下

1.7 removeAllKey()

删除所有值为key的节点

        删除所有值为key的元素,只需要把remove()代码中的return删去,让cur继续走下去即可。

        代码如下:

//删除所有值为key的节点public void removeAllKey(int key){ListNode cur = head;while(cur != null){if(cur.val == key){//删除头结点if(cur == head){head = head.next;if(head != null) {head.prev = null;}else{//只有一个节点的情况last = null;}}else {//删除中间和尾巴//删除尾巴if(cur.next == null){cur.prev.next = cur.next;last = last.prev;}else {//删除中间cur.prev.next = cur.next;cur.next.prev = cur.prev;}}}cur = cur.next;}}

 1.8 clear()

清空链表 

         清空链表的所有节点,有两种方法:

1、暴力清空(将head和last直接置空)

public void clear(){head = null;last = null;
}

 2、将所有节点的前驱和后继置空

   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;}

2、LinkedList和ArrayList的区别

        一、从存储方面:ArrayList在物理和逻辑上都是连续的;LinkedList在物理上不连续,但在逻辑上是连续的。

        二、增删查改和访问元素方面:

        ArrayList在插入的时候需要将被删元素后面的元素后移一个单位,时间复杂度为O(n),而LinkedList只需要直接把节点插进去,时间复杂度为O(1)。此外,ArrayList空间不够需要1.5倍扩容;而链表对容量没有概念,只需要新建一个节点插入即可。

        ArrayList可以通过下标随机访问元素,时间复杂度O(1);LinkedList则只能通过cur一个一个寻找,复杂度为O(n)。

        总结:访问元素次数多的使用顺序表,增删查改次数多则使用链表。

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词