链表的定义:
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。
链表包含的什么:
每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
链表的种类:单向链表,双向链表,环形链表
最普通的单向链表学习:
- 单向链表是链表结构中的最基础类型,就是由一个数据域和指向下一个的节点的指针域组成
- 我们先来看看java中如何定义一个链表节点(LinkedNode):
//声明一个节点类
class LinkedNode{
private int data;//节点的数据域,存放数据的
private LinkedNode nextNode;//指向下一个的节点的指针域组成
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public LinkedNode getNextNode() {
return nextNode;
}
public void setNextNode(LinkedNode nextNode) {
this.nextNode = nextNode;
}
public LinkedNode(int data, LinkedNode nextNode) {
super();
this.data = data;
this.nextNode = nextNode;
}
public LinkedNode() {
super();
}
@Override
public String toString() {
return "ListNode [data=" + data + ", nextNode=" + nextNode + "]";
}
}
- OK,上面已经定义好了一个节点,但这个不能实现链表的结构,因为这只是一个一个的节点,我们需要使用另外一个类来实现链表的创建,但节点是必不可少的,总结的就是当我们创建很多节点对象通过这个链表类的方法(add)把他们构建成数据结构之链表.
- 那么链表结构中有什么?需要一个头节点headNode,因为链表就是从头节点开始寻找数据.
- 接下来我们写链表的实现类(Linked):
//创建链表实现类
class Linked{
private LinkedNode headNode=new LinkedNode();
//传入链表节点,添加到头节点后面
public void add(LinkedNode node) {
//1.首先判断头节点下有没有节点,也就是是否是第一个节点的添加
if (headNode.getNextNode()==null) {
//2.如果是首次添加节点,那么就让头节点指向这个节点
headNode.setNextNode(node);
}else {
LinkedNode temp=null;//3.声明一个中间节点对象当做指针
temp=headNode.getNextNode();//4.从头节点开始遍历
while (temp.getNextNode()!=null) {//5.如果当前节点的下一个节点为null,说明该节点已经是尾节点了
temp=temp.getNextNode();
}
//6.让尾节点的nextNode指向新添加的节点
temp.setNextNode(node);
}
}
//打印节点信息
public void forEachPrint() {
LinkedNode temp=null;
temp=headNode.getNextNode();
while (temp!=null) {
System.out.println(temp.getData());
temp=temp.getNextNode();
}
}
}
- 到这一步我们就完成了链表的最简单功能,添加和打印,接下来我们测试一下:
public static void main(String[] args) {
LinkedNode node1=new LinkedNode();
LinkedNode node2=new LinkedNode();
LinkedNode node3=new LinkedNode();
LinkedNode node4=new LinkedNode();
node1.setData(1);
node2.setData(2);
node3.setData(3);
node4.setData(4);
Linked linked=new Linked();
linked.add(node1);
linked.add(node2);
linked.add(node3);
linked.add(node4);
linked.forEachPrint();
}
//结果是 1,2,3,4
- 我们已经实现了添加,那怎么删除呢?删除节点的思想很简单:如果为尾节点,那么让其前一个节点的nextNode为null,如果是中间节点,则让其前一个节点指向其后一个节点就完成了删除操作,代码实现:
//节点的删除,根据索引
public void deleteNode(LinkedNode node) {
LinkedNode temp=null;
temp=headNode.getNextNode();
if (temp==null) {
System.out.println("链表为空");
}
//如果删除的是头节点,则让头指针指向下一个节点
if (temp.getData()==node.getData()) {
headNode.setNextNode(temp.getNextNode());
return ;
}
while (temp!=null) {
//如果是尾节点,则直接让其前一个节点指向null
if (temp.getNextNode().getData()==node.getData()&&temp.getNextNode()==null) {
temp.setNextNode(null);
return ;
}
//如果是中间节点,则让其前一个节点指向目标节点的下一个节点
if (temp.getNextNode().getData()==node.getData()&&temp.getNextNode()!=null) {
temp.setNextNode(temp.getNextNode().getNextNode());
return ;
}
temp=temp.getNextNode();
}
}
- 链表的翻转输出:给定一个链表,反向输出其结果,代码如下:
//链表的翻转
public void reverseLinked() {
if(headNode==null) {
System.out.println("链表为空");
}
LinkedNode reverseHeadNode=null;
LinkedNode tempNode=headNode;
Stack<LinkedNodeNode> stack=new Stack<LinkedNodeNode>();
int i=0;
while (tempNode!=null) {
stack.push(tempNode);
i+=1;
tempNode=tempNode.nextNode;
}
Node node=headNode=null;
for (int j = 0; j < i; j++) {
add(stack.pop().data);
}
}
双向链表学习:
- 结构如下:
class LinkedNode{
private Integer data;//数据域
private LinkedNode leftNode;//该节点左边的节点
private LinkedNode rightNode;//该节点右边的节点
}