3、链接表的实现:双向链表

 链接表ADT:

 1 package ren.laughing.datastructure.base;
 2
 3
 4 import ren.laughing.datastructure.exception.InvalidNodeException;
 5 import ren.laughing.datastructure.exception.OutOfBoundaryException;
 6 /**
 7  * 链接表ADT
 8  * 单链表和双链表用顺序存储结构并不友好
 9  * 链表方便插入,不方便查找
10  * SLNode和DLNode都实现了Node结点
11  * 因此采用Node结点作为参数、降低算法复杂度
12  * 链接表可以看作是一组结点序列以及基于结点进行操作的线性结构的抽象
13  * @author Laughing_Lz
14  * @time 2016年4月6日
15  */
16 public interface LinkedList {
17     //查询链接表当前的规模
18     public int getSize();
19     //判断列表是否为空
20     public boolean isEmpty();
21     //返回第一个结点
22     public Node first() throws OutOfBoundaryException;
23     //返回最后一结点
24     public Node last() throws OutOfBoundaryException;
25     //返回 p 之后的结点
26     public Node getNext(Node p) throws InvalidNodeException, OutOfBoundaryException;
27     //返回 p 之前的结点
28     public Node getPre(Node p) throws InvalidNodeException, OutOfBoundaryException;
29     //将 e 作为第一个元素插入链接表,并返回 e 所在结点
30     public Node insertFirst(Object e);
31     //将 e 作为最后一个元素插入列表,并返回 e 所在结点
32     public Node insertLast(Object e);
33     //将 e 插入至 p 之后的位置,并返回 e 所在结点
34     public Node insertAfter(Node p, Object e) throws InvalidNodeException;
35     //将 e 插入至 p 之前的位置,并返回 e 所在结点
36     public Node insertBefore(Node p, Object e) throws InvalidNodeException;
37     //删除给定位置处的元素,并返回之
38     public Object remove(Node p) throws InvalidNodeException;
39     //删除首元素,并返回之
40     public Object removeFirst() throws OutOfBoundaryException;
41     //删除末元素,并返回之
42     public Object removeLast() throws OutOfBoundaryException;
43     //将处于给定位置的元素替换为新元素,并返回被替换的元素
44     public Object replace(Node p, Object e) throws InvalidNodeException;
45     //元素迭代器
46     public Iterator elements();
47     }

双向链表:

  1 package ren.laughing.datastructure.baseImpl;
  2
  3 import ren.laughing.datastructure.base.Iterator;
  4 import ren.laughing.datastructure.base.LinkedList;
  5 import ren.laughing.datastructure.base.Node;
  6 import ren.laughing.datastructure.exception.InvalidNodeException;
  7 import ren.laughing.datastructure.exception.OutOfBoundaryException;
  8 /**
  9  * 链接表的实现:双向链表
 10  * @author Laughing_Lz
 11  * @time 2016年4月6日
 12  */
 13 public class DLinkList implements LinkedList{
 14     private DLNode head;//头结点
 15     private DLNode tail;//尾结点
 16     private int size;//规模
 17
 18     public DLinkList() {
 19         size=0;
 20         head = new DLNode();
 21         tail = new DLNode();
 22         head.setNext(tail);//初始化双链表时,首尾结点互指
 23         tail.setPre(head);
 24     }
 25     //辅助方法:检验结点p是否合法,如合法转换为DLNode
 26     public DLNode checkPosition(Node p) throws InvalidNodeException{
 27         if(p == null){
 28             throw new InvalidNodeException("错误:p为空");
 29         }else if(p==head){
 30             throw new InvalidNodeException("错误:p指向头结点,非法");
 31         }else if(p == tail){
 32             throw new InvalidNodeException("错误:p指向尾结点,非法");
 33         }else{
 34             DLNode node = (DLNode) p;
 35             return node;
 36         }
 37     }
 38
 39     @Override
 40     public int getSize() {
 41         return this.size;
 42     }
 43
 44     @Override
 45     public boolean isEmpty() {
 46         if(this.size==0){
 47             return true;
 48         }else{
 49             return false;
 50         }
 51     }
 52
 53     @Override
 54     public Node first() throws OutOfBoundaryException {
 55         if(size==0){
 56             throw new OutOfBoundaryException("链接表为空");
 57         }else{
 58             return head.getNext();//返回DLNode(已实现Node)
 59         }
 60     }
 61
 62     @Override
 63     public Node last() throws OutOfBoundaryException {
 64         if(size==0){
 65             throw new OutOfBoundaryException("链接表为空");
 66         }else{
 67             return tail.getPre();//返回DLNode(已实现Node)
 68         }
 69     }
 70
 71     @Override
 72     public Node getNext(Node p) throws InvalidNodeException, OutOfBoundaryException {
 73         DLNode node = this.checkPosition(p);
 74         node  = node.getNext();
 75         if(node == tail){
 76             throw new OutOfBoundaryException("错误:已经是链表尾端");
 77         }
 78         return node;
 79     }
 80
 81     @Override
 82     public Node getPre(Node p) throws InvalidNodeException, OutOfBoundaryException {
 83         DLNode node =this.checkPosition(p);
 84         node = node.getPre();
 85         if(node == head){
 86             throw new OutOfBoundaryException("错误:已经是链表首端");
 87         }
 88         return node;
 89     }
 90     //将 e 作为第一个元素插入链接表,并将含有该元素的结点返回
 91     @Override
 92     public Node insertFirst(Object e) {
 93         DLNode p = new DLNode(e, head, head.getNext());
 94         head.getNext().setPre(p);
 95         head.setNext(p);
 96         size++;
 97         return p;
 98     }
 99     //将 e 作为最后一个元素插入链接表,并将含有该元素的结点返回
100     @Override
101     public Node insertLast(Object e) {
102         DLNode p = new DLNode(e, tail.getPre(), tail);
103         tail.getPre().setNext(p);
104         tail.setPre(p);
105         size++;
106         return p;
107     }
108
109     @Override
110     public Node insertAfter(Node p, Object e) throws InvalidNodeException {
111         DLNode node = checkPosition(p);
112         DLNode newNode = new DLNode(e, node, node.getNext());
113         node.getNext().setPre(newNode);
114         node.setNext(newNode);
115         size++;
116         return newNode;
117     }
118
119     @Override
120     public Node insertBefore(Node p, Object e) throws InvalidNodeException {
121         DLNode node = checkPosition(p);
122         DLNode newNode = new DLNode(e, node.getPre(), node);
123         node.getPre().setNext(newNode);
124         node.setPre(newNode);
125         size++;
126         return newNode;
127     }
128
129     @Override
130     public Object remove(Node p) throws InvalidNodeException {
131         DLNode node = checkPosition(p);
132         node.getPre().setNext(node.getNext());
133         node.getNext().setPre(node.getPre());
134         size--;
135         return node.getData();
136     }
137
138     @Override
139     public Object removeFirst() throws OutOfBoundaryException {
140         return remove(head.getNext());
141     }
142
143     @Override
144     public Object removeLast() throws OutOfBoundaryException {
145         return remove(tail.getPre());
146     }
147
148     @Override
149     public Object replace(Node p, Object e) throws InvalidNodeException {
150         DLNode node = checkPosition(p);
151         Object obj = node.getData();
152         node.setData(e);
153         return obj;
154     }
155     //元素迭代器
156     @Override
157     public Iterator elements() {
158         Iterator it = new LinkListIterator(this);
159         return it;
160     }
161
162 }

涉及到使用迭代器遍历链表,代码如下:

 1 package ren.laughing.datastructure.base;
 2 /**
 3  * 迭代器,为了遍历链表中的数据元素
 4  * @author Laughing_Lz
 5  * @time 2016年4月6日
 6  */
 7 public interface Iterator {
 8     // 移动到第一个元素
 9     public void first();
10
11     // 移动到下一个元素
12     public void next();
13
14     // 检查迭代器中是否还有剩余的元素
15     public boolean isDone();
16
17     // 返回当前元素
18     public Object currentItem();
19 }
 1 package ren.laughing.datastructure.baseImpl;
 2
 3 import ren.laughing.datastructure.base.Iterator;
 4 import ren.laughing.datastructure.base.LinkedList;
 5 import ren.laughing.datastructure.base.Node;
 6 import ren.laughing.datastructure.exception.OutOfBoundaryException;
 7 /**
 8  * 对于链接表的迭代器的实现
 9  * @author Laughing_Lz
10  * @time 2016年4月6日
11  */
12 public class LinkListIterator implements Iterator{
13     private LinkedList linkedList;//链接表
14     private Node current;//当前结点
15
16     public LinkListIterator(LinkedList linkedList) {
17         this.linkedList = linkedList;
18         if(linkedList.isEmpty()){//若当前链表为空
19             current = null;//当前结点置空
20         }else{
21             current = linkedList.first();//否则从第一个数据元素开始
22         }
23     }
24
25     @Override
26     public void first() {
27         if(linkedList.isEmpty()){
28             current = null;
29         }else{
30             current = linkedList.first();
31         }
32     }
33
34     @Override
35     public void next() {
36         if(isDone()){
37             throw new OutOfBoundaryException("错误:已经没有未遍历的元素了");
38         }else if(current == linkedList.last()){
39             current = null;//已经到达最后一个数据元素
40         }else{
41             current= linkedList.getNext(current);
42         }
43     }
44     //检查迭代器中是否还有剩余的元素
45     @Override
46     public boolean isDone() {
47         if(current == null){
48             return true;
49         }else{
50             return false;
51         }
52     }
53     //返回当前元素
54     @Override
55     public Object currentItem() throws OutOfBoundaryException {
56         if(isDone()){
57             throw new OutOfBoundaryException("错误:已经没有未遍历的元素了");
58         }
59         return current.getData();
60     }
61
62 }
时间: 2024-08-03 08:03:28

3、链接表的实现:双向链表的相关文章

Cocos2dx中利用双向链表实现无限循环滚动层

[Qboy原创] 在Cocos2dX 3.0 中已经实现一些牛逼的滚动层,但是对于有一些需要实现循环滚动的要求确没有实现,笔者在前段时间的一个做了一个游戏,需求是实现在少有的(13个)英雄中进行循环滚动层,即用户可以无限的向一个方向滚动,当到最后时,由前面的进行重复出现. 如下图: 为了满足以上需求,我第一反应就想到了采用大学数据结构中所学的双向链表.想想还真称靠谱诶.那就说干就干吧. 1.定义双向链接表结构: struct CycNode{//构建双向链表结构 CycNode* preNode

第二章 线性表2(链接表)

3.5.2 链接表接口 链接表可以看成是一组结点序列以及基于结点进行操作的线性结果的抽象,或则说是对链表的抽象. 链接表的接口: 1 package com.datastructure.chapter03.interfaces; 2 3 import com.datastructure.chapter03.exception.InvalidNodeException; 4 import com.datastructure.chapter03.exception.OutOfBoundaryExce

创建一个双向链表数据结构

这是书上的一道练习题,要求创建一个双向链表数据结构Ring,它是一个环形的结构,Ring必须支持从当前位置单步地前进或回退. add方法在当前元素之后添加元素,支持使用for-each.任何因环空而导致的无效操作,Ring类支持抛出适当的异常. 此外,不能继承LinkedList,也就是说只能自己单写一个. 解题的思路很简单,既然LinkedList就满意要求,那么再做一个LinkedList就可以了. 直接拿LinkedList源码来分析. 首先LinkedList创建了一个内部结点类:Nod

数据结构第四篇——线性表的链式存储之双向链表

?注:未经博主同意,不得转载. 前面讨论的单链表,每个结点中只有一个指针域,用来存放指向后继结点的指针,因此,从某个结点出发只能顺时针往后查找其他结点.若要查找某个结点的直接前驱,则需要从头指针开始沿链表探寻,处理起来十分不方便.为克服单链表的这一缺点,可引入双向链表. 双向链表中每一个结点含有两个指针域,一个指针指向其直接前驱结点,另一个指针指向直接后继结点.和单链表类似,双向链表一般也只有头指针唯一确定:同样也可设头结点,使得双向链表的某些操作简便一些. 双向链表结构定义如下:  双向链表是

双向链表(一)

参考: http://blog.sina.com.cn/s/blog_7d44748b01013fsf.html    (写的太好啦) http://blog.163.com/haibianfeng_yr/blog/static/34572620201453061036702/ 双(向)链表中有两条方向不同的链,即每个结点中除next域存放后继结点地址外,还增加一个指向其直接前趋的指针域prior.双向链表在查找时更方便 特别是大量数据的遍历 注意:    ①双链表由头指针head惟一确定的. 

c语言双向链表

typedef int ElemType; typedef struct _Node { ElemType value; struct _Node* pnext; struct _Node* prev; }node, *pNode; //创建双向链表 pNode Create_Double_List(int count) { pNode pn = NULL; pNode pb = NULL; pNode phead = (pNode)malloc(sizeof(node)); printf("请

C++__双向链表(练习)

双向链表 link.h #ifndef LINK_H_ #define LINK_H_ #define HEADER 0 #define TAIL -1 typedef int data_type; enum LINK_OP { LINK_ERR = -1, LINK_OK }; class LINK { private: data_type data; LINK *next; LINK *last; public: LINK(); LINK(data_type data); virtual ~

剑指offer:二叉搜索树与双向链表

1.题目描述: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 2.解题思路: (1)将左子树构造成双向链表,并返回链表头节点: (2)定位左子树双链表的尾节点: (3)如果左子树链表不为空,将当前root连缀其链尾: (4)将右子树构造出双向链表,并返回链表头节点: (5)如果右子树链表不为空,将当前root连缀其表头: (6)根据左子树链表是否为空,确定返回的节点. 3.JavaScript实现: function Conv

Uva 12657 Boxes in a Line 双向链表

操作4比较特殊,为了避免一次性修改所有元素的指针,由于题目只要求输出奇数盒子的编号,所以我们可以灵活的根据是否进行过操作4对操作1 操作2 进行改动 操作3不受操作4影响 上代码.... #include<cstdio> #include<algorithm> const int maxn=100000+5; int right[maxn],left[maxn]; void link (int L,int R){ right[L]=R;left[R]=L; } //在双向链表这样复