轉載注明!! https://blog.csdn.net/qq_31842777/article/details/90610469
涉及:
連結清單建立、計算連結清單長度、周遊列印連結清單、插入、删除結點、連結清單反轉、合并兩個有序連結清單結果仍為有序連結清單、從尾到頭列印連結清單。
直接上代碼(含測試):
import java.util.Stack;
/*
*連結清單基本操作
*面試算法題
*/
public class MyLinkedList {
//定義頭結點
public Node head;
//定義結點類
public static class Node{//類必須是static,後面測試會用到此類建立執行個體
int data;
Node next;
Node(){}
Node(int data){
this.data=data;
}
}
/*
*以下是表的基本操作
*/
//添加結點,以建立連結清單 周遊連結清單到尾結點,然後添加結點
public void addNode(Node node) {
Node temp=head;
//以下操作找到連結清單的尾結點,然後插入
while(temp.next!=null) {
temp=temp.next;
}
//如果temp.next為空,即到尾結點,加入新結點
temp.next=node;
}
//擷取連結清單長度 從頭周遊連結清單
public int getLength(Node head) {
if(head==null) {
return 0;
}
Node temp=head;
int length=1;
while(temp.next!=null) {
length++;
temp=temp.next;
}
return length;
}
/*
* 以下是算法題
*/
//1.從node周遊并列印連結清單
/*
* 如果head為空,傳回空
* 如果head不為空,周遊并列印
*/
public static void print(Node node) {
if(node==null) {
return;
}
Node temp=node;
while(temp!=null) {
System.out.print("-->"+temp.data);
temp=temp.next;
}
System.out.println();
}
//2.插入操作:在指定位置插入結點
/*
* 連結清單下标從1開始
* index允許的範圍是(1,getLength(head)+1]
* 如:長度為7的連結清單
*/
public void insertByIndex(int index,Node node) {
if(index<1||index>getLength(head)+1) {
return;
}
Node temp=head;
int length=1;
while(temp.next!=null) {
if((index-1)==length++) {//如插入到第4位,需在第三位開始操作,交換next值
node.next=temp.next;
temp.next=node;
}
temp=temp.next;
}
}
//3.删除操作
public void deleteByIndex(int index) {
if(index<1||index>getLength(head)) {
return;
}
Node temp=head;
int length=1;
while(temp.next!=null) {
if((index-1)==length++) {
temp.next=temp.next.next;
}
temp=temp.next;
}
}
//!!!插入删除不能插入删除第一個和最後一個結點,待優化!!!
//4.連結清單反轉
/**
* 連結清單翻轉操作的順序對于疊代來說是從鍊頭往鍊尾,而對于遞歸是從鍊尾往鍊頭
* 遞歸方式:遞歸,在反轉目前節點之前先反轉後續節點
* 非遞歸方式:周遊,将目前結點的下一個結點緩存後更改目前結點指針
*/
//非遞歸實作
public static Node reverseList(Node head) {
if (head == null || head.next == null) {
return head;
}
Node current=head;
Node newHead=null;//反轉後新連結清單的表頭
Node next=null;//定義目前節點的下一個結點
while(current!=null) {
next=current.next;//儲存目前結點的下一個結點,下次循環要用,因為後續操作會破壞current.next
current.next=newHead;//current目前結點指向newHead
//操作結束,current結點後移
newHead=current;
current=next;
}
return newHead;
}
//遞歸實作
public static Node reverseListRec(Node head) {
if(head==null||head.next==null) {
return head;
}
Node newHead=reverseListRec(head.next);//找到最後一個結點,并指派給newHead
head.next.next=head;//新連結清單指向目前結點
head.next=null;//置空目前結點的下一個結點,避免形成環
return newHead;
}
/**
* 5.合并兩個有序連結清單,合并之後連結清單依然有序
* 若合并前清單非有序,可先進行冒泡排序,再合并
* 思路:兩種方式:1.建立一個新的連結清單,不斷的将原來兩個連結清單的資料接入新的連結清單,不破壞原連結清單
* 2.在原來兩個連結清單上進行操作,将其中一個連結清單的資料不斷的和另一個連結清單的資料進行比較,
* 如果第一個連結清單的資料比第二個大的話那就将第二個連結清單的資料放在第一個連結清單目前資料的前邊,破環原連結清單
* 此處采用第一種
*/
public static Node mergeTwoLinkedList(Node head1,Node head2) {
//兩連結清單為空,傳回空
if(head1==null&&head2==null) {
return null;
}
//任意一個為空,傳回另一個
if(head1==null) {
return head2;
}
if(head2==null) {
return head1;
}
//建立新連結清單
Node newHead;
Node temp;//建立temp結點,用于操作
//初始化新連結清單的頭結點
if(head1.data<head2.data) {
newHead=head1;
temp=head1;//!!!!!
head1=head1.next;
}else {
newHead=head2;
temp=head2;
head2=head2.next;
}
//周遊兩連結清單,将結果依次插入temp之後
while(head1!=null&&head2!=null) {
if(head1.data<head2.data) {
//初始化已經循環一次,追加
temp.next=head1;
head1=head1.next;
temp=temp.next;
}else {
temp.next=head2;
head2=head2.next;
temp=temp.next;
}
}
//若兩個連結清單的任意一個沒有比較完,追加到temp
if(head1!=null) {
temp.next=head1;
}
if(head2!=null) {
temp.next=head2;
}
return newHead;
}
/**
* 6.從尾到頭列印單連結清單
* 思路:對于這種颠倒順序的問題,實作要想到棧,後進先出!!!
* 故要麼自己使用棧,要麼系統使用棧(遞歸)
* 兩種方式:1.自己使用棧
* 2.系統使用棧(遞歸)
*/
public static void printFromLast(Node head) {
if(head==null) {
return;
}
Stack<Node> stack=new Stack<>();
Node temp=head;
//入棧
while(temp!=null) {
stack.push(temp);
temp=temp.next;
}
//出棧
while(!stack.isEmpty()) {
System.out.println(stack.pop().data);
}
}
public static void printFromLastRec(Node head) {
if(head==null) {
return;
}
printFromLastRec(head.next);
System.out.println(head.data);
}
public static void main(String[] args) {
//建立連結清單執行個體
MyLinkedList LinkedList=new MyLinkedList();
LinkedList.head=new Node(0);
Node node1=new Node(1);
Node node2=new Node(2);
Node node3=new Node(4);
Node node4=new Node(6);
Node node5=new Node(7);
LinkedList.addNode(node1);
LinkedList.addNode(node2);
LinkedList.addNode(node3);
LinkedList.addNode(node4);
LinkedList.addNode(node5);
System.out.println("連結清單長度:"+LinkedList.getLength(LinkedList.head));
System.out.println("周遊并列印連結清單:");
MyLinkedList.print(LinkedList.head);
Node node6=new Node(9);
System.out.println("插入:");
LinkedList.insertByIndex(5,node6);
MyLinkedList.print(LinkedList.head);
System.out.println("删除:");
LinkedList.deleteByIndex(6);
MyLinkedList.print(LinkedList.head);
System.out.println("連結清單反轉:");
System.out.println("非遞歸實作:");
LinkedList.head=MyLinkedList.reverseList(LinkedList.head);
MyLinkedList.print(LinkedList.head);
System.out.println("遞歸實作:");
LinkedList.head=MyLinkedList.reverseListRec(LinkedList.head);
MyLinkedList.print(LinkedList.head);
System.out.println("合并有序連結清單結果為有序連結清單:");
System.out.println("待合并的連結清單:");
MyLinkedList LinkedList1=new MyLinkedList();
LinkedList1.head=new Node(1);
Node node11=new Node(2);Node node12=new Node(3);Node node13=new Node(4);
LinkedList1.addNode(node11);LinkedList1.addNode(node12);LinkedList1.addNode(node13);
MyLinkedList.print(LinkedList1.head);
MyLinkedList LinkedList2=new MyLinkedList();
LinkedList2.head=new Node(2);
Node node9=new Node(3);Node node7=new Node(4); Node node8=new Node(5);
LinkedList2.addNode(node9);LinkedList2.addNode(node7);LinkedList2.addNode(node8);
MyLinkedList.print(LinkedList2.head);
System.out.println("結果:");
MyLinkedList newLinkedList=new MyLinkedList();
newLinkedList.head=MyLinkedList.mergeTwoLinkedList(LinkedList1.head,LinkedList2.head);
MyLinkedList.print(newLinkedList.head);
}
}
運作結果: