目录
链表的基本概念
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素
的逻辑顺序是通过链表中的指针
链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素
的数据域,另一个是存储下一个结点地址的指针
域。
链表不会像数组一样开辟一片连续的空间,比数组空间的利用率高,链表可以根据需要申请空间也可以释放空间,且申请的空间后链表的空间也不要求是连续的。链表的增删的效率比数组高,但是链表查找效率没有数组高。
单链表
单向链表单链表是链表
的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针
进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量
指向列表中的下一个结点;
链表是由结点
构成,head指针指向第一个成为表头结点,而终止于最后一个指向NULL
的指针。
该链表的头节点不添加数据,头节点的next变量存储了第一个变量的地址,第一个变量也存储了下一个节点的地址,依次类推可以得到一条链表。需要添加链表时在链表的最后节点的next变量添加一个新节点。
删除链表可以先找到该节点的父节点将父节点的next指向该节点的子节点 (如上图要删除第二个节点)
public class Linked {
private int date;//链表中的数据
private Linked next;//下一个节点
public Linked(){
}
public Linked(int date){
this.date = date;
}
public void add(int date){//添加节点
Linked linked = this;
while (linked.next != null){
linked=linked.next;
}
linked.next=new Linked(date);
}
public int get(int index){//获取节点中的数据
Linked linked=this;
for(int i=0; i <= index; i++){
linked = linked.next;
if(linked == null){
throw new IndexOutOfBoundsException();
}
}
return linked.date;
}
public int delete(int index){//删除节点并返回该节点的数据
Linked linked=this;
for(int i=0; i<index; i++){
linked = linked.next;
if(linked.next == null){
throw new IndexOutOfBoundsException();
}
}
int date = linked.date;
linked.next = linked.next.next;
return date;
}
public int length(){//链表的长度
Linked linked = this;
int length = 0;
while (linked.next != null){
linked = linked.next;
length++;
}
return length;
}
public void forEach(){//遍历链表
Linked linked = this;
while (linked.next != null){
System.out.println(linked.next.date);
linked = linked.next;
}
}
}
双链表
双向链表也叫双链表,是链表的一种,它的每个数据结点
中都有两个指针
,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
链表增加结点
根据索引添加节点
找到当前索引位置的父节点,将该节点加入该链表,将父节点的next指向新加入的节点,该节点的front指向该父节点,next指向该父节点原来的子节点。(这一步需要判断是否存在该子节点,存在才可以操作)将该子节点的front指向新节点中
添加元素到链表的最后
遍历找到最后的节点,加入该链表
删除操作
找到该索引所在的节点,将该节点的父节点的next指向
public class DoubleLinked {
private int date;
private DoubleLinked next;
private DoubleLinked front;
public void addNext(DoubleLinked linked){
this.next = linked;
}
public void addFront(DoubleLinked linked){
this.front = linked;
}
public boolean isEmpty(){//判断链表是否为空
if(this.front == null && this.next == null){
return true;
}
return false;
}
//添加元素至链表最后
public void add(int date){
DoubleLinked doubleLinked =this;
while (doubleLinked.next!=null){
doubleLinked=doubleLinked.next;
}
doubleLinked.next=new DoubleLinked(date);
doubleLinked.next.front=doubleLinked;
}
//根据索引添加元素
public void add(int index,int date){
DoubleLinked doubleLinked=this;
for (int i=0;i<index;i++){
doubleLinked=doubleLinked.next;
}
DoubleLinked doubleLinked1 = new DoubleLinked(date);
doubleLinked1.next=doubleLinked.next;
doubleLinked1.front=doubleLinked;
doubleLinked.next = doubleLinked1;
}
//根据索引删除节点
public int delete(int index){
DoubleLinked doubleLinked =this;
if(doubleLinked.isEmpty()){
throw new IndexOutOfBoundsException();
}
for(int i=0;i<index;i++){
doubleLinked=doubleLinked.next;
if(doubleLinked==null){
throw new IndexOutOfBoundsException();
}
}
doubleLinked.front.next=doubleLinked.next;
if(doubleLinked.next!=null) {
doubleLinked.next.front = doubleLinked.front;
}
return doubleLinked.date;
}
//遍历链表
public void forEach(){
DoubleLinked doubleLinked=this;
while (doubleLinked.next!=null){
System.out.println(doubleLinked.next.date);
doubleLinked=doubleLinked.next;
}
}
public DoubleLinked(int date){
this.date=date;
}
public DoubleLinked(){}
}
环形链表
循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。
环形链表即在单链表的基础上加尾指针指向头节点形成的闭环链表。
下面这段代码简单实现了环形链表,且并未实现删除操作,删除操作可以根据需要去实现。如约瑟夫问题。或者像上面代码定义一个头节点根据索引删除,在定义的尾节点的上添加。下面这段代码只是为了帮助大家理解环形链表。
public class CircularLinked {
private int date;
private CircularLinked next;
private CircularLinked tail;
public CircularLinked(int date){
this.date=date;
}
public CircularLinked(){
}
public boolean isEmpty(){
return next==null;
}
public void add(int date){
if(isEmpty()){
this.date=date;
this.next=this;
tail = this;
}else {
CircularLinked circularLinked = new CircularLinked(date);
circularLinked.next = tail.next;
tail.next = circularLinked;
tail = circularLinked;
}
}
public int length(){
if(isEmpty()){
return 0;
}
int i=0;
CircularLinked circularLinked = this;
while (circularLinked!=tail){
circularLinked = circularLinked.next;
i++;
}
return i+1;
}
}