首先定义一个节点
public class Node {
private int data; // 节点值
private Node next; // 指向下一个节点的指针
public Node(int data){
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
也可以复杂一点
这里只用到最简单的data为int型的节点。
然后定义一个链表类封装链表的操作,链表类里需要一个头节点。
package com.example.demo.LinkedList;
/**
* @author MasterYi
* @Description: 单链表
* @date: 2019/11/8
*/
public class MyLinkedList {
private Node head; // 首先要有一个头节点
public MyLinkedList(){}
// 构造方法
// 将一个头节点传进来 构造出一个链表 此时链表里只有一个头节点
public MyLinkedList(Node head){
this.head = head;
}
// 求链表长度
public int getLength(){
// 头节点为空时,长度为0
int length = 0;
for(Node node = this.head;node!=null;node=node.getNext()){
length ++;
}
return length;
}
/**
* 找出第index节点,index从0开始
* @param index
* @return
*/
public Node findNodeByIndex(int index){
if(index+1 > this.getLength()){
return null;
}
Node retNode = this.head;
for(int i=0;i<this.getLength();i++){
if(i == index){
return retNode;
}
retNode=retNode.getNext();
}
return null;
}
/**
* 遍历链表并打印
*/
public void printList(){
for(Node node=this.head;node!=null;node=node.getNext()){
System.out.println("node data:"+node.getData());
}
System.out.println("-------------------");
}
/**
* 找出下一个节点
* @param curNode
* @return
*/
public Node findNext(Node curNode){
if(null == curNode){
return null;
}
return curNode.getNext();
}
/**
* 找出上一个节点
* @param curNode
* @return
*/
public Node findLast(Node curNode){
if(null == curNode || 0 == this.getLength()){
return null;
}
Node lastNode = null;
for(lastNode=this.head;lastNode.getNext()!=curNode;lastNode=lastNode.getNext()){}
return lastNode.getNext()==curNode? lastNode : null;
}
/**
* 向尾部添加一个节点
* @param addNode
* @return
*/
public boolean addNodeTail(Node addNode){
// 头节点为空 插入的节点就是头节点
if(0 == this.getLength()){
this.head = addNode;
}else{
Node tail = this.head; // 尾部节点
// 找到最后一个节点
for (;tail.getNext()!=null;tail=tail.getNext()){}
tail.setNext(addNode);
}
return true;
}
/**
* 在尾部删除一个节点
* @return
*/
public boolean delNodeTail(){
if(0 == this.getLength()){
return false;
}
Node tail;
for(tail = this.head;tail.getNext()!=null;tail=tail.getNext()){}
this.findLast(tail).setNext(null); // 将前一个节点的next指针指向null
return true;
}
/**
* 在当前节点后面新增一个节点
* @param curNode
* @return
*/
public boolean addNode(Node curNode,Node newNode){
if(0 == this.getLength()){
return false;
}
Node nowNode;
for(nowNode = this.head;nowNode!=curNode;nowNode=nowNode.getNext()){}
if(nowNode == curNode){
// 新节点的next指向当前的后面节点
// 当前节点的next指向新节点
newNode.setNext(nowNode.getNext());
nowNode.setNext(newNode);
return true;
}else {
// 没有找到当前节点
return false;
}
}
/**
* 删除当前节点
* @param curNode
* @return
*/
public boolean delNode(Node curNode){
Node nowNode = this.head;
for(int i=0;nowNode!=curNode && i<this.getLength();i++){
nowNode = nowNode.getNext();
}
// 没有找到此节点
if(null == nowNode ){
return false;
}
// 将当前节点的上一个节点的next设为下一个节点的next
this.findLast(nowNode).setNext(nowNode.getNext());
return true;
}
}
测试
public class TestMain {
public static void main(String[] args) {
MyLinkedList myLinkedList = new MyLinkedList();
Node head = new Node(1);
myLinkedList.addNodeTail(head);
myLinkedList.addNodeTail(new Node(2));
myLinkedList.addNodeTail(new Node(3));
myLinkedList.addNodeTail(new Node(4));
myLinkedList.addNodeTail(new Node(5)); // 向链表里往尾部插入5个节点 现在链表长度为5
myLinkedList.printList();
myLinkedList.delNodeTail(); // 删除尾部的一个节点,现在长度为4
myLinkedList.printList();
Node curNode = myLinkedList.findNodeByIndex(2);
Node node999 = new Node(999);
myLinkedList.addNode(curNode,node999); // 往第二个节点的后面插入一个新节点
myLinkedList.printList();
myLinkedList.delNode(node999); // 删除这个新节点
myLinkedList.printList();
}
}
测试结果:
以上为单链表的实现。单链表是指节点里只有数据域(data)和指向下一节点的指针(next)
单链表可以在O(1)的时间内找到当前节点的下一节点(直接调用node.getNext()),但需要O(n)的时间来找出上一节点(需要从头节点开始遍历,findLast()方法体现了这个问题)
双向链表指不仅仅有数据域、下一节点的指针、还有上一节点的指针,只需要在Node类里增加一个指向上一节点的指针(pre),同时修改findLast()为node.getPre()即可。
此外还有环形链表(最后一个节点的指针指向头节点),
环形链表又分双向环形链表和单项环形链表。