java——单链表
我们都知道数组有一定的缺陷,在无序数组中,搜索效率低下,在有序数组中,存在着插入效率低,而且创建一个数组后,它的大小是不可能改变的。
单链表的概述
单链表是链表中结构最简单的,一个单链表的节点(node)分两部分,第一部分(data)保存或显示有关节点的信息,另一部分存储了下一个节点的地址,最后一个节点存储地址的部分指向空值。单向链表只可以项一个方向遍历,一般查找一个节点的时候需要从第一个节点开始访问下一个节点,直到访问到需要的位置,而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将当前插入的节点设置为头节点,next指向原头节点即可,删除一个节点,我们将提供该节点的上一个节点的next指向该节点的下一个节点。
链节点的演示
上面展示了的是一个单链表的存储原理,简单易懂,head为头接点,它不存放任何数据,只是充当一个指向链表中真正存放数据的第一个节点的作用,而每个节点都有一个next引用,指向下一个节点,就这样一节一节往下面记录,直到最后一个节点,其中的next指向null,
在表头增加节点
上面可以看出,当增加一个节点的时候,会从表头增加一个节点,然后连接下一个节点
删除节点
可以看出删除节点的话,会先从第一个节点的信息连接到第二个节点这样一次寻找到需要的位置删除元素,然后就会将当前被删除节点的上一个节点这直接连接到下一个节点。
public class LinkedListOnePoint {
private Node head;//头节点
private int size;//链表长度,即链表中节点的数量
public LinkedListOnePoint() {
head = null;
size = 0;
}
//私有内部类 代表链表每个节点
private class Node {
private Object data;//链表节点的值
private Node next;//指向下一个节点
public Node(Object data) {
this.data = data;
}
}
// 判断链表是否为空
public boolean isEmpty() {
return size == 0 ? true : false;
}
// 查看链表头节点不溢出
public Object headNode() {
if (size == 0) {
return null;
}
return head.data;
}
//在链表表头插入一个节点(入栈)
public void insertInHead(Object obj) {
Node newNode = new Node(obj);
if (size == 0) {
head = newNode;
} else {
newNode.next = head;
head = newNode;
}
size++;
}
// 删除链表表头节点(出栈)
public Object deleteHeadNode() {
if (size == 0) {
return null;
}
Object obj = head.data;
if (head.next == null) {
head = null;//只有一个节点
} else {
head = head.next;
}
size--;
return obj;
}
// 链表查找:判断链表中是否包含了某个元素
public boolean containObject(Object object) {
if (size == 0) {
return false;
}
Node n = head;
while (n != null) {
if (n.data == object) {
return true;
} else {
n = n.next;
}
}
return false;
}
// 删除链表中的指定节点(如果包含多个指定节点,只会删除第一个)
public boolean deletaNode(Object object) {
if (size == 0) {
System.out.println("链表为空");
return false;
}
//先在链表中查询是否包含该结点,找到之后获取该结点和其前一个结点
Node previous = null;//前一个节点
Node current = head;//当前节点
while (current.data != object) {
if (current.next == null) {
System.out.println("没有找到节点");
return false;
}
previous = current;
current = current.next;
}
if (current == head) {
this.deleteHeadNode();
} else {
previous.next = current.next;
size--;
}
return true;
}
//正向打印链表
public void display() {
if (size == 0) {
System.out.println("链表为空");
}
Node n = head;
while (n != null) {
System.out.print("<-" + n.data);
n = n.next;
}
System.out.println();
}
//反向打印链表
public void printListFromTailToHead(Node node) {
if (node == null) {
System.out.println("链表为空");
}
Stack<Integer> stack = new Stack<>();
while (node != null) {
stack.push((Integer) node.data);//压栈
node = node.next;
}
while (!stack.isEmpty()) {
System.out.print(stack.pop() + "<-");//出栈
}
System.out.println();
}
// 反向打印链表(递归)
public void printListFromTailToHeadDiGui(Node node) {
if (node == null) {
System.out.println("链表为空");
} else {
if (node != null) {
printListFromTailToHeadDiGui(node.next);
}
System.out.print(node.data + "<-");
}
System.out.println();
}
public static void main(String[] args) {
LinkedListOnePoint list = new LinkedListOnePoint();
System.out.println(list.isEmpty());//true
System.out.println(list.size);//0
list.display();//链表为空
list.printListFromTailToHead(list.head);//链表为空
list.insertInHead(0);
list.insertInHead(2);
list.insertInHead(3);
list.insertInHead(4);
list.insertInHead(5);
list.insertInHead(6);
list.display();
list.printListFromTailToHead(list.head);//<-6<-5<-4<-3<-2<-0
list.printListFromTailToHeadDiGui(list.head);//0<-2<-3<-4<-5<-6<-
System.out.println(list.isEmpty());//false
System.out.println(list.size);//6
System.out.println(list.containObject(2));//true
}
}
总结
- 链表包含一个linkedList对象和许多Link对象
- lingedList对象包含一个引用,这个引用通常叫做first,它指向链表的第一个链节点。
- 每个link对象半寒数据和一个引用,通常叫做next,它指向链表的下一个链节点。
- next字段为null值意味着链表的结尾。
- 在表头插入链节点需要把新的链节点的next字段指向原来的第一个链节点,然后把first指向新的链结点
- 在表头删除链节点是要把first指向first.next
- 为了遍历链表,从frist开始,然后从一个链结点到下一个链结点,方法是有每个链结点的next字段找到下一个链结点
- 通过遍历链表可以找到下一个链结点
- 通过遍历链表可以找到拥有特定值的链结点,一旦找到,可以显示,删除或用其他方式操作该链结点。
- 新链结点可以插在某个特定值的链结点,一旦找到,可以显示,删除或其他方式操作该链结点。
- 新链结点可以插在某个特定值的链结点的前面或后面,首先遍历找到这个链结点。