双端链表:双端链表与传统链表非常相似.只是新增了一个属性-即对最后一个链结点的引用
如上图所示:由于有着对最后一个链结点的直接引用.所以双端链表比传统链表在某些方面要方便.比如在尾部插入一个链结点.双端链表可以进行直接操作
但传统链表只能通过next节点循环找到最后链结点操作.所以双端链表适合制造队列.
下面的双端链表类.有几个重要方法.
insertFirst(插入首链结点)
这个方法与上篇博文的单链表是基本一样的.唯一区别就是,多了个last引用的操作.正常由于last是指向尾链结点的引用,所以插入首链结点是与他无关的.
但当链结点为空(isEmpty())的时候,这会追加的链结点既是首链结点又是尾链结.所以需要将last指向它.
插入尾部链结点也是与普通的理解基本一致,所以不多赘述.唯一也要注意的是链结点为空(isEmpty())的时候.需要将first指向该链结点.
deleteFirst(删除首部链结点)
这个需要注意的就是,如果仅剩下一个链结点.那么删除后last就应该指向null了.
这里顺便谈下链表和数组相比效率的优越性.在表头插入和删除的速度都很快,因为只需要改变一下引用所以花费O(1)的时间.
平均起来查找,删除和在指定节点后插入数据都需要搜索一半的链结点.需要O(N)次比较和数组一样.然由于链表删除插入的时候
不需要像数组那种元素的移动.所以效率还是要优于数组.
还有一点就是链表的内存可以随时的扩展内存.而数组的内存是一开始就固定好的.这样就会导致数组的效率和可用性大大下降.
如上图所示:由于有着对最后一个链结点的直接引用.所以双端链表比传统链表在某些方面要方便.比如在尾部插入一个链结点.双端链表可以进行直接操作
但传统链表只能通过next节点循环找到最后链结点操作.所以双端链表适合制造队列.
下面的双端链表类.有几个重要方法.
insertFirst(插入首链结点)
这个方法与上篇博文的单链表是基本一样的.唯一区别就是,多了个last引用的操作.正常由于last是指向尾链结点的引用,所以插入首链结点是与他无关的.
但当链结点为空(isEmpty())的时候,这会追加的链结点既是首链结点又是尾链结.所以需要将last指向它.
public
void
insertFirst(
double
dd) {
Link newLink = new Link(dd);
if (isEmpty()){
last = newLink;
}
newLink.next = first;
first = newLink;
}
insertLast(插入尾链结点)
Link newLink = new Link(dd);
if (isEmpty()){
last = newLink;
}
newLink.next = first;
first = newLink;
}
插入尾部链结点也是与普通的理解基本一致,所以不多赘述.唯一也要注意的是链结点为空(isEmpty())的时候.需要将first指向该链结点.
public
void
insertLast(
double
dd) {
Link newLink = new Link(dd);
if (isEmpty()) {
first = newLink;
} else {
last.next = newLink;
}
last = newLink;
}
看下插入尾部链结点的引用指向:
Link newLink = new Link(dd);
if (isEmpty()) {
first = newLink;
} else {
last.next = newLink;
}
last = newLink;
}
deleteFirst(删除首部链结点)
这个需要注意的就是,如果仅剩下一个链结点.那么删除后last就应该指向null了.
public
void
deleteFirst() {
first = first.next;
if (first.next == null ) {
last = null ;
}
}
最后这个代码如下:
first = first.next;
if (first.next == null ) {
last = null ;
}
}
FirstLastLink
package com.dbstructor.oop3;
// 链结点类
class Link {
public double dData;
public Link next;
public Link(double dd) {
dData = dd;
}
public void displayLink() {
System.out.print(dData + " ");
}
}
// 双端链表类
class FirstLastList {
public Link first;
public Link last;
public FirstLastList() {
first = null;
last = null;
}
public boolean isEmpty(){
return (first == null);
}
// 表头插入
public void insertFirst(double dd) {
Link newLink = new Link(dd);
if(isEmpty()){
last = newLink;
}
newLink.next = first;
first = newLink;
}
// 表尾插入
public void insertLast(double dd) {
Link newLink = new Link(dd);
if(isEmpty()) {
first = newLink;
}else {
last.next = newLink;
}
last = newLink;
}
// 删除表头
public void deleteFirst() {
first = first.next;
if(first.next == null) {
last = null;
}
}
public void displayList() {
System.out.print("List (first--->last)");
Link current = first;
while(current != null){
current.displayLink();
current = current.next;
}
System.out.println();
}
}
public class FirstLastApp {
public static void main(String[] args) {
FirstLastList theList = new FirstLastList();
// 插入链表头数据
theList.insertFirst(22);
theList.insertFirst(44);
theList.insertFirst(66);
// 插入链表尾数据
theList.insertLast(11);
theList.insertLast(33);
theList.insertLast(55);
theList.displayList();
// 删除表头数据
theList.deleteFirst();
theList.deleteFirst();
theList.displayList();
}
}
代码运行结果为:
package com.dbstructor.oop3;
// 链结点类
class Link {
public double dData;
public Link next;
public Link(double dd) {
dData = dd;
}
public void displayLink() {
System.out.print(dData + " ");
}
}
// 双端链表类
class FirstLastList {
public Link first;
public Link last;
public FirstLastList() {
first = null;
last = null;
}
public boolean isEmpty(){
return (first == null);
}
// 表头插入
public void insertFirst(double dd) {
Link newLink = new Link(dd);
if(isEmpty()){
last = newLink;
}
newLink.next = first;
first = newLink;
}
// 表尾插入
public void insertLast(double dd) {
Link newLink = new Link(dd);
if(isEmpty()) {
first = newLink;
}else {
last.next = newLink;
}
last = newLink;
}
// 删除表头
public void deleteFirst() {
first = first.next;
if(first.next == null) {
last = null;
}
}
public void displayList() {
System.out.print("List (first--->last)");
Link current = first;
while(current != null){
current.displayLink();
current = current.next;
}
System.out.println();
}
}
public class FirstLastApp {
public static void main(String[] args) {
FirstLastList theList = new FirstLastList();
// 插入链表头数据
theList.insertFirst(22);
theList.insertFirst(44);
theList.insertFirst(66);
// 插入链表尾数据
theList.insertLast(11);
theList.insertLast(33);
theList.insertLast(55);
theList.displayList();
// 删除表头数据
theList.deleteFirst();
theList.deleteFirst();
theList.displayList();
}
}
List (first--->last)
66
.
0
44
.
0
22
.
0
11
.
0
33
.
0
55
.
0
List (first--->last) 22 . 0 11 . 0 33 . 0 55 . 0
链表的效率
List (first--->last) 22 . 0 11 . 0 33 . 0 55 . 0
这里顺便谈下链表和数组相比效率的优越性.在表头插入和删除的速度都很快,因为只需要改变一下引用所以花费O(1)的时间.
平均起来查找,删除和在指定节点后插入数据都需要搜索一半的链结点.需要O(N)次比较和数组一样.然由于链表删除插入的时候
不需要像数组那种元素的移动.所以效率还是要优于数组.
还有一点就是链表的内存可以随时的扩展内存.而数组的内存是一开始就固定好的.这样就会导致数组的效率和可用性大大下降.