二、链表
2.1 单链表
2.1.1 概述
功能:遍历打印、添加到最后、按ID大小添加、根据ID进行修改、根据ID删除节点
2.1.2 代码及详细注释
package linkedlist;
import linkedlist.pojo.User;
public class UndirectionalLinkedList {
// 头指针一开始就要初始化
private Node head = new Node();
public void push(User user){
Node node = new Node(user);
Node tmp = head;
while(true){
if(tmp.next == null){
break;
}
// 注意指针后移,防止死循环
tmp = tmp.next;
}
tmp.next = node;
}
public void show(){
Node tmp = head.next;
if (tmp == null) {
System.out.println("链表为空!");
}
while(true){
if(tmp == null){
return;
}
System.out.println(tmp);
tmp = tmp.next;
}
}
public boolean insert(User user) {
Node node = new Node(user);
Node tmp = head;
boolean flag = false; // 默认插入失败
while(true){
if(tmp.next == null){
flag = true;
break;
}
if(node.user.getId() < tmp.next.user.getId()) {
flag = true;
break;
}
if(node.user.getId() == tmp.next.user.getId()) {
break;
}
tmp = tmp.next;
}
if(flag) {
node.next = tmp.next;
tmp.next = node;
}
return flag;
}
public boolean update(User user) {
Node node = new Node(user);
Node tmp = head.next;
boolean flag = false; // 默认更新失败
if(tmp == null){
System.out.println("链表为空!");
return flag;
}
while (true) {
if (tmp == null) {
break;
}
if (node.user.getId() == tmp.user.getId()) {
flag = true;
break;
}
tmp = tmp.next;
}
if(flag){
tmp.user.setName(node.user.getName());
}
return flag;
}
public boolean delete(int id) {
Node tmp = head;
boolean flag = false; // 默认删除失败
if(tmp.next == null) {
System.out.println("链表为空!");
return flag;
}
while(true) {
if(tmp.next == null) {
break;
}
if(tmp.next.user.getId() == id) {
flag = true;
break;
}
tmp = tmp.next;
}
if(flag) {
tmp.next = tmp.next.next;
}
return flag;
}
private class Node {
private User user;
private Node next;
public Node(){}
public Node(User user) {
this.user = user;
}
@Override
public String toString() {
return "Node{" +
"user=" + user +
'}';
}
}
}
2.1.3 代码2.0版(完整版)
注意:完整版对show方法进行了改造,增加了入栈、出栈、单链表的翻转、反向打印、有序合并这5个方法
package linkedlist;
import linkedlist.pojo.User;
public class UndirectionalLinkedList {
// 头指针一开始就要初始化
private Node head = new Node();
public void push(User user){
Node node = new Node(user);
Node tmp = head;
while(true){
if(tmp.next == null){
break;
}
// 注意指针后移,防止死循环
tmp = tmp.next;
}
tmp.next = node;
}
private void _show(Node head){
Node tmp = head.next;
if (tmp == null) {
System.out.println("链表为空!");
}
while(true){
if(tmp == null){
return;
}
System.out.println(tmp);
tmp = tmp.next;
}
}
public void show(){
this._show(this.head);
}
public boolean insert(User user) {
Node node = new Node(user);
Node tmp = head;
boolean flag = false; // 默认插入失败
while(true){
if(tmp.next == null){
flag = true;
break;
}
if(node.user.getId() < tmp.next.user.getId()) {
flag = true;
break;
}
if(node.user.getId() == tmp.next.user.getId()) {
break;
}
tmp = tmp.next;
}
if(flag) {
node.next = tmp.next;
tmp.next = node;
}
return flag;
}
public boolean update(User user) {
Node node = new Node(user);
Node tmp = head.next;
boolean flag = false; // 默认更新失败
if(tmp == null){
System.out.println("链表为空!");
return flag;
}
while (true) {
if (tmp == null) {
break;
}
if (node.user.getId() == tmp.user.getId()) {
flag = true;
break;
}
tmp = tmp.next;
}
if(flag){
tmp.user.setName(node.user.getName());
}
return flag;
}
public boolean delete(int id) {
Node tmp = head;
boolean flag = false; // 默认删除失败
if(tmp.next == null) {
System.out.println("链表为空!");
return flag;
}
while(true) {
if(tmp.next == null) {
break;
}
if(tmp.next.user.getId() == id) {
flag = true;
break;
}
tmp = tmp.next;
}
if(flag) {
tmp.next = tmp.next.next;
}
return flag;
}
private Node _reverse() {
if(head.next == null || head.next.next == null) { // 1个或0个不翻转
return head;
}
Node cur = head.next;
Node reverseHead = new Node();
while (cur != null) {
Node next = cur.next;
cur.next = reverseHead.next;
reverseHead.next = cur;
cur = next;
}
return reverseHead;
}
public void reverse() {
Node node = this._reverse();
head.next = node.next;
}
public void reversePrint() {
if(head.next == null) {
System.out.println("[]");
return;
}
Node node = this._reverse();
_show(node);
}
public void stackPush(User user) {
Node node = new Node(user);
node.next = head.next;
head.next = node;
}
public User stackPop() {
if (head.next == null) {
return null;
}
Node res = head.next;
head.next = res.next;
// 复制user
User user = new User();
user.setName(res.user.getName());
user.setId(res.user.getId());
return user;
}
public UndirectionalLinkedList mergeSorted(UndirectionalLinkedList otherList) {
UndirectionalLinkedList newList = new UndirectionalLinkedList();
if(otherList.head.next == null) {
newList.head.next = this.head.next;
return newList;
}
Node cur = this._reverse().next;
Node otherCur = otherList._reverse().next;
while (cur != null && otherCur != null) {
User user = new User();
if(cur.user.getId() > otherCur.user.getId()) {
user.setId(cur.user.getId());
user.setName(cur.user.getName());
cur = cur.next;
}else{
user.setId(otherCur.user.getId());
user.setName(otherCur.user.getName());
otherCur = otherCur.next;
}
newList.stackPush(user);
}
while (cur != null) {
User user = new User();
user.setId(cur.user.getId());
user.setName(cur.user.getName());
cur = cur.next;
newList.stackPush(user);
}
while (otherCur != null) {
User user = new User();
user.setId(otherCur.user.getId());
user.setName(otherCur.user.getName());
otherCur = otherCur.next;
newList.stackPush(user);
}
return newList;
}
private class Node {
private User user;
private Node next;
public Node(){}
public Node(User user) {
this.user = user;
}
@Override
public String toString() {
return "Node{" +
"user=" + user +
'}';
}
}
}
2.2 双向链表
2.2.1 概述
双向链表,相比于单向链表,既能够找前驱也能够找后驱,本次实现是双向链表的增删改查
2.2.2 代码
UserNode
package linkedlist.node;
import lombok.Data;
@Data
public class UserNode {
private Integer id;
private String name;
private UserNode next;
private UserNode pre;
public UserNode(Integer id, String name) {
this.id = id;
this.name = name;
}
public UserNode() {
}
@Override
public String toString() {
return "UserNode{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
双向链表主体
package linkedlist.dual;
import linkedlist.node.UserNode;
public class DualLinkedList {
// 头结点
private UserNode head = new UserNode();
// 尾结点
private UserNode tail = head;
private int size = 0;
public int getSize() {
return size;
}
public boolean isEmpty() {
return head == tail;
}
public void show() {
if (isEmpty()) {
System.out.println("[]");
return;
}
UserNode cur = head.getNext();
while (cur != null) {
System.out.println(cur);
cur = cur.getNext();
}
}
public void reverseShow() {
if (isEmpty()) {
System.out.println("[]");
return;
}
UserNode cur = tail;
while (cur != head) {
System.out.println(cur);
cur = cur.getPre();
}
}
public void add(UserNode newNode) {
tail.setNext(newNode);
newNode.setPre(tail);
tail = newNode;
size++;
}
public void remove(int id) {
if(isEmpty()) {
System.out.println("链表为空,删除失败");
return;
}
UserNode cur = head.getNext();
boolean flag = false; // flag为false表示没有找到该id对应的结点
while (cur != null) {
if(cur.getId() == id) {
flag =true;
break;
}
cur = cur.getNext();
}
if(flag) {
if(cur == tail) { // 如果要删除最后一个结点,需要特判
tail = tail.getPre();
tail.setNext(null);
size--;
return;
}
cur.getPre().setNext(cur.getNext()); // 当前结点前驱的后驱指向当前结点的后驱
cur.getNext().setPre(cur.getPre()); // 当前结点后驱的前驱指向当前结点的前驱
size--;
}else {
System.out.println("未找到ID="+id+"的结点");
}
}
public void update(UserNode newNode) {
if(isEmpty()) {
System.out.println("链表为空,无法进行更新操作");
return;
}
UserNode cur = head.getNext();
boolean flag = false; // flag为false表示没有找到该id对应的结点
while (cur != null) {
if(cur.getId() == newNode.getId()) {
flag =true;
break;
}
cur = cur.getNext();
}
if(flag) {
cur.setName(newNode.getName());
}else {
System.out.println("未找到待更新结点");
}
}
}
2.3 循环单向链表与约瑟夫问题
2.3.1 概述
循环单向链表一般不设置头结点,删除结点需要把所有条件考虑清楚
约瑟夫问题:
n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。
2.3.2 AC代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
CircleLinkedList circleLinkedList = new CircleLinkedList();
circleLinkedList.exitFromJosepCircle(n,m);
}
}
class CircleLinkedList {
private JosephNode head = null;
private JosephNode tail = null;
private int size = 0;
public int getSize() {
return size;
}
public boolean isEmpty() {
return head == null;
}
public void show() {
if(isEmpty()) {
System.out.println("[]");
return;
}
JosephNode cur = head;
while (true) {
System.out.println(cur);
if (cur == tail) {
break;
}
cur = cur.getNext();
}
}
public void add(JosephNode node) {
if(head == null) {
head = node;
tail = head;
tail.setNext(head);
size++;
return;
}
tail.setNext(node);
tail = node;
tail.setNext(head);
size++;
}
public void clear() {
size = 0;
head = null;
tail = null;
}
public void delete(int id) {
if(isEmpty()) {
System.out.println("该链表为空,不能删除");
return;
}
if(size == 1) { // 如果只有一个结点
clear();
return;
}
if (head.getId() == id && size > 1) { // 如果要删除第一个结点,特判
head = head.getNext();
tail.setNext(head);
size--;
return;
}
JosephNode cur = head;
JosephNode cur4next = head.getNext();
boolean flag = false; // 默认代表没找到结点
while (true) {
if(cur4next.getId() == id) {
flag = true;
break;
}
if(cur4next == tail) {
break;
}
cur = cur.getNext();
cur4next = cur4next.getNext();
}
if(flag) { // 找到了
if(cur4next == tail) {
tail = cur;
}
cur.setNext(cur4next.getNext());
size--;
}else {
System.out.println("不存在待删除的结点");
}
}
public void constructJosepCircle(int n) {
for(int i=1;i<=n;i++) {
JosephNode josephNode = new JosephNode(i);
add(josephNode);
}
}
public void exitFromJosepCircle(int n,int m) {
clear();
constructJosepCircle(n);
JosephNode cur = head;
while (size > 0) {
for(int i=0;i
cur = cur.getNext();
}
System.out.printf("%d ",cur.getId());
delete(cur.getId());
if(size > 0) {
cur = cur.getNext();
}
}
}
}
class JosephNode {
private int id;
private JosephNode next;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public JosephNode getNext() {
return next;
}
public void setNext(JosephNode next) {
this.next = next;
}
@Override
public String toString() {
return "JosephNode{" +
"id=" + id +
'}';
}
public JosephNode(int id) {
this.id = id;
}
public JosephNode() {}
}