当前位置: 首页 > 后端技术 > Java

cs61bweek2--DLList

时间:2023-04-01 21:15:12 Java

1.提出了双链表问题。本节不讲太多知识,主要围绕优化。想象一下,对于单链表的addLast()方法publicvoidaddLast(intx){size+=1;IntNodep=哨兵;while(p.next!=null){p=p.next;}p.next=newIntNode(x,null);}可以看出,每增加一个新的结束节点之前,我们都要遍历到当前结束节点。时间复杂度为O(n)。有没有办法实现O(1)?优化1添加一个变量last,它始终指向最后一个节点,类似于C语言中的尾指针publicclassSLList{privateIntNodelast;publicvoidaddLast(intx){last.next=newIntNode(x,null);最后一个=最后一个。下一个;尺寸+=1;}...}这样做之后,添加最后一个节点addLast()和找到最后一个节点getLast()的值的时间复杂度可以优化为O(1),但是对于removeLast(),即为删除尾节点,复杂度还是O(n),因为当我要删除尾节点时,需要找到倒数第二个节点,将其next赋值给NULL,这还是需要从头遍历整个链表.优化2.考虑给每个节点增加一个prev指针字段,指向它的前一个节点。这样,对于一个节点,它不仅可以访问它的上一个节点,还可以访问下一个节点,即双链表publicclassIntNode{publicIntNodeprev;公共整数项;publicIntNodenext;}经过优化,当我们需要删除最后一个节点时,只需要last.prev.next=null删除最后一个节点即可,时间复杂度降低为O(1)。随之而来的问题是,当一个链表中的所有节点都被删除,只剩下sentinel节点时,sentinel和last一起指向sentinel节点。也就是说last有时会指向一个普通的节点,删除的时候只哨兵节点指向哨兵节点,所以我们可能需要加入很多特殊的判断条件,优化起来比较麻烦。3那么我们可以考虑增加两个哨兵节点,一个在头部,一个在尾部。众所周知,sentinel节点数据字段我们不关心(图中??),sentinel节点就是标记节点的作用另一种方法是循环双链表,共享同一个sentinel节点,如图图中Summary2.Generic我们的IntNode代码定义是publicclassIntNode{publicIntNodeprev;公共整数项;接下来是公共IntNode;这意味着如果我们尝试使用字符串DLListd2=newDLList("hello");d2.addLast("world");我们只能将整数添加到链表节点的数据字段中。那么显然编译器会报错。一个直接的方法就是把所有的int都改成String,但是如果我想生成Double类型的节点怎么办?重新改一遍岂不是很麻烦,所以Java提供了一种叫做泛型的语法,我们只需要在类名(类名)后面加上即可,当我们要使用任何类型的变量时,往往就可以了只是在里面传递参数,命名为ElemType只是为了方便理解,你可以自定义任何名称DLList可以容纳任何类型的泛型如下:私有整数大小;公共类stuffNode{publicstuffNodeprev;公共ElemType项目;publicstuffNode接下来;...}...}我们已经定义了DLList类的通用类型。我们在main()函数中使用的时候,传入我们想要实现的类型即可。我们在声明时将所需的类型括在尖括号中,并在实例化时使用<>。例如:字符串类型DLListd2=newDLList<>("hello");d2.addLast("世界");整数类型DLListd1=newDLList<>(5);d1.addFirst(10);注意,在实例化泛型类型时,传入的参数必须是类型的大写字母,即Integer、Double、Character、Boolean、Long、Short、Byte、Float,而不是intchar