单链表
小王子单链表
小王子有一天迷上了排队的游戏,桌子上有标号为 1-10 按顺序摆放的 10 个玩具,现在小王子想将它们按自己的喜好进行摆放。小王子每次从中挑选一个好看的玩具放到所有玩具的最前面。已知他总共挑选了 M 次,每次选取标号为 X 的玩具放到最前面,求摆放完成后的玩具标号。
给出一组输入,M=8 共计排了 8 次,这 8 次的序列为 9,3,2,5,6,8,9,8。 求最终玩具的编号序列。
过程:
1、创建初始链表
2、实现链表的删除操作
3、实现链表的插入操作
4、输出已排好序的链表
import java.util.Scanner;
public class 单链表 {
static class Node{
int data;
Node next;
Node(int data){
this.data = data;
}
}//成员类,表节点
static Node head = new Node(1);//头节点
//初始化链表
static void init() {
Node x = head;
for(int i = 1; i <= 10; i++) {
x = (x.next = new Node(i));
// x.next = new Node(i);
// x = x.next;
x.next = null;
}
}
//删除节点
static void del(int x) {
Node Befor = head;//存放一个节点前驱,方便删除元素
for(Node T = head.next; T != null; T = T.next) {
if(T.data == x) {//找到要删除的数
Node temp = T;//临时节点保存节点
Befor.next = T.next;//将节点从链表上删除
return;//删除后结束函数
}
Befor = T;
}
}
//插入元素(头插法)
static void insert(int x) {
Node temp = new Node(x);
temp.next = head.next;
head.next = temp;
}
//显示链表
static void show(int x) {
//System.out.println("这是第"+x+"次操作");
for(Node T = head.next; T != null; T = T.next) {
System.out.print(T.data + " ");
}
System.out.println();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int N;
Scanner in = new Scanner(System.in);
init();
//show(0);
N = in.nextInt();
for(int i = 1; i <= N; i++) {
int x = in.nextInt();
del(x);
insert(x);
show(i);
}
}
}
循环链表
约瑟夫环问题
设有 n 个人围坐在圆桌周围,现从某个位置 k(1≤k≤n) 上的人开始报数,报数到 m 的人就站出来。下一个人,即原来的第 m+1 个位置上的人,又从 1 开始报数,再报数到 m 的人站出来。依次重复下去,直到全部的人都站出来为止。试设计一个程序求出这 n 个人的出列顺序。
- 要求一:采用循环链表解决
- 要求二:可以使用模拟法,模拟循环链表
- 要求三:可以不使用循环链表类的定义使用方式
分析:和上一个创建链表几乎一样,只不过让末尾的节点指向头节点以形成循环链表。
即x.next = head。
import java.util.Scanner;
public class 循环链表 {
static class Node{
int val;
Node next;
Node(int val){
this.val = val;
}
}
public static void main(String[] args) {
int N, M, K; //n个人从第k个位置报数,数到m出列
Scanner in = new Scanner(System.in);
N = in.nextInt();
K = in.nextInt();
M = in.nextInt();
Node head = new Node(1);//头节点单列出来,方便形成循环链表
Node x = head;
//初始化循环链表
for(int i = 2; i <= N; i++) {
x = (x.next = new Node(i));
x.next = head;//形成循环链表
}//此时,x指向末尾节点
//寻找报数起点
for(int i = 1; i < K; i++) {
x = x.next;//此时,x指向第k-1个节点
}
//报数,出环
while(x != x.next) {//只剩下一个节点的时候停止
for(int i = 1; i < M; i++) {
x = x.next;
}//此时,x指向要删除节点的前一个节点
System.out.println(x.next.val + " ");
x.next = x.next.next;//删除节点
}
//输出最后一个节点值
System.out.println(x.val);
}
}
双向链表
小王子双链表
与单链表题目相同,用双向链表实现。
重点在于节点有两个指针域:next和before。next指向节点的下一个节点,before指向节点的前一个节点。即x.next.befor = x,这样就可形成双向。在小王子问题中,这样做的时候,删除节点的时候就不必在new一个节点保存前驱节点,直接就能找到。
import java.util.Scanner;
public class 双向链表 {
static class Node{
int data;
Node next;
Node befor;
Node(int data){
this.data = data;
}
}
static Node head = new Node(1);//头节点
//初始化链表
static void init() {
Node x = head;
for(int i = 1; i <= 10; i++) {
x.next = new Node(i);//建立双向链表
x.next.befor = x;
x = x.next;
}
x.next = null;
}
//删除节点
static void del(int x) {
for(Node T = head.next; T != null; T = T.next) {
if(T.data == x) {//找到删除的节点
T.befor.next = T.next;//将节点x从链表上摘除
T.next.befor = T.befor;//虽删除,但T的左右指针还指向之前指向的节点
return;//删除节点后,结束函数
}
}
}
//插入节点(头插)
static void insert(int x) {
Node temp = new Node(x);
temp.next = head.next;
temp.next.befor = temp;
head.next = temp;
temp.befor = head;//头节点的next的before也指向头节点,在本题中,写不写均可
}
//显示链表
static void show(int x) {
//System.out.println("这是第" + x + "次操作");
for(Node T = head.next; T != null; T = T.next) {
System.out.print(T.data + " ");
}
System.out.println();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int N;
Scanner in = new Scanner(System.in);
init();
//show(0);
N = in.nextInt();
for(int i = 1; i <= N; i++) {
int x = in.nextInt();
del(x);
insert(x);
show(x);
}
}
}