链表
链表是一个常见的基础数据结构,可以理解为一种线性表,是一种物理存储单元上非连续、非顺序的存储结构。也可以称之为链式存储的线性表,链表是由多个链表元素(节点)组成,二节点之间通过逻辑连接,这样就形成了链式存储结构。
链表可以分为两个域:
1、数据域(值域):用来存储节点的值
2、指针域(链域):用来存储其后节点的地址或位置
下面我将对自己学过的链表做一个复习与总结,只是单纯的为了以后能够随时复习,它的存在相当于一个笔记的形式。
单链表
1、单链表的的每个节点只有一个next指针域,它是一种顺序存储结构。
2、单链表中每个节点的存储地址存放在其前驱节点(也就是上一个节点)的指针域中,那么问题来了,第一个节点前面没有节点了,所以应该设一个头指针H指向第一个节点。
3、同理,最后一个节点没有直接后继节点了,所以指定单链表的最后一个节点的指针域为空(NULL)。
4、单链表的头指针H标志着整个单链表的开始,所以必须得先知道头指针,才能够顺着每个节点的next指针域去得到单链表中的每个元素。
5、在单链表中要找到第N个节点或者数据元素,必须先找到第N-1个节点,通过它的指针域去拿到N的信息。
6、单链表只可向一个方向遍历。
7、有时候为了操作的统一方便,可以给单链表增加一个头结点,这个头结点数据域存储一些关于线性表的长度等附加信息,指针域用来存储指向第一个结点的指针,也就变成了H —> 头结点数据域/指针域 —> 第一个结点数据域/指针域…
单链表的基本操作
可以在单链表上执行各种操作,下面将介绍这些基本操作和实现。
package demo2;
//一个节点
public class Node {
//节点内容
int data;
//下一个节点
Node next;
public Node(int data) {
// TODO Auto-generated constructor stub
this.data=data;
}
//为节点追加节点
public Node append(Node node) {
//this.next=node;
//当前节点
Node currentNode=this;
//循环向后找
while(true) {
//取出下一个节点
Node nextNode=currentNode.next;
//如果下一个节点为null
if(nextNode==null) {
break;
}
//赋给当前节点
currentNode=nextNode;
}
//把需要追加的节点添加到找到的当前节点
currentNode.next=node;
return this;
}
//插入一个节点作为当前节点的下一个结点
public void after(Node node) {
//取出下一个节点
Node nextNext=next;
//把当前结点作为当前节点的下一个节点
this.next=node;
//把下下一个节点设置为新节点的下一个节点
node.next=nextNext;
}
//显示所有节点的信息
public void show() {
Node currentNode=this;
while(true) {
System.out.println(currentNode.data+" ");
currentNode=currentNode.next;
//如果是最后一个节点
if(currentNode==null) {
break;
}
}
System.out.println();
}
//删除下一个节点
public void removeNext() {
//取出下下一个节点
Node nextNext=next.next;
//把下下一个节点设置为当前节点的下一个节点
this.next=nextNext;
}
//获取下一个节点
public Node next() {
return this.next;
}
//获取节点中的数据
public int getData() {
return this.data;
}
//查看当前节点是否是最后一个节点
public boolean isLast() {
return next==null;
}
}
public class TestNode {
public static void main(String[] args) {
//创建节点
Node n1=new Node(1);
Node n2=new Node(2);
Node n3=new Node(3);
//n1.append(n2);
//n1.append(n3);
//取出下一个结点
n1.append(n2).append(n3).append(new Node(4));
//System.out.println(n1.next().next().getData());
//System.out.println(n2.next());
//取出下一个节点的数据
//System.out.println(n1.next().next().next().getData());
//显示所有节点内容
//System.out.println(n1.isLast());
n1.show();
//删除一个节点
//n1.next.removeNext();
//n1.show();
Node node=new Node(5);
n1.next.after(node);
n1.show();
}
}
循环链表
1、循环列表首尾相接,它是将单链表的最后一个结点的指针域由NULL改为指向表头结点,就得到了单链形式的循环链表,即循环单链表。
2、带头结点的循环单链表的各种操作的实现算法和带头结点的单链表的实现算法基本一致,差别仅在于算法中判断当前结点p是否为表尾结点的条件不同
循环链表的基本操作
package demo2;
public class lookNode {
//节点内容
int data;
//下一个节点
lookNode next=this;
public lookNode(int data) {
// TODO Auto-generated constructor stub
this.data=data;
}
//插入一个节点作为当前节点的下一个结点
public void after(lookNode node) {
//取出下一个节点
lookNode nextNext=next;
//把当前节点作为当前节点的下一个节点
this.next=node;
//把下下一个节点设置为新节点的下一个节点
node.next=nextNext;
}
//删除下一个节点
public void removeNext() {
//取出下下一个节点
lookNode nextNext=next.next;
//把下下一个节点设置为当前节点的下一个节点
this.next=nextNext;
}
//获取下一个节点
public lookNode next() {
return this.next;
}
//获取节点中的数据
public int getData() {
return this.data;
}
//查看当前节点是否是最后一个节点
public boolean isLast() {
return next==null;
}
}
package demo2;
public class textLookNode {
public static void main(String[]args) {
lookNode n1=new lookNode(1);
lookNode n2=new lookNode(2);
lookNode n3=new lookNode(3);
lookNode n4=new lookNode(4);
//增加节点
n1.after(n2);
n2.after(n3);
n3.after(n4);
System.out.println(n1.next().getData());
System.out.println(n2.next().getData());
System.out.println(n3.next().getData());
System.out.println(n4.next().getData());
}
}
双链表
双向链表也被称为双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点地址,一般称之为右链域;一个存储直接前驱结点地址,一般称为左链域。
双链表的基本操作
对于链表的一些执行操作,虽然理解起来还是比较复杂,但是只要自己动手画个图去理解下,还是比较容易的,对于双链表的一些操作(插入、删除)等我就不做具体分析了,主要看代码吧!
package demo2;
public class doubleNode {
//上一个节点
doubleNode pre;
//下一个节点
doubleNode next=this;
//节点数据
int data;
public doubleNode(int data) {
this.data=data;
}
//增加节点
public void after(doubleNode node) {
//原来的下一节点
doubleNode nextNext =next;
//把新节点作为单签节点的下一个节点
this.next=node;
//把当前结点做为新节点的前一个结点
node.pre=this;
//让原来的下一个节点作为新节点的下一个节点
node.next=nextNext;
//让原来的下一个节点的上一个节点为新节点
nextNext.pre=node;
}
//获取下一节点
public doubleNode next() {
return this.next;
}
//获取上一节点
public doubleNode pre() {
return this.pre;
}
//获取数据
public int getData() {
return this.data;
}
}
package demo2;
public class textDoubleNode {
public static void main(String[] args) {
//创建节点
doubleNode n1=new doubleNode(1);
doubleNode n2=new doubleNode(2);
doubleNode n3=new doubleNode(3);
//doubleNode n4=new doubleNode(4);
//doubleNode n5=new doubleNode(5);
//追加节点
n1.after(n2);
n2.after(n3);
//查看上一个,自己,下一个节点的内容
System.out.println(n2.pre().getData());
System.out.println(n2.getData());
System.out.println(n2.next().getData());
System.out.println(n3.next().getData());
System.out.println(n1.pre().getData());
}
}