单链表相关算法的java代码 ,欢迎提出意见和建议!
public class ListNode {
private ListNode(int value){
this.value=value;
}
private int value; // 链表节点值
private ListNode next ; // 下一个节点
public static void main(String[] args) {
ListNode node1 = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
ListNode node5 = new ListNode(5);
ListNode node6 = new ListNode(109);
System.out.println("**************构造链表***************");
node1.next=node2;
node2.next=node3;
node3.next=node4;
node4.next=node5;
node5.next=node6;
System.out.println("**************原始链表***************");
printList(node1);
System.out.println("**************反转链表***************");
ListNode head = reverseList(node1);
printList(head);
System.out.println("**************复制链表***************");
ListNode copyList = copyList(node1);
printList(copyList);
System.out.println("**************原始链表***************");
printList(node1);
System.out.println("**************合并链表***************");
ListNode mergeList = mergeList(node1,copyList);
printList(mergeList);
System.out.println("**************是否相交***************");
System.out.println(isIntersect(node1,node4));
System.out.println("**************是否有环***************");
// node1.next.next.next=node3; // 模拟环
System.out.println(existsCycle(node6));
System.out.println(existsCycle(node1));
System.out.println("**************环入口节点值***************");
ListNode enter = enterNode(node1);
System.out.println(enter == null?null:enter.value);
System.out.println("**************插入有序***************");
ListNode orderHead = insertNode(node1,6);
printList(orderHead);
System.out.println("**************倒数K节点***************");
ListNode lastkNode = findLastKNode(node1,7);
System.out.println(lastkNode== null?null:lastkNode.value);
}
/**
* 打印单链表
* @param head 头节点
*/
private static void printList(ListNode head){
while(head != null){
System.out.println(head.value);
head = head.next;
}
}
/**
* 反转链表
* @param head 原头节点
* @return 新头节点
*/
private static ListNode reverseList(ListNode head){
if(head == null ) return null;
ListNode newList = new ListNode(head.value); // 新链表头节点
while( head.next != null ){
ListNode temp = new ListNode(head.next.value); // 不能直接用里面的节点,否则出现死循环
temp.next = newList;
newList = temp;
head = head.next;
}
return newList;
}
/**
* 复制单链表(为了判断没干扰到原来的链表,加100进行测试)
* @param head 原来链表头节点
* @return 新链表头节点
*/
private static ListNode copyList(ListNode head){
if(head == null) return null;
ListNode newHead = new ListNode(head.value+100);
ListNode newHead1 = newHead ; // 新链表的头节点
while (head.next != null ){
ListNode temp = new ListNode(head.next.value+100);
newHead.next = temp;
newHead = newHead.next;
head = head.next;
}
return newHead1;
}
/**
* 合并两个有序链表
* @param n1 第一个链表节点
* @param n2 第二个链表节点
* @return 新链表头节点
*/
private static ListNode mergeList(ListNode n1,ListNode n2){
if( n1 == null ) return n2;
if( n2 == null ) return n1;
ListNode head = null;
ListNode head1 = head;
while(n1 != null && n2 != null) {
ListNode node = null;
if (n1.value <= n2.value) {
node = new ListNode(n1.value);
n1 = n1.next;
} else {
node = new ListNode(n2.value);
n2 = n2.next;
}
if (head == null) {
head = node;
head1 = head;
}
else {
head.next=node;
head = head.next;
}
}
if (n1 != null ){ // 把剩余的链表接上去
head.next= n1;
}
if (n2 != null ){ // 把剩余的链表接上去
head.next = n2;
}
return head1;
}
/**
* 判断两个链表是否相交
* @param n1 链表1
* @param n2 链表2
* @return 相交返回true 否则返回false
*/
private static boolean isIntersect(ListNode n1,ListNode n2){
if(n1 == null || n2 == null){
return true;
}
int len1 = 0;
int len2 = 0;
ListNode nn1 = n1;
ListNode nn2 = n2;
// 计算链表长度
while (nn1 != null){
len1 ++;
nn1 = nn1.next;
}
// 计算链表长度
while (nn2 != null){
len2 ++;
nn2 = nn2.next;
}
// 先让链表往前走一段 剩余相同的长度 开始遍历
if( len1 >= len2 ){
int count = len1-len2;
for (int i = 0; i < count ; i++) {
n1 = n1.next;
}
}
else {
int count = len2-len1;
for (int i = 0; i < count ; i++) {
n2 = n2.next;
}
}
while (n1 != null){
if(n1 == n2){
return true;
}
else {
n1=n1.next;
n2=n2.next;
}
}
return false;
}
/**
* 是否存在环
* @param head 头节点
* @return 存在返回true 否则返回false
*/
private static boolean existsCycle(ListNode head){
if( head == null ) return false;
ListNode slow = head;
ListNode fast = head;
// 快慢指针 快指针一下子走两步 慢指针一次一步
while ((slow = slow.next) != null && (fast = fast.next.next) != null){
if(slow == fast){
return true;
}
}
return false;
}
/**
* 环入口节点
* @param head 头节点
* @return 存在返回true 否则返回false
*/
private static ListNode enterNode(ListNode head){
if( head == null ) return null;
ListNode slow = head;
ListNode fast = head;
// 快慢指针往前走 如果快指针的下个节点为空了 证明没环
// 设 头节点到环入口的长度为 y 相遇点距离 入口为 x 环长度为 r 快指针走了n圈
// 则 快指针走过的路程是慢指针的两倍 2(x+y)=nr+x+y
// 化简 y=nr=x
// 继续 y=(n-1)r+(r-x) r-x 为 相遇点到环入口点的长度
// 这时候 快指针从头开始走 慢指针也开始一步步走 必会相遇
// y - (r-x) = (n-1)r
while ((slow = slow.next) != null && (fast = fast.next.next) != null){
if(slow == fast){
fast = head;
break;
}
}
// 不存在环的时候报错问题
if(fast != null ){
// 快指针回到头部 开始每次走一步
while ((slow = slow.next) != null && (fast = fast.next) != null){
if(slow == fast){
return slow;
}
}
}
return null;
}
/**
* 有序单向循环链表插入结点
* @param head 有序链表头节点
* @param number 插入的值
*/
private static ListNode insertNode(ListNode head,int number){
// 当空链表 或者插入的值比第一个小的时候
if( head == null || number <= head.value) {
ListNode newHead = new ListNode(number);
if(head != null){
newHead.next=head;
}
return newHead;
}
// 其他情况还返回老的链表的头节点
ListNode oldHead = head;
while (head != null){
int temp = head.value;
if(temp <= number){
if(head.next != null) { // 是否走到头了
if(head.next.value >= number){ // 找到插入位置了
ListNode tmpNode = new ListNode(number);
tmpNode.next = head.next;
head.next= tmpNode;
return oldHead;
}
}
else { // 链表尾部了
ListNode tmpNode = new ListNode(number);
head.next = tmpNode;
}
}
// 继续向后查找
head = head.next;
}
return oldHead;
}
/**
* 查找链表的倒数第K个节点
* @param head 头节点
* @param pos 位置
* @return 倒数位置
*/
public static ListNode findLastKNode(ListNode head,int pos){
if(head == null || pos < 0){
return null;
}
else {
int i = 0; // 位置初始化为 1
ListNode result = head;
while (head != null ){
// 让快指针先走 n 步
if(i >= pos){
result = result.next;
}
head = head.next;
i++;
}
// 判断是否超过链表长度
if(i < pos){
return null;
}
return result;
}
}
}
输出
**************原始链表***************
1
2
3
4
5
109
**************反转链表***************
109
5
4
3
2
1
**************复制链表***************
101
102
103
104
105
209
**************原始链表***************
1
2
3
4
5
109
**************合并链表***************
1
2
3
4
5
101
102
103
104
105
109
209
**************是否相交***************
true
**************是否有环***************
false
false
**************环入口值***************
null
**************插入有序***************
1
2
3
4
5
6
109
**************倒数K节点***************
1