1.将两个有序单链表合并成一个有序单链表
实现步骤:
(1)获得head1和head2中数据值较小的节点,并设置为合并后链表的首节点。
(2)通过循环循环依次获得链表1和链表2中数据较小 的节点,并添加到合并链表的末尾 。
(3)当步骤2执行完毕,如果某一链表中的首节点不为null,则将该链表首节点及其之后的节点添加到合并后链表的末尾。
public class MergeSingleLinkList {
public static void main(String[] args) {
//创建两个单链表
//链表1
Node node1_4 = new Node(289);
Node node1_3 = new Node(186, node1_4);
Node node1_2 = new Node(167, node1_3);
Node node1_1 = new Node(103, node1_2);
//链表2
Node node2_4 = new Node(228);
Node node2_3 = new Node(147, node2_4);
Node node2_2 = new Node(134, node2_3);
Node node2_1 = new Node(67, node2_2);
//测试合并两个有序单链表
Node headNode = mergeList(node1_1, node2_1);
print(headNode);
}
/*
实现单链表的遍历操作
*/
public static void print(Node headNode){
//定义一个临时节点,用于辅助单链表的遍历操作
Node tempNode=headNode;
//定义一个循环,用于实现单链表的遍历操作
while(tempNode!=null){
//输出tempNode中保存的数据值
System.out.println(tempNode.data);
//让tempNode指向它的下一个节点
tempNode=tempNode.next;
}
}
/*
实现节点类
*/
private static class Node{
/*
用于保存节点中的数据
*/
private int data;
/*
用于保存下一个节点的地址值
*/
private Node next;
/*
为data做初始化的工作
*/
public Node(int data){
this.data=data;
}
public Node(int data,Node next){
this.data=data;
this.next=next;
}
}
public static Node mergeList(Node head1,Node head2){
//1.head1和head2都为null
if(head1 == null && head2 == null){
return null;
}
//2.head和head2只有一个为null
if(head1==null){
return head2;
}
if(head2==null){
return head1;
}
//3.定义headnode和lastnode,分别作为合并后链表的首节点或尾结点
Node headNode=null,lastNode=null;
//4.获取head1和head2中数据值较小的节点,并设置为合并后链表的首节点和尾结点。
if(head1.data>head2.data){
headNode=head2;
lastNode=head2;
//更新head2的值,让head2指向head2的下一个节点
head2=head2.next;
}else{
headNode=head1;
lastNode=head1;
head1=head1.next;
}
//5.定义一个循环,用于依次的获取链表1和链表2中数据值较小的节点,并把该节点添加到合并后链表的末尾。
while(head1!=null && head2 !=null){
//处理head1的数据值大于head2的情况
if(head1.data>head2.data){
lastNode.next=head2;
lastNode=head2;
//更新head2的值
head2=head2.next;
}else{
lastNode.next=head1;
lastNode=head1;
head1=head1.next;
}
}
//6.循环执行完毕,如果某个链表的首节点不为null,那么我们将这个链表的首节点及其之后的节点添加到合并后的链表的末尾
if(head1==null){
lastNode.next=head2;
}else{
lastNode.next=head1;
}
//7.返回合并后链表的首节点
return headNode;
}
}
2.如何判断一个单链表有环
实现步骤:
(1)定义一个fast和slow指针,指针的初始值都设为单链表的头结点
(2)让fast指针每次向后走两步,slow指针每次向后走一步。
(3)循环执行步骤2,如果fast指向的节点为null或者fast指向节点的后一个节点为null,则证明单链表无环。如果fast指针和slow指针指向了同一个节点,则证明单链表有环。
public class JudgeHasCycle {
public static void main(String[] args) {
//1.创建一个单链表
Node lastNode=new Node(55);
Node node4=new Node(44,lastNode);
Node node3=new Node(33,node4);
Node node2=new Node(22,node3);
Node headNode=new Node(11,node2);
lastNode.setNext(node2);
//2.判断是否有环
boolean flag=hasCycle(headNode);
System.out.println(flag);
}
public static boolean hasCycle(Node headNode){
//1.如果headNode为null的情况
if(headNode==null){
return false;
}
//2.定义一个快指针,每次往后走两步
Node fast=headNode;
//3.定义一个慢指针,每次往后走一步
Node slow=headNode;
//4.定义一个循环,用于判断单链表是否有环
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
//5.如果fast和slow指向同一个节点,则证明单链表有环
if(fast==slow){
return true;
}
}
//7.否则,单链表无环
return false;
}
private static class Node{
private int data;
private Node next;
public Node(int data){
this.data=data;
}
public Node(int data,Node next){
this.data=data;
this.next=next;
}
public void setNext(Node next) {
this.next=next;
}
}
}
3.如果存在两个单链表相交的结果,请找出相交节点并返回。
实现步骤:
(1)获得以head1为首节点的单链表长度,记为length1;以head2为首节点的单链表长度,记为length2;
(2)定义longNode指针,用于指向长度较长的单链表的首节点;定义shortNode指针,用于指向长度较短的单链表的首节点。
(3)让longNode指针往后移动Math.abs(length1-length2)次。
(4)定义一个循环,每次让longNode指针和shorNode指针往后移动一次,当longNode指针和shortNode指向同一个节点时,那么就停止循环操作,LongNode指针和shortNode指针指向的节点就是两个单链表相交的第一个节点。
public class SingleLinkIntersect {
public static void main(String[] args) {
//1.创建两个单链表
Node lastNode=new Node(77);
Node node6=new Node(66,lastNode);
Node node3=new Node(33,node6);
Node node2=new Node(22,node3);
Node head1=new Node(11,node2);
Node node5=new Node(55,node6);
Node head2=new Node(44,node5);
Node commonNode=getFirstCommonNode(head1,head2);
System.out.println(commonNode.getData());
}
public static Node getFirstCommonNode(Node head1,Node head2){
//1.处理head1和head2为Null的情况
if(head1==null || head2==null){
return null;
}
//2.获得以head1为首节点的单链表长度
int length1=getLength(head1);
//3.获得以head2位首节点的单链表长度
int length2=getLength(head2);
//4.定义LongNode指针,用于指向长度较长的单链表的首节点
Node longNode=length1>length2 ? head1:head2;
//5.定义shortNode指针,用于指向长度较短的单链表的首节点
Node shortNode=length1>length2 ? head2:head1;
//6.让LongNode指针往后移动Math.abs(length1-length2)次
for(int i=0;i<Math.abs(length1-length2);i++){
longNode=longNode.getNext();
}
//7.定义一个循环,每次让longNode和shortNode往后移动一次
while(longNode!=shortNode){
longNode=longNode.next;
shortNode=shortNode.next;
}
//8.返回两个单链表的相交节点
return longNode;
}
public static int getLength(Node headNode){
//1.定义一个变量,用于保存单链表的长度
int length=0;
//2.定义一个循环,用于实现单链表的遍历操作
Node tempNode=headNode;
while(tempNode!=null){
tempNode=tempNode.getNext();
//3.更新length的值
length++;
}
//4.返回单链表的长度
return length;
}
public static class Node{
private int data;
private Node next;
public Node(int data){
this.data=data;
}
public Node(int data,Node next){
this.data=data;
this.next=next;
}
public void setNext(Node next){
this.next=next;
}
public Node getNext() {
return next;
}
public int getData() {
return data;
}
}
}
4.输出单链表的倒数第k个节点
实现步骤:
(1)定义first指针和second指针,并且设置他们的初始值为单链表的首节点。
(2)通过循环,让first指针往后移动k-1次。
(3)通过循环,把fist指针和second指针往后移动一次。当first指针指向的节点是单链表的尾结点时,那么就停止移动。此时,second的指针指向的节点就是单链表倒数第k个节点。
public class Print_DKNode {
public static void main(String[] args) {
Node lastNode=new Node(55);
Node node4=new Node(44,lastNode);
Node node3=new Node(33,node4);
Node node2=new Node(22,node3);
Node head=new Node(11,node2);
Node node=Print_dkNode(head,5);
System.out.println(node.getData());
}
public static Node Print_dkNode(Node headNode,int k){
//1.处理headNode为Null的情况
if(headNode==null){
throw new NullPointerException("headNode为null");
}
//此处k的合法取值范围:[1,单链表长度]
//2.定义first指针和second指针,并且设置他们的初始值为单链表的首节点
Node first=headNode;
Node second=headNode;
//3.通过循环,让first指针往后移动k-1次。
for(int i=0;i<k-1;i++){
first=first.getNext();
}
//4.通过循环,每次让first和second往后移动一次,当first指针指向单链表的尾结点时,那么就停止移动,此时,second指针指向的节点就是单链表的倒数第k个节点。
while(first.getNext()!=null){
first=first.getNext();
second=second.getNext();
}
//5.返回倒数第k个节点
return second;
}
public static class Node{
private int data;
private Node next;
public Node(int data){
this.data=data;
}
public Node(int data,Node next){
this.data=data;
this.next=next;
}
public void setNext(Node next){
this.next=next;
}
public Node getNext(){
return next;
}
public void setData(int data){
this.data=data;
}
public int getData(){
return data;
}
}
}
5.单链表的反转
实现步骤:
(1)定义一个节点,用于保存反转后链表的首节点。
(2)把原链表的首节点插入到反转后链表的最前面。
(3)更新原链表和反转后链表的首节点。
(4)循环中执行步骤(2)和步骤(3),直到原链表中的首节点为null时停止。
public class ReverseSingleLinkList {
public static void main(String[] args){
//1.创建一个单链表
Node lastNode=new Node(44);
Node node3=new Node(33,lastNode);
Node node2=new Node(22,node3);
Node headNode=new Node(11,node2);
System.out.println("反转之前的链表");
print(headNode);
System.out.println();
Node reverse=reverseLinkList(headNode);
System.out.println("反转之后的链表");
print(reverse);
}
/*
实现单链表的反转
*/
public static Node reverseLinkList(Node headNode){
//1.判断headNode为Null和单链表只有一个节点的情况
if(headNode==null || headNode.getNext()==null){
return headNode;
}
//2.定义一个节点,用于保存反转后链表的首节点
Node reverse=null;
//3.定义一个循环,用于实现单链表的反转操作
while(headNode!=null){
//4.获得HeadNode的下一个节点
Node nextNode=headNode.getNext();
//5.把headNode插入到反转后链表的最前面
headNode.setNext(reverse);
//6.更新反转后链表的首节点
reverse=headNode;
//7.跟新需要反转链表的首节点
headNode=nextNode;
}
//8.返回反转后链表的首节点
return reverse;
}
/*实现单链表的遍历操作
*/
public static void print(Node headNode){
//1.定义一个临时节点,用于辅助单链表的便利操作
Node tempNode=headNode;
//2.定义一个循环,用于实现单链表的遍历操作
while(tempNode!=null){
//3.输出tempNode中保存的数据值
System.out.println(tempNode.getData());
//4.让它的tempNode指向他的下一个节点
tempNode=tempNode.getNext();
}
}
public static class Node(){
private int data;
private Node next;
public Node(int data){
this.data=data;
}
public Node(int data,Node next){
this.data=data;
this.next=next;
}
public void setNext(Node next){
this.next=next;
}
public Node getNext(){
return next;
}
public void setData(int data){
this.data=data;
}
public int getData(){
return data;
}
}
}
6.从未到头打印单链表
实现步骤:
(1)创建一个栈
(2)从头到尾遍历链表,然后将遍历出来的节点依次存入栈中
(3)遍历并打印输出栈中的所有节点
import java.util.Stack;
public class print_SingleLinkList {
public static void main(String[] args) {
//1.创建一个单链表
Node lastNode=new Node(44);
Node node1=new Node(33,lastNode);
Node node2=new Node(22,node1);
Node headNode=new Node(11,node2);
reversePrint(headNode);
}
public static void reversePrint(Node headNode){
//1.处理headNode为null的情况
if(headNode==null){
throw new NullPointerException("headNode为null");
}
//2.创建一个栈
Stack<Node> stack=new Stack<>();
//3.遍历单链表中的所有节点
Node tempNode=headNode;
while(tempNode!=null){
//4.把遍历出来的节点添加进入栈中
stack.push(tempNode);
tempNode=tempNode.getNext();
}
//5.遍历栈中的所有节点
while(!stack.isEmpty()){
Node node=stack.pop();
System.out.println(node.getData());
}
}
}
7.判断一个链表是否是回文结构
实现步骤:
(1)使用一个辅助栈,第一次遍历链表的时候,把所有元素存入栈中。
(2)第二次遍历链表,依次取出栈中元素,然后比较元素的值是否相等。
import java.util.Stack;
public class Justy_isPalindrome {
public static void main(String[] args){
//1.创建一个单链表
Node lastNode=new Node(1);
Node node3=new Node(2,lastNode);
Node node2=new Node(2,node3);
Node headNode=new Node(1,node2);
boolean flag=isPalindRome(headNode);
System.out.println(flag);
}
public static boolean isPalindRome(Node headNode){
//1.判断单链表为null的情况
if(headNode==null){
throw new NullPointerException("headNode为null");
}
//2.第一次遍历单链表,把节点保存入栈中
Stack<Node> stack=new Stack<>();
Node tempNode=headNode;
while(tempNode!=null){
stack.push(tempNode);
tempNode=tempNode.getNext();
}
//3.第二次遍历单链表,依次取出栈中元素,然后对比元素是否相等
while(headNode!=null){
if(headNode.data!=stack.pop().data){
return false;
}
headNode=headNode.getNext();
}
return true;
}
}