概述
- 链表是以节点的方式来存储
- 每个节点包含data域(存储有效数据),next域(指向下一个节点)
- 链表的各个节点不一定是连续存储的
- 链表分带头节点的链表和没有头节点的链表,根据实际的需求确定
逻辑结构
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5ed5621246e4d47118ec49a4d013d4ec.png)
代码实现
class SingleLinkedList {
private Node head = new Node(0, "", "");
public void add(Node node) {
Node helper = head;
while (true) {
if (helper.next != null) {
helper = helper.next;
} else {
break;
}
}
helper.next = node;
}
public void list() {
if (head.next == null) {
System.out.println("链表为空");
return;
}
Node helper = head.next;
while (true) {
System.out.println(helper);
if (helper.next != null) {
helper = helper.next;
} else {
break;
}
}
}
public void addByOrder(Node node) {
Node helper = head;
boolean isExist = false;
while (true) {
if (helper.next == null) {
break;
}
if (helper.next.no > node.no) {
break;
} else if (helper.next.no == node.no) {
isExist = true;
break;
}
helper = helper.next;
}
if (isExist) {
System.out.printf("编号为%d节点已存在\n",node.no);
} else {
node.next = helper.next;
helper.next = node;
}
}
public void update(Node node) {
Node helper = head;
boolean isExist = false;
while(true) {
if(helper.next==null) {
break;
}else if(helper.next.no==node.no) {
isExist = true;
break;
}
helper = helper.next;
}
if(isExist) {
helper.next.name = node.name;
helper.next.nickName = node.nickName;
}else {
System.out.printf("没有找到编号为%d的节点\n",node.no);
}
}
public void delete(int no) {
Node helper = head;
boolean isExist = false;
while(true) {
if(helper.next==null) {
break;
}else if(helper.next.no==no) {
isExist=true;
break;
}
helper = helper.next;
}
if(isExist) {
helper.next = helper.next.next;
}else {
System.out.printf("编号为%d的节点不存在",no);
}
}
}
class Node {
int no;
String name;
String nickName;
Node next;
public Node(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
this.next = null;
}
@Override
public String toString() {
return "no=" + no + "\tname=" + name + "\tnickName=" + nickName;
}
}
单链表相关面试题
求单链表中有效节点个数
public static int getSize(Node node) {
Node helper = node;
int num = 0;
while(true) {
if(helper.next==null) {
break;
}
num++;
helper = helper.next;
}
return num;
}
查找单链表中倒数第k个节点
public static int getSize(Node node) {
Node helper = node;
int num = 0;
while(true) {
if(helper.next==null) {
break;
}
num++;
helper = helper.next;
}
return num;
}
public static void deleteByLastIndex(Node node,int index) {
if(node.next==null) {
System.out.println("链表为空");
return;
}
int size = getSize(node);
if(index<1||index>size) {
System.out.printf("倒数第%d个节点不存在",index);
return;
}
Node helper = node;
int current=0;
while(true) {
if(current==size-index) {
helper.next = helper.next.next;
break;
}
helper = helper.next;
current++;
}
}
将链表反转
public static void reverseLinkedList(Node head) {
Node newHeadNode = new Node(0,null,null);
Node current = head.next;
Node helper = null;
while(current!=null) {
helper = current;
current = current.next;
helper.next = newHeadNode.next;
newHeadNode.next = helper;
}
head.next = newHeadNode.next;
}
从尾到头打印单链表
- 方式一:先将链表反转,再遍历,但这种方式破环了链表的原有结构,或是可以克隆原有节点创建一个新的反转的链表,但是会损耗大量空间
- 方式二:使用栈结构,先依次将链表中的所有元素入栈,再将栈中的元素依次出栈打印,利用栈的先进后出的特点,来实现链表的逆序打印
public static void reversePrint(Node head) {
if(head.next==null) {
System.out.println("链表为空");
return;
}
Stack<Node> stack = new Stack<>();
Node helper = head;
while(helper.next!=null) {
stack.add(helper.next);
helper = helper.next;
}
System.out.println("逆序打印的结果为");
while(!stack.isEmpty()) {
System.out.println(stack.pop());
}
}
合并两个有序的单链表,要求合并之后链表依然有序
public static Node orderMerge(Node head1, Node head2) {
Node current1 = head1.next;
Node current2 = head2.next;
Node helper = null;
Node newHead = new Node(0, null, null);
Node helper2 = newHead;
while (current1 != null && current2 != null) {
if (current1.no > current2.no) {
helper = current2;
current2 = current2.next;
} else {
helper = current1;
current1 = current1.next;
}
helper.next = helper2.next;
helper2.next = helper;
helper2 = helper2.next;
}
if (current1 != null) {
helper2.next = current1;
}
if (current2 != null) {
helper2.next = current2;
}
return newHead;
}