Java实现点链表

链结点在链表中,每个数据项都被包含在‘点“中,一个点是某个类的对象,这个类可认叫做 LINK

因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点。

每个 LINK 对象中都包含一个对下一个点引用的字段(通常叫做next

但是本身的对象中有一个字段指向对第一个链结点的引用单链表是一种顺序存取的结构,

为找第 i个数据元素,必须先找到第i-1个数据元素。

因此,查找第i个数据元素的基本操作为:移动指针,比较j

    1、链接存储方法 

    链接方式存储的线性表简称为链表(LinkedList )。 

    链表的具体存储表示为: 

    ① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的, 

也可以是不连续的) 

 ② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻 

辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信 

息(称为指针(pointer )或链(link) ) 

    注意: 

    链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示 

各种非线性的数据结构。 

    2 、链表的结点结构 

     ┌──┬──┐ 

     │data next │ 

     └──┴──┘ 

    data --存放结点值的数据域 

    next --存放结点的直接后继的地址(位置)的指针域(链域) 

    注意: 

    ①链表通过每个结点的链域将线性表的 个结点按其逻辑顺序链接在一起的。 

    ②每个结点只有一个链域的链表称为单链表(Single                         Linked  List )。 

    3 、头指针 head 和终端结点指针域的表示 

    单链表中每个结点的存储地址是存放在其前趋结点 next 域中,而开始结点无前 

趋,故应设头指针 head 指向开始结点。 

    注意: 

    链表由头指针唯一确定,单链表可以用头指针的名字来命名。 

    【例】头指针名是 head 的链表可称为表 head 。 

    终端结点无后继,故终端结点的指针域为空,即 NULL 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
public class LinkList<T> {
 
     public class Node{  //定义节点
         private T data;
         private Node next;
         public Node(){
             
         }
         public Node(T data,Node next){
             this .data=data;
             this .next=next;
         }
     }
     
     private Node header; //头节点
     private Node tail; //尾节点
     private int size; //链表大小
     
    
     //构造函数初始化数据
     public LinkList(){
         header= null ;
         tail= null ;
     }
     public LinkList(T element){
         header= new Node(element, null );
         tail=header;
         size++;
     }
     
     //链表长度
     public int length(){
         return size;
     }
     
     //返回指定位置index的节点
     public T get( int index){
         return getNodeByIndex(index).data;
     }
     
     private Node getNodeByIndex( int index) {
         if (index< 0 ||index>size- 1 ){
             throw new IndexOutOfBoundsException( "线性表索引越界" );
         }
         Node current=header;
         for ( int i= 0 ;i<size&¤t!= null ;i++,current=current.next){
             if (i==index){
                 return current;
             }
         }
         return null ;
     }
     
     //返回element在链表的位置,-1表示不存在
     public int locate(T element){
         Node current=header;
         for ( int i= 0 ;i<size&¤t!= null ;i++,current=current.next){
             if (current.data==element){
                 return i;
             }
         }
         return - 1 ;
     }
     
     
     //在index位置插入节点element
     public void insert(T element, int index){
         if (index< 0 ||index>size){
             throw new IndexOutOfBoundsException( "线性表索引越界" );
         }
         if (header== null ){
             add(element);
         } else {
             if (index== 0 ){
                 addAtHeader(element);
             } else {
                 Node prev=getNodeByIndex(index- 1 );
                 prev.next= new Node(element,prev.next);
                 size++;
             }
         }
     }
     
     //采用尾插法为链表添加新节点
     private void add(T element) {
         // TODO Auto-generated method stub
         if (header== null ){
             header= new Node(element, null );
             tail=header;
         } else {
             Node newNode= new Node(element, null );
             tail.next=newNode;
             tail=newNode;
         }
         size++;
     }
     
     //采用头插法为链表添加新节点
     private void addAtHeader(T element){
         header= new Node(element,header);
         if (tail== null ){
             tail=header;
         }
         size++;
     }
     
     //删除index位置的节点
     public T delete( int index){
         if (index< 0 ||index>size- 1 ){
             throw new IndexOutOfBoundsException( "线性表索引越界" );
         }
         Node del= null ;
         if (index== 0 ){
             del=header;
             header=header.next;
         } else {
             Node prev=getNodeByIndex(index- 1 );
             del=prev.next;
             prev.next=del.next;
             del.next= null ;
         }
         size--;
         return del.data;
     }
     
     //从链表后面删除一个节点
     public T remove(){
         return delete(size- 1 );
     }
     
     //是否为空
     public boolean empty(){
         return size== 0 ;
     }
     //清空链表
     public void clear(){
         header= null ;
         tail= null ;
         size= 0 ;
     }
     
     public String toString(){
         if (empty()){
             return "[]" ;
         } else {
             StringBuilder sb= new StringBuilder( "[" );
             for (Node current=header;current!= null ;current=current.next){
                 sb.append(current.data.toString()+ ", " );
             }
             int len=sb.length();
             return sb.delete(len- 2 , len).append( "]" ).toString();
         }
     }
     public static void main(String[] args) {
         LinkList<String> list= new LinkList<String>();
         list.insert( "aaa" , 0 );
         list.add( "bbb" );
         list.add( "ccc" );
         System.out.println(list.toString());
         list.insert( "ddd" , 1 );
         System.out.println(list.toString());
         list.delete( 2 );
         System.out.println(list.toString());
         System.out.println( "ccc在链表中的位置:" +list.locate( "ccc" ));
         System.out.println( "链表中索引2处的元素:" +list.get( 2 ));
     }
 
}
/* * 基于链表实现二叉树节 */ package dsa; public class BinTreeNode implements BinTreePosition { protected Object element;//该节中存放的对象 protected BinTreePosition parent;//父亲 protected BinTreePosition lChild;//左孩子 protected BinTreePosition rChild;//右孩子 protected int size;//后代数目 protected int height;//高度 protected int depth;//深度 /**************************** 构造方法 ****************************/ public BinTreeNode() { this(null, null, true, null, null); } public BinTreeNode( Object e,//节内容 BinTreePosition p,//父节 boolean asLChild,//是否作为父节的左孩子 BinTreePosition l,//左孩子 BinTreePosition r)//右孩子 { size = 1; height = depth = 0; parent = lChild = rChild = null;//初始化 element = e;//存放的对象 //建立与父亲的关系 if (null != p) if (asLChild) p.attachL(this); else p.attachR(this); //建立与孩子的关系 if (null != l) attachL(l); if (null != r) attachR(r); } /**************************** Position接口方法 ********************************/ //返回当前节中存放的对象 public Object getElem() { return element; } //将对象obj存入当前节,并返回此前的内容 public Object setElem(Object obj) { Object bak = element; element = obj; return bak; } /**************************** BinTreePosition接口方法 *************************/ //判断是否有父亲(为使代码描述简洁) public boolean hasParent() { return null != parent; } //返回当前节的父节 public BinTreePosition getParent() { return parent; } //设置当前节的父节 public void setParent(BinTreePosition p) { parent = p; } //判断是否为叶子 public boolean isLeaf() { return !hasLChild() && !hasRChild(); } //判断是否为左孩子(为使代码描述简洁) //若当前节有父亲,而且是左孩子,则返回true;否则,返回false public boolean isLChild() { return (hasParent() && this == getParent().getLChild()) ? true : false; } //判断是否有左孩子(为使代码描述简洁) public boolean hasLChild() { return null != lChild; } //返回当前节的左孩子 public BinTreePosition getLChild() { return lChild; } //设置当前节的左孩子(注意:this.lChild和c.parent都不一定为空) public void setLChild(BinTreePosition c) { lChild = c; } //判断是否为右孩子(为使代码描述简洁) //若当前节有父亲,而且是右孩子,则返回true;否则,返回false public boolean isRChild() { return (hasParent() && this == getParent().getRChild()) ? true : false; } //判断是否有右孩子(为使代码描述简洁) public boolean hasRChild() { return null != rChild; } //返回当前节的右孩子 public BinTreePosition getRChild() { return rChild; } //设置当前节的右孩子(注意:this.rChild和c.parent都不一定为空) public void setRChild(BinTreePosition c) { rChild = c; } //返回当前节后代元素的数目 public int getSize() { return size; } //在孩子发生变化后,更新当前节及其祖先的规模 public void updateSize() { size = 1;//当前节 if (hasLChild()) size += getLChild().getSize();//左子树的规模 if (hasRChild()) size += getRChild().getSize();//右子树的规模 if (hasParent()) getParent().updateSize();//递归更新各个真祖先的规模记录 } //返回当前节的高度 public int getHeight() { return height; } //在孩子发生变化后,更新当前节及其祖先的高度 public void updateHeight() { height = 0;//先假设没有左、右孩子 if (hasLChild()) height = Math.max(height, 1+getLChild().getHeight());//左孩子 if (hasRChild()) height = Math.max(height, 1+getRChild().getHeight());//右孩子 if (hasParent()) getParent().updateHeight();//递归更新各个真祖先的高度记录 } //返回当前节的深度 public int getDepth() { return depth; } //在父亲发生变化后,更新当前节及其后代的深度 public void updateDepth() { depth = hasParent() ? 1+getParent().getDepth() : 0;//当前节 if (hasLChild()) getLChild().updateDepth();//沿孩子引用逐层向下, if (hasRChild()) getRChild().updateDepth();//递归地更新所有后代的深度记录 } //按照中序遍历的次序,找到当前节的直接前驱 public BinTreePosition getPrev() { //若左子树非空,则其中的最大者即为当前节的直接前驱 if (hasLChild()) return findMaxDescendant(getLChild()); //至此,当前节没有左孩子 if (isRChild()) return getParent();//若当前节是右孩子,则父亲即为其直接前驱 //至此,当前节没有左孩子,而且是左孩子 BinTreePosition v = this;//从当前节出发 while (v.isLChild()) v = v.getParent();//沿左孩子链一直上升 //至此,v或者没有父亲,或者是父亲的右孩子 return v.getParent(); } //按照中序遍历的次序,找到当前节的直接后继 public BinTreePosition getSucc() { //若右子树非空,则其中的最小者即为当前节的直接后继 if (hasRChild()) return findMinDescendant(getRChild()); //至此,当前节没有右孩子 if (isLChild()) return getParent();//若当前节是左孩子,则父亲即为其直接后继 //至此,当前节没有右孩子,而且是右孩子 BinTreePosition v = this;//从当前节出发 while (v.isRChild()) v = v.getParent();//沿右孩子链一直上升 //至此,v或者没有父亲,或者是父亲的左孩子 return v.getParent(); } //断绝当前节与其父亲的父子关系 //返回当前节 public BinTreePosition secede() { if (null != parent) { if (isLChild()) parent.setLChild(null);//切断父亲指向当前节的引用 else parent.setRChild(null); parent.updateSize();//更新当前节及其祖先的规模 parent.updateHeight();//更新当前节及其祖先的高度 parent = null;//切断当前节指向原父亲的引用 updateDepth();//更新节及其后代节的深度 } return this;//返回当前节 } //将节c作为当前节的左孩子 public BinTreePosition attachL(BinTreePosition c) { if (hasLChild()) getLChild().secede();//摘除当前节原先的左孩子 if (null != c) { c.secede();//c脱离原父亲 lChild = c; c.setParent(this);//确立新的父子关系 updateSize();//更新当前节及其祖先的规模 updateHeight();//更新当前节及其祖先的高度 c.updateDepth();//更新c及其后代节的深度 } return this; } //将节c作为当前节的右孩子 public BinTreePosition attachR(BinTreePosition c) { if (hasRChild()) getRChild().secede();//摘除当前节原先的右孩子 if (null != c) { c.secede();//c脱离原父亲 rChild = c; c.setParent(this);//确立新的父子关系 updateSize();//更新当前节及其祖先的规模 updateHeight();//更新当前节及其祖先的高度 c.updateDepth();//更新c及其后代节的深度 } return this; } //前序遍历 public Iterator elementsPreorder() { List list = new List_DLNode(); preorder(list, this); return list.elements(); } //中序遍历 public Iterator elementsInorder() { List list = new List_DLNode(); inorder(list, this); return list.elements(); } //后序遍历 public Iterator elementsPostorder() { List list = new List_DLNode(); postorder(list, this); return list.elements(); } //层次遍历 public Iterator elementsLevelorder() { List list = new List_DLNode(); levelorder(list, this); return list.elements(); } /**************************** 辅助方法 ****************************/ //在v的后代中,找出最小者 protected static BinTreePosition findMinDescendant(BinTreePosition v) { if (null != v) while (v.hasLChild()) v = v.getLChild();//从v出发,沿左孩子链一直下降 //至此,v或者为空,或者没有左孩子 return v; } //在v的后代中,找出最大者 protected static BinTreePosition findMaxDescendant(BinTreePosition v) { if (null != v) while (v.hasRChild()) v = v.getRChild();//从v出发,沿右孩子链一直下降 //至此,v或者为空,或者没有右孩子 return v; } //前序遍历以v为根节的(子)树 protected static void preorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 list.insertLast(v);//访问v preorder(list, v.getLChild());//遍历左子树 preorder(list, v.getRChild());//遍历右子树 } //中序遍历以v为根节的(子)树 protected static void inorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 inorder(list, v.getLChild());//遍历左子树 list.insertLast(v);//访问v inorder(list, v.getRChild());//遍历右子树 } //后序遍历以v为根节的(子)树 protected static void postorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 postorder(list, v.getLChild());//遍历左子树 postorder(list, v.getRChild());//遍历右子树 list.insertLast(v);//访问v } //层次遍历以v为根节的(子)树 protected static void levelorder(List list, BinTreePosition v) { Queue_List Q = new Queue_List();//空队 Q.enqueue(v);//根节入队 while (!Q.isEmpty()) { BinTreePosition u = (BinTreePosition) Q.dequeue();//出队 list.insertLast(u);//访问v if (u.hasLChild()) Q.enqueue(u.getLChild()); if (u.hasRChild()) Q.enqueue(u.getRChild()); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值