單鏈表相關算法的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