?????? 今天我想跟大家来唠叨一下双向链表,何为双向链表?简而言之,每个结点存储两个链,并允许双向遍历的链表称为双向链表。我对于链表的理解是这样的,一个结点类,一个位置类,一个链表本身类。
一、结点类
public class DoubleLinkNode { public String iData; //前一个结点 public DoubleLinkNode prev; //后一个结点 public DoubleLinkNode next; public DoubleLinkNode(String iData){ this(iData,null,null); } public DoubleLinkNode(String iData, DoubleLinkNode dln, DoubleLinkNode dln2) { this.iData=iData; this.prev=dln; this.next=dln2; } }
?这个类比较简单,没什么好说,对于第二个构造器,主要是为了使后面结点之间的连接更简洁。你也可以不用这个构造器。
二、位置类(迭代器类)
public class DbLinkListIterator { //标识当前的位置 DoubleLinkNode current; DbLinkListIterator(DoubleLinkNode dln) { current=dln; } //判断当前位置是否有效 public boolean isValid(){ return current!=null; } //向前行进 public void advace(){ if (isValid()) { current=current.next; } } //向后倒退 public void back(){ if (isValid()) { current=current.prev; } } //返回当前位置的标识符 public String retrieve(){ if (isValid()) { return current.iData; } return null; } }
?这个类主要用来反馈链表当前的位置,如果你不想单独建这个类,你可以把它放在链表本身类的内部。但是本人觉得把它单独抽象出来成一个类,结构会更加的清晰。
三、链表本身类
public class LinkList_Double { //头结点 private DoubleLinkNode header; //尾结点 private DoubleLinkNode tail; //初始化头尾结点 public LinkList_Double() { header=new DoubleLinkNode("header"); tail=new DoubleLinkNode("tail",header,null); header.next=tail; } //判断双向链表是否为空 public boolean isEmpty(){ return header.next==tail||tail.prev==header; } //第一个结点之前的位置 public DbLinkListIterator zero(){ return new DbLinkListIterator(header); } //第一个结点的位置 public DbLinkListIterator first(){ if (!isEmpty()) { return new DbLinkListIterator(header.next); } return new DbLinkListIterator(header); } //最后一个结点的位置 public DbLinkListIterator last(){ if (!isEmpty()) { return new DbLinkListIterator(tail.prev); } return new DbLinkListIterator(tail); } //指定位置之后插入方法 public void insertAfter(String obj,DbLinkListIterator pos){ if (pos!=null&&pos.current!=null) { DoubleLinkNode newDoubleLinkNode=new DoubleLinkNode(obj,pos.current,pos.current.next); newDoubleLinkNode.prev.next=newDoubleLinkNode; newDoubleLinkNode.next.prev=newDoubleLinkNode; } } //指定位置之前插入方法 public void insertBefore(String obj,DbLinkListIterator pos){ if (pos.current!=header&&pos!=null&&pos.current!=null) { DoubleLinkNode newDoubleLinkNode=new DoubleLinkNode(obj,pos.current.prev,pos.current); newDoubleLinkNode.prev.next=newDoubleLinkNode; newDoubleLinkNode.next.prev=newDoubleLinkNode; } } //查找方法 public DbLinkListIterator find(String key){ DoubleLinkNode itr=header.next; while (itr!=null) { if (itr.iData.equals(key)) { return new DbLinkListIterator(itr); } itr=itr.next; } return null; } //删除方法 public void delete(String key){ DbLinkListIterator itr=find(key); if (itr==null) { System.out.println("不存在该关键字"); return; } itr.current.prev.next=itr.current.next; itr.current.next.prev=itr.current.prev; } //向前显示 public void displayBofore(){ if (isEmpty()) { System.out.println("该双向链表为空"); }else { DbLinkListIterator itr=first(); while (itr!=null&&!itr.retrieve().equals("tail")) { System.out.print(itr.retrieve()+" "); itr.advace(); } } } //向后显示 public void displayAfter(){ if (isEmpty()) { System.out.println("该双向链表为空"); }else { DbLinkListIterator itr=last(); while (itr!=null&&!itr.retrieve().equals("header")) { System.out.print(itr.retrieve()+" "); itr.back(); } } } }
为了方便,作者的想法是虚构两个结点,即头结点、尾结点,这样做的好处就是能够保证每次插入有效结点时,它的前后都有结点,这样就少了许多的条件判断。当然双向链表本身的方法肯定不止这么一点,我只是大概的列举了一些。
四、测试类
public class LinkList_doubleTest { public static void main(String[] args) { LinkList_Double linkList_Double=new LinkList_Double(); //插入第一个结点 linkList_Double.insertAfter("a", linkList_Double.zero()); //在指定结点之后插入 linkList_Double.insertAfter("b", linkList_Double.find("a")); linkList_Double.insertAfter("c", linkList_Double.find("b")); //在指定结点之前插入 linkList_Double.insertBefore("e", linkList_Double.find("b")); linkList_Double.insertBefore("f", linkList_Double.first()); //删除指定结点 linkList_Double.delete("f"); //顺序显示 linkList_Double.displayBofore(); //逆序显示 linkList_Double.displayAfter(); } }
?最后,作者也是正在学习的过程中,自然还有很多?考虑不周全的地方,如有,还请见谅,并希望您能指出我的不足之处,大家一起学习、进步。
原文:http://19900524.iteye.com/blog/2252478