單鏈表
概述
功能:遍歷打印、添加到最后、按ID大小添加、根據ID進行修改、根據ID刪除節點
代碼及詳細注釋
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.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 +
'}';
}
}
}
雙向鏈表
概述
雙向鏈表,相比於單向鏈表,既能夠找前驅也能夠找后驅,本次實現是雙向鏈表的增刪改查
代碼
- 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("未找到待更新結點");
}
}
}
循環單向鏈表與約瑟夫問題
概述
- 循環單向鏈表一般不設置頭結點,刪除結點需要把所有條件考慮清楚
- 約瑟夫問題:
n 個人圍成一圈,從第一個人開始報數,數到 m 的人出列,再由下一個人重新從 1 開始報數,數到 m 的人再出圈,依次類推,直到所有的人都出圈,請輸出依次出圈人的編號。
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<m-1;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() {}
}