java链表 作用_链表详解(Java实现)

二、链表

2.1 单链表

2.1.1 概述

功能:遍历打印、添加到最后、按ID大小添加、根据ID进行修改、根据ID删除节点

2.1.2 代码及详细注释

package linkedlist;

import linkedlist.pojo.User;

/**

* @author: doudou

* @date: Created in 2020/3/31

* @description:

* @version: 1.0

*/

public class UndirectionalLinkedList {

// 头指针一开始就要初始化

private Node head = new Node();

/**

* push方法,将元素放到链表的末尾

* @param user

*/

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;

}

}

/**

* 按照id,升序插入到特定位置

* 如果有重复的元素,则插入失败

* @param user

* @return

*/

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;

}

/**

* 根据user的id更新元素

* @param user

* @return

*/

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;

}

/**

* 根据id删除元素

* @param id

* @return

*/

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;

/**

* @author: doudou

* @date: Created in 2020/3/31

* @description:

* @version: 1.0

*/

public class UndirectionalLinkedList {

// 头指针一开始就要初始化

private Node head = new Node();

/**

* push方法,将元素放到链表的末尾

* @param user

*/

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);

}

/**

* 按照id,升序插入到特定位置

* 如果有重复的元素,则插入失败

* @param user

* @return

*/

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;

}

/**

* 根据user的id更新元素

* @param user

* @return

*/

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;

}

/**

* 根据id删除元素

* @param id

* @return

*/

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);

}

/**

* 添加一个元素到链表的第一个位置,入栈

* @param user 待入栈的元素

*/

public void stackPush(User user) {

Node node = new Node(user);

node.next = head.next;

head.next = node;

}

/**

* 将链表的第一个元素出栈

* @return

*/

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;

}

/**

* 有序合并两个链表(两个链表都为从小到大排列的,合并后也为从小到大排列) O(n)

* @param otherList 要与this合并的链表

* @return 新的链表

*/

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;

/**

* @author: doudou

* @date: Created in 2020/4/12

* @description:

* @version: 1.0

*/

@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;

/**

* @author: doudou

* @date: Created in 2020/4/12

* @description: 带头结点的双向链表

* @version: 1.0

*/

public class DualLinkedList {

// 头结点

private UserNode head = new UserNode();

// 尾结点

private UserNode tail = head;

private int size = 0;

/**

* 获取双向链表有效结点的数量

* @return 有效结点的数量

*/

public int getSize() {

return size;

}

/**

* 判空

* @return 如果为空,则返回为true

*/

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();

}

}

/**

* 增加新结点

* @param newNode

*/

public void add(UserNode newNode) {

tail.setNext(newNode);

newNode.setPre(tail);

tail = newNode;

size++;

}

/**

* 根据ID删除结点,如果要删除的是最后一个结点,一定要小心

* @param id 要删除结点的id

*/

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+"的结点");

}

}

/**

* 更新结点

* @param newNode 利用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;

/**

* @author: doudou

* @date: Created in 2020/4/12

* @description:

* @version: 1.0

*/

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;

/**

* 获取循环单向链表的长度

* @return

*/

public int getSize() {

return size;

}

/**

* 判空

* @return

*/

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();

}

}

/**

* 增加新结点

* @param node 新增加的结点

*/

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;

}

/**

* 根据ID删除结点

* @param id

*/

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("不存在待删除的结点");

}

}

/**

* 生成约瑟夫环

* @param n 1-n

*/

public void constructJosepCircle(int n) {

for(int i=1;i<=n;i++) {

JosephNode josephNode = new JosephNode(i);

add(josephNode);

}

}

/**

* 打印出圈顺序

* @param n 1-n

* @param m 数到m出圈

*/

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() {}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值