Java 實現鏈表
實現功能
- 鏈表無序加入數據
- 打印所有節點信息
- 有序插入節點
- 修改節點數據
- 刪除節點
- 獲取鏈表有效節點個數
- 獲取倒數第K個節點(思路:定義兩個指針變量一開始指向頭節點,讓第一個first先走k-1步,然後第二個second跟第一個一起走,當第一個走到頭後,輸出第二個就是倒數第K個元素)
- 用棧來反轉鏈表
- 使用頭插法反轉鏈表
- 將兩個有序的鏈表合併(非遞歸)
- 遞歸合併鏈表
可以看看註釋,面試的題與鏈表基本實現都有
package DataStructure.LinkListDemo;
import java.util.Stack;
//定義node
class Node{
public int no;
public String name;
public Node next; //存放指向下一個節點的數據
public Node(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Node{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
//實現鏈表功能
class LinkedListDemo{
private Node head=new Node(-1,"");//初始化頭節點
/**
* 鏈表無序加入數據
* @param node
*/
public void add(Node node){
Node temp=head; //由於不能移動head,所以用temp代替
while(true){
if(temp.next==null){ //當找到下一個節點元素爲空是,就可以把新的數據加入到這裏
break;
}
temp=temp.next; //當找不到時,一直向後找
}
temp.next=node; //這裏加入新節點
}
/**
* 打印所有節點信息
*/
public void prtList(){
if(head.next==null) System.out.println("鏈表爲空");
Node temp=head.next; //由於不能移動head,所以用temp代替
while(true){
if(temp==null){ //判斷鏈表誰否到最後
break;
}
System.out.println(temp);//輸出節點信息
temp=temp.next;//節點後移
}
}
/**
*有序插入節點
*/
public void addOrder(Node node){
Node temp=head;
boolean flag=false; //判斷是否重複添加
while (true){ //查找該插入的節點位置
if(temp.next==null){ //在鏈表最後
break;
}
if(node.no<temp.next.no){ //這裏需要找到temp的下一個位置與插入的node比較,比temp的下一個元素小,那就可以插入到temp後面
break; //位置已經找到
}else if(temp.next.no==node.no){
flag=true;
break; //不能添加重複的元素
}
temp=temp.next; //向後移
}
if(flag) System.out.println("不能添加重複編號的節點: "+node);
else {
node.next=temp.next;
temp.next=node;
}
}
/**
* 修改節點數據
* @param node
*/
public void updateNode(Node node){
if(head.next==null) System.out.println("鏈表爲空,不能修改");
Node temp=head.next;
boolean flag=false;//表示是否找到修改的節點
while (true){
if(temp==null) break; //表示找到最後還是沒有找到
if(temp.no==node.no){
flag=true;//表示找到了
break;
}
temp=temp.next;//接着向後查找
}
if(flag) {
temp.name=node.name;
}else{
System.out.println("未發現存在的節點 :"+node);
}
}
/**
* 刪除節點
* @param node
*/
public void deleteNode(Node node){
if(head.next==null) System.out.println("鏈表爲空,不能刪除");
Node temp=head; //由於不能改變head的值,使用臨時變量
boolean flag=false;//表示未能找到刪除節點
while(true){
if(temp.next==null){
break; //表示未能找到當前刪除的節點
}
if(temp.next.no==node.no){ //表示找到要刪除的節點
flag=true;
break;
}
temp=temp.next;//找不到就向後找
}
if(flag){
temp.next=temp.next.next;
}else{
System.out.println("未能找到刪除的節點: "+node);
}
}
/**
* 獲取鏈表有效節點個數
* @return
*/
public int getAllNodeNumber(){
int num=0;
if(head.next==null) return 0;
Node temp=head.next;
while (true){
if(temp==null){
break;
}
num++;
temp=temp.next;
}
return num;
}
/**
* 獲取倒數第K個節點(思路:定義兩個指針變量一開始指向頭節點,讓第一個first先走k-1步,然後第二個second跟第一個一起走,當第一個走到頭後,輸出第二個就是倒數第K個元素)
*/
public void getLastK(int k){
if(head.next==null) System.out.println("鏈表爲空");
Node first=head;
Node second=head;
for (int i = 0; i < k-1; i++) {
if(first.next==null) return;
first=first.next;
}
while(first.next!=null){
first=first.next;
second=second.next;
}
System.out.println(second);
}
/**
* 用棧來反轉鏈表
*/
public void InverseList(){
if(head.next==null) {
System.out.println("鏈表爲空,不能反轉");
return;
}
Node temp=head; //使用temp來遍歷list
Node newTemp=head; //使用newTemp來串新鏈表
Stack<Node> stack=new Stack<>(); //用棧來保存鏈表所有數據
while(temp.next!=null){ //循環加入棧中
stack.push(temp.next);
temp=temp.next;
}
while(!stack.empty()){ // 當棧不爲空時,一直彈出,加到新節點後(改變原先順序)
newTemp.next=stack.pop();
newTemp=newTemp.next;
}
// while (stack.size()>0){ //不改變原先順序,直接打印出來
// System.out.println(stack.pop());
// }
newTemp.next=null; //如果不設置最後一個節點的next域,那將會變成環形鏈表
}
/**
* 使用頭插法反轉鏈表
*/
public void reverse() {
if (head.next == null || head.next.next == null)
return ;
Node cur=head.next;
Node next=null;
Node reserve=new Node(-1,"");
while(cur!=null){
next=cur.next;
cur.next=reserve.next;
reserve.next=cur;
cur=next;
}
head.next=reserve.next;
}
/**
* 將兩個有序的鏈表合併
* @param list1
* @param list2
* @return
*/
public Node mergeList(Node list1,Node list2){
if(list1==null) return list2; //如果一條鏈表爲空,那就返回另一條鏈表
if(list2==null) return list1;
Node newNode=new Node(-1,""); //定義一個新鏈表頭
Node temp=newNode; //頭不能變,所以定義臨時變量
while((list1!=null)&&(list2!=null)){ //當只要有一個變量的值爲空就跳出循環
if(list1.no>=list2.no){ //當list1.no>=list2.no
temp.next=list2; //我們把小的連到頭的後面,下同
list2=list2.next;
}
else {
temp.next=list1;
list1=list1.next;
}
temp=temp.next; //臨時變量向後移
}
// if(list1==null){
// temp.next=list2;
// }
// else if (list2==null){
// temp.next=list1;
// }
temp.next=list1==null?list2:list1; //當某一個鏈表的值爲空時,就將另一條鏈表連入新表
return newNode.next; //返回新鏈表的第一個值
}
/**
* 遞歸合併鏈表
* @param list1
* @param list2
* @return
*/
public Node mergeListDigui(Node list1,Node list2){
if(list1==null) return list2;
if(list2==null) return list1;
if(list1.no<list2.no){
list1.next= mergeListDigui(list1.next,list2);
return list1;
}else {
list2.next = mergeListDigui(list1, list2.next);
return list2;
}
}
}
//測試方法
public class LinkListDemo {
public static void main(String[] args) {
Node node=new Node(1,"kaikai");
Node node1=new Node(2,"kaikai");
Node node2=new Node(4,"kaikai");
LinkedListDemo list=new LinkedListDemo();
// list.addOrder(node);
// list.addOrder(node1);
// list.addOrder(node2);
// list.prtList(); //打印鏈表
Node node3=new Node(2,"kaikai1");
Node node4=new Node(3,"kaikai");
Node node5=new Node(8,"kaikai");
node.next=node1;
node1.next=node2;
node3.next=node4;
node4.next=node5;
//合併鏈表
Node node6 = list.mergeListDigui(node, node4);
while(node6!=null){
System.out.println(node6);
node6=node6.next;
}
// final int allNodeNumber = list.getAllNodeNumber();
// System.out.println("鏈表的有效個數爲: "+allNodeNumber);
//
// System.out.println("鏈表反轉後爲: ");
// list.reverse();
// list.prtList();
//
// System.out.println("得到鏈表倒數第K的節點爲: ");
// list.getLastK(3);
//
// System.out.println("修改數據後爲:");
// Node node5=new Node(5,"kaikai55555");
// list.updateNode(node5);
// list.prtList();
//
// System.out.println("刪除數據後爲:");
// Node node6=new Node(5,"kaikai55555");
// list.deleteNode(node6);
// list.prtList();
}
}