博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据结构之链表
阅读量:6817 次
发布时间:2019-06-26

本文共 4897 字,大约阅读时间需要 16 分钟。

数组的两大缺点:

1。若改变数组的大小就要创建一个新的数组,并需要从原数组复制所有的数据到新的数组

2。数组元素在内存中依次顺序存储,这意味着向数组插入一项要移动数组中的其他元素

因此,我们使用链式结构,链式结构是存储数据的结点以及指向其他节点的指针的集合。如此一来,节点可以位于内存的任意位置,而且从一个节点到另一个节点的传递可以通过在结构中存储节点间引用来实现。

一。单向链表

1。链表:

如果一个节点包含指向另一个节点的数据值,那么多个节点可以连接成一串,只通过一个变量访问整个节点序列,这样的节点序列称为链表(linked list)

2。单向链表:

如果每个节点仅包含其指向后继节点的引用,这样的链表称为单向链表。

一个整型单向链表的实现:

 

None.gif
package
 com.sohu.blog.denns_zane.list;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/** */
/**
InBlock.gif * 
@author
 dennis
InBlock.gif * @Description 整型单向链表节点
ExpandedBlockEnd.gif 
*/
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 IntSLLNode 
dot.gif
{
InBlock.gif    
public
 
int
 info; 
//
 用户信息
InBlock.gif
InBlock.gif    
public
 IntSLLNode next; 
//
 下一个节点,自引用
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/** */
/**
InBlock.gif     * 
@param
 info
InBlock.gif     * 
@param
 next
ExpandedSubBlockEnd.gif     
*/
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 IntSLLNode(
int
 info, IntSLLNode next) 
dot.gif
{
InBlock.gif        
this
.info 
=
 info;
InBlock.gif        
this
.next 
=
 next;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/** */
/**
InBlock.gif     * 
@param
 info
ExpandedSubBlockEnd.gif     
*/
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 IntSLLNode(
int
 info) 
dot.gif
{
InBlock.gif        
this
(info, 
null
);
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/** */
/**
InBlock.gif * 
ExpandedBlockEnd.gif 
*/
None.gif
package
 com.sohu.blog.denns_zane.list;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/** */
/**
InBlock.gif * 
@author
 dennis
InBlock.gif * desc: 整型单向链表
ExpandedBlockEnd.gif 
*/
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 IntSLList 
dot.gif
{
InBlock.gif    
protected
 IntSLLNode head, tail;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 IntSLList() 
dot.gif
{
InBlock.gif        head 
=
 tail 
=
 
null
;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
boolean
 isEmpty() 
dot.gif
{
InBlock.gif        
return
 head 
==
 
null
;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/** */
/**
InBlock.gif     * @description 增加新节点,并设置它的next为原head
InBlock.gif     * 
@param
 el
ExpandedSubBlockEnd.gif     
*/
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
void
 addToHead(
int
 el) 
dot.gif
{
InBlock.gif        head 
=
 
new
 IntSLLNode(el, head);
InBlock.gif        
if
 (tail 
==
 
null
)
InBlock.gif            tail 
=
 head;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/** */
/**
InBlock.gif     * @description 增加新节点,并设置原tail的next为新节点
InBlock.gif     * 
@param
 el
ExpandedSubBlockEnd.gif     
*/
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
void
 addToTail(
int
 el) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
if
 (
!
isEmpty()) 
dot.gif
{
InBlock.gif            tail.next 
=
 
new
 IntSLLNode(el);
InBlock.gif            tail 
=
 tail.next;
ExpandedSubBlockStart.gifContractedSubBlock.gif        }
 
else
 
dot.gif
{
InBlock.gif            head 
=
 tail 
=
 
new
 IntSLLNode(el);
ExpandedSubBlockEnd.gif        }
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
int
 deleteFromHead() 
dot.gif
{
InBlock.gif        
if
 (head 
==
 
null
)
InBlock.gif            
throw
 
new
 NullPointerException();
InBlock.gif        
int
 el 
=
 head.info;
InBlock.gif        
if
 (head 
==
 tail)
InBlock.gif            head 
=
 tail 
=
 
null
;
InBlock.gif        
else
InBlock.gif            head 
=
 head.next;
InBlock.gif        
return
 el;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
int
 deleteFromTail() 
dot.gif
{
InBlock.gif        
if
 (head 
==
 
null
)
InBlock.gif            
throw
 
new
 NullPointerException();
InBlock.gif        
int
 el 
=
 tail.info;
InBlock.gif        
if
 (head 
==
 tail)
InBlock.gif            head 
=
 tail 
=
 
null
;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
else
 
dot.gif
{
InBlock.gif            IntSLLNode temp;
InBlock.gif            
for
 (temp 
=
 head; temp.next 
!=
 
null
 
&&
 temp.next 
!=
 tail; temp 
=
 temp.next)
InBlock.gif                tail 
=
 temp;
InBlock.gif            System.out.println(tail.info);
InBlock.gif            tail.next 
=
 
null
;
ExpandedSubBlockEnd.gif        }
InBlock.gif        
return
 el;
InBlock.gif
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
void
 printAll() 
dot.gif
{
InBlock.gif        
for
 (IntSLLNode temp 
=
 head; temp 
!=
 
null
; temp 
=
 temp.next)
InBlock.gif            System.out.print(temp.info 
+
 
"
 
"
);
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
boolean
 isInList(
int
 el) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
for
 (IntSLLNode temp 
=
 head; temp 
!=
 
null
; temp 
=
 temp.next) 
dot.gif
{
InBlock.gif            
if
 (temp.info 
==
 el)
InBlock.gif                
return
 
true
;
ExpandedSubBlockEnd.gif        }
InBlock.gif        
return
 
false
;
InBlock.gif
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/** */
/**
InBlock.gif     * 
@param
 el
ExpandedSubBlockEnd.gif     
*/
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
void
 delete(
int
 el) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
if
 (
!
isEmpty()) 
dot.gif
{
InBlock.gif            
if
 (head 
==
 tail 
&&
 head.info 
==
 el)
InBlock.gif                head 
=
 tail 
=
 
null
;
InBlock.gif            
else
 
if
 (head.info 
==
 el)
InBlock.gif                head 
=
 head.next;
ExpandedSubBlockStart.gifContractedSubBlock.gif            
else
 
dot.gif
{
InBlock.gif                IntSLLNode pred, temp;
//
 pred为找的节点的前一节点,temp即为找到的节点
ExpandedSubBlockStart.gifContractedSubBlock.gif
                
for
 (pred 
=
 head, temp 
=
 head.next; temp 
!=
 
null
; pred 
=
 pred.next, temp 
=
 temp.next) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
if
 (temp.info 
==
 el) 
dot.gif
{
InBlock.gif                        pred.next 
=
 temp.next; 
//
 前一节点的next设置为当前节点的next
InBlock.gif
                        
if
 (temp 
==
 tail)
InBlock.gif                            tail 
=
 pred;
ExpandedSubBlockEnd.gif                    }
ExpandedSubBlockEnd.gif                }
ExpandedSubBlockEnd.gif            }
ExpandedSubBlockEnd.gif        }
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif}
None.gif
None.gif

二。双向链表

单向链表的deleteFromTail()方法指出了单向链表的固有问题,这种链表的节点仅仅包含指向后继节点的引用,所以无法立即访问它的前驱节点,不得不扫描整个链表来查找此前驱节点。因此,我们重新定义链表节点,包含两个引用,一个指向前驱节点,一个指向后驱节点,也就是——双向链表。
一个整型双向链表的实现:
ExpandedBlockStart.gif
ContractedBlock.gif
/** */
/**
InBlock.gif * 
ExpandedBlockEnd.gif 
*/
None.gif
package
 com.sohu.blog.denns_zane.list;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/** */
/**
InBlock.gif * 
@author
 dennis desc:双向链表节点
ExpandedBlockEnd.gif 
*/
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 IntDLLNode 
dot.gif
{
InBlock.gif    
public
 
int
 info;
InBlock.gif
InBlock.gif    
public
 IntDLLNode prev, next;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/** */
/**
InBlock.gif     * 
@param
 info
InBlock.gif     * 
@param
 prev
InBlock.gif     * 
@param
 next
ExpandedSubBlockEnd.gif     
*/
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 IntDLLNode(
int
 info, IntDLLNode next, IntDLLNode prev) 
dot.gif
{
InBlock.gif        
super
();
InBlock.gif        
this
.info 
=
 info;
InBlock.gif        
this
.prev 
=
 prev;
InBlock.gif        
this
.next 
=
 next;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 IntDLLNode(
int
 info) 
dot.gif
{
InBlock.gif        
this
(info, 
null
null
);
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/** */
/**
InBlock.gif * 
ExpandedBlockEnd.gif 
*/
None.gif
package
 com.sohu.blog.denns_zane.list;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/** */
/**
InBlock.gif * 
@author
 dennis
InBlock.gif * 
ExpandedBlockEnd.gif 
*/
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 IntDLList 
dot.gif
{
InBlock.gif    
private
 IntDLLNode head, tail;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 IntDLList() 
dot.gif
{
InBlock.gif        head 
=
 tail 
=
 
null
;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
boolean
 isEmpty() 
dot.gif
{
InBlock.gif        
return
 head 
==
 
null
;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
void
 addToHead(
int
 el) 
dot.gif
{
InBlock.gif        
if
 (head 
==
 
null
)
InBlock.gif            head 
=
 
new
 IntDLLNode(el);
ExpandedSubBlockStart.gifContractedSubBlock.gif        
else
 
dot.gif
{
InBlock.gif            head 
=
 
new
 IntDLLNode(el, head, 
null
);
InBlock.gif            head.next.prev 
=
 head;
ExpandedSubBlockEnd.gif        }
InBlock.gif        
if
 (tail 
==
 
null
)
InBlock.gif            tail 
=
 head;
InBlock.gif
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
void
 addToTail(
int
 el) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
if
 (
!
isEmpty()) 
dot.gif
{
InBlock.gif            tail 
=
 
new
 IntDLLNode(el, 
null
, tail);
InBlock.gif            tail.prev.next 
=
 tail;
ExpandedSubBlockEnd.gif        }
 
else
InBlock.gif            head 
=
 tail 
=
 
new
 IntDLLNode(el);
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
int
 removeFromTail() 
dot.gif
{
InBlock.gif        
if
 (head 
==
 
null
)
InBlock.gif            
throw
 
new
 NullPointerException();
InBlock.gif        
int
 el 
=
 tail.info;
InBlock.gif        
if
 (head 
==
 tail)
InBlock.gif            head 
=
 tail 
=
 
null
;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
else
 
dot.gif
{
InBlock.gif            tail 
=
 tail.prev;
InBlock.gif            tail.next 
=
 
null
;
ExpandedSubBlockEnd.gif        }
InBlock.gif        
return
 el;
InBlock.gif
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
int
 removeFromHead() 
dot.gif
{
InBlock.gif        
if
 (head 
==
 
null
)
InBlock.gif            
throw
 
new
 NullPointerException();
InBlock.gif        
int
 el 
=
 head.info;
InBlock.gif        
if
 (head 
==
 tail)
InBlock.gif            head 
=
 tail 
=
 
null
;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
else
 
dot.gif
{
InBlock.gif            head 
=
 head.next;
InBlock.gif            head.prev 
=
 
null
;
ExpandedSubBlockEnd.gif        }
InBlock.gif        
return
 el;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
boolean
 isInList(
int
 el) 
dot.gif
{
InBlock.gif        
if
 (head 
==
 
null
)
InBlock.gif            
return
 
false
;
InBlock.gif        IntDLLNode temp;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
for
 (temp 
=
 head; temp 
!=
 
null
; temp 
=
 temp.next) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if
 (temp.info 
==
 el) 
dot.gif
{
InBlock.gif                
return
 
true
;
ExpandedSubBlockEnd.gif            }
ExpandedSubBlockEnd.gif        }
InBlock.gif        
return
 
false
;
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
void
 delete(
int
 el) 
dot.gif
{
InBlock.gif        
if
 (head 
==
 
null
)
InBlock.gif            
throw
 
new
 NullPointerException();
InBlock.gif        IntDLLNode temp;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
for
 (temp 
=
 head; temp 
!=
 
null
; temp 
=
 temp.next) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if
 (temp.info 
==
 el) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if
 (temp 
==
 head) 
dot.gif
{
InBlock.gif                    head.next.prev 
=
 
null
;
InBlock.gif                    head 
=
 head.next;
ExpandedSubBlockEnd.gif                }
 
else
InBlock.gif                    temp.prev.next 
=
 temp.next;
ExpandedSubBlockEnd.gif            }
ExpandedSubBlockEnd.gif        }
ExpandedSubBlockEnd.gif    }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public
 
void
 printAll() 
dot.gif
{
InBlock.gif        IntDLLNode temp;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
for
 (temp 
=
 head; temp 
!=
 
null
; temp 
=
 temp.next) 
dot.gif
{
InBlock.gif            System.out.print(temp.info 
+
 
"
 
"
);
ExpandedSubBlockEnd.gif        }
InBlock.gif        System.out.println();
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif}
None.gif

三。跳转表,循环表,自组织表(略)
四。结论
1。需要随机访问某元素,数组更为合适
2。需要动态分配内存,经常改变结构,链表更为合适
3。相比于链表,数组更为节约空间。毕竟链表节点还需要保存一个或者两个引用

文章转自庄周梦蝶  ,原文发布时间5.17

转载地址:http://occzl.baihongyu.com/

你可能感兴趣的文章
MEMCACHE常用的命令
查看>>
docker 基础
查看>>
Angular基础(七) HTTP & Routing
查看>>
使用Freeline提高你的工作效率
查看>>
FTP服务器
查看>>
爬百度新闻
查看>>
TCP协议与UDP协议的区别
查看>>
软件定时器算法
查看>>
VB.NET 自动打包程序
查看>>
CISCO引擎RPR SSO
查看>>
LINUX APACHE 安装测试
查看>>
Java导致登录UCS Manager异常
查看>>
HTTP协议
查看>>
Win10怎么改Host文件?Win10编辑host文件方法(无视权限)
查看>>
sql convert and cast
查看>>
我的NodeJS一年之旅总结
查看>>
MyBatis-3.4.2-源码分析6:解析XML之objectWrapperFactoryElement & reflectorFactoryElement
查看>>
javascript与获取鼠标位置有关的属性
查看>>
Oracle database 11.2.0.3.0 升级至 11.2.0.3.14
查看>>
heartbeat理论介绍
查看>>