鏈表
- 單項鏈表
- 判斷鏈表是否為空
- 增加
- 洗掉
- 查找
- 更改
- 插入
- 遍歷
- 反轉鏈表
- 整體代碼實作
- 如何操作鏈表:
- 雙向鏈表
- 判斷鏈表是否為空
- 增加
- 洗掉
- 查找
- 更改
- 插入
- 遍歷雙向鏈表
- 整體代碼實作
- 操作雙向鏈表
- 環形鏈表
- 利用環形鏈表約瑟夫問題的解決
單項鏈表
邏輯結構圖:

先創建一個節點類:
為了簡化代碼鏈表中的真實資料均整形data表示,并用Num(Num從1開始)記錄對應的下標,
public class Node {
int data;//鏈表中的真實資料
int Num;//對應下標
Node next;//指標
public Node(){}
public Node(int data){
this.data=data;
next=null;
}
public Node(int data,int Num){
this.data=data;
this.Num=Num;
}
然后創建一個單向鏈表類
public class DemoNdeList {
private Node first;
private Node last;
private int total;
public NodeList(){}
public boolean isEmpty(){}//判斷鏈表是否為空
public void add(Node newNode){}//增加元素
public void delete(Node delNode){}//洗掉元素
public Node findElem(Node findNode){}//查找元素
public void revise(Node reNode){}//更改元素
public void insertElem(Node newNode){}//往中間插入元素
public void ergod(){}//遍歷元素
public void reverseElem(){}//反轉鏈表
}
接下來一一實作上述方法:
判斷鏈表是否為空
public boolean isEmpty(){
return first==null;
}
增加
頭插法
public void add(Node newNode){
if(isEmpty()){
first=newNode;
last=newNode;
}else{
last.next=newNode;
last=newNode;
}
newNode.Num=++total;
}
洗掉
public void delete(Node delNode){
if(isEmpty()){
System.out.println("鏈表為空,無洗掉選項");
}
else if(delNode.Num==first.Num){
first=first.next;
Node newptr=first;
while(newptr!=null){
newptr.Num--;
newptr=newptr.next;
}
total--;
}
else if(delNode.Num==last.Num){
Node cur=first;
while(cur.next.Num!=last.Num)
cur=cur.next;
cur.next=null;
last=cur;
total--;
}
else {
Node cur = first;
Node ptr = first;
while (cur != null && cur.Num != delNode.Num) {//找到被修改元素
ptr = cur;
cur = cur.next;
}
if (cur != null) {
ptr.next = cur.next;
Node newptr = cur.next;
while (newptr != null) {
newptr.Num--;
newptr = newptr.next;
}
total--;
} else {
System.out.println("查無此元素");
}
}
}
查找
public Node findElem(Node findNode){
if(isEmpty()){
System.out.println("鏈表為空,無法查找");
return null;
}
Node cur=first;
while(cur!=null&&cur.data!=findNode.data)
cur=cur.next;
return cur;
}
更改
public void revise(Node reNode){
if(isEmpty()){
System.out.println("鏈表為空,無法查找");
return;
}
Node cur=first;
while(cur!=null&&cur.Num!=reNode.Num)
cur=cur.next;
if(cur!=null){
cur.data=reNode.data;
}else{
System.out.println("查無此元素");
}
插入
注意這里的插入方法只涉及往中間插,不涉及頭插與尾插,
public void insertElem(Node newNode){
if(isEmpty()){
first=newNode;
last=newNode;
return;
}
Node cur=first;
Node ptr=first;
while(cur!=null&&cur.Num!= newNode.Num) {//找到插入位置
ptr=cur;
cur = cur.next;
}
if(cur!=null){
ptr.next=newNode;
newNode.next=cur;
while(cur!=null){
cur.Num++;
cur=cur.next;
}
total++;
}
}
遍歷
public void ergod(){
if(isEmpty()){
System.out.println("鏈表為空,無法遍歷");
return;
}
Node cur=first;
while(cur!=null){
System.out.println(cur.Num+"\t"+cur.data);
cur=cur.next;
}
}
反轉鏈表
先用tmp記錄cur.next,然后將cur指向的下一個結點的指標(cur.next)指向上一個結點(bef),如此反復,直到最后一個節點即可,
public void reverseElem(){
Node cur=first;
Node bef=null;
while(cur!=null){
Node tmp=cur.next;
cur.next=bef;
bef=cur;
cur=tmp;
}
first=bef;
}
整體代碼實作
public class NodeList {
private Node first;
private Node last;
private int total;
public NodeList(){}
//判斷是否為空
public boolean isEmpty(){
return first==null;
}
//增加元素
public void add(Node newNode){
if(isEmpty()){
first=newNode;
last=newNode;
}else{
last.next=newNode;
last=newNode;
}
newNode.Num=++total;
}
//洗掉元素
public void delete(Node delNode){
if(isEmpty()){
System.out.println("鏈表為空,無洗掉選項");
}
else if(delNode.Num==first.Num){
first=first.next;
Node newptr=first;
while(newptr!=null){
newptr.Num--;
newptr=newptr.next;
}
total--;
}
else if(delNode.Num==last.Num){
Node cur=first;
while(cur.next.Num!=last.Num)
cur=cur.next;
cur.next=null;
last=cur;
total--;
}
else {
Node cur = first;
Node ptr = first;
while (cur != null && cur.Num != delNode.Num) {//找到被修改元素
ptr = cur;
cur = cur.next;
}
if (cur != null) {
ptr.next = cur.next;
Node newptr = cur.next;
while (newptr != null) {
newptr.Num--;
newptr = newptr.next;
}
total--;
} else {
System.out.println("查無此元素");
}
}
}
//查找元素
public Node findElem(Node findNode){
if(isEmpty()){
System.out.println("鏈表為空,無法查找");
return null;
}
Node cur=first;
while(cur!=null&&cur.data!=findNode.data)
cur=cur.next;
return cur;
}
//更改元素
public void revise(Node reNode){
if(isEmpty()){
System.out.println("鏈表為空,無法查找");
return;
}
Node cur=first;
while(cur!=null&&cur.Num!=reNode.Num)
cur=cur.next;
if(cur!=null){
cur.data=reNode.data;
}else{
System.out.println("查無此元素");
}
}
//往中間插入元素插入元素
public void insertElem(Node newNode){
if(isEmpty()){
first=newNode;
last=newNode;
return;
}
Node cur=first;
Node ptr=first;
while(cur!=null&&cur.Num!= newNode.Num) {//找到插入位置
ptr=cur;
cur = cur.next;
}
if(cur!=null){
ptr.next=newNode;
newNode.next=cur;
while(cur!=null){
cur.Num++;
cur=cur.next;
}
total++;
}
}
//遍歷鏈表
public void ergod(){
if(isEmpty()){
System.out.println("鏈表為空,無法遍歷");
return;
}
Node cur=first;
while(cur!=null){
System.out.println(cur.Num+"\t"+cur.data);
cur=cur.next;
}
}
//反轉鏈表
public void reverseElem(){
Node cur=first;
Node bef=null;
while(cur!=null){
Node tmp=cur.next;
cur.next=bef;
bef=cur;
cur=tmp;
}
first=bef;
}
}
如何操作鏈表:
import java.util.Scanner;
public class DemoNdeList {
public static void menu(){
System.out.println(" 1.增加元素");
System.out.println(" 2.洗掉元素");
System.out.println(" 3.查找元素");
System.out.println(" 4.更改元素");
System.out.println(" 5.插入元素");
System.out.println(" 6.遍歷鏈表");
System.out.println(" 7.反轉鏈表");
System.out.println(" 8.退出");
}
public static void main(String[] args){
NodeList L=new NodeList();
Scanner sc=new Scanner(System.in);
boolean flag=true;
while(flag){
menu();
int key=sc.nextInt();
switch(key){
case 1:
System.out.println("請輸入數字:");
int n1=sc.nextInt();
Node w1=new Node(n1);
L.add(w1);
break;
case 2:
System.out.println("請輸入洗掉元素序列號:");
int n2=sc.nextInt();
Node w2=new Node();
w2.Num=n2;
L.delete(w2);
break;
case 3:
System.out.println("請輸入查找元素資料:");
int n3=sc.nextInt();
Node w3=new Node(n3);
if(L.findElem(w3)!=null){
System.out.println("找到此元素,序列為:"+L.findElem(w3).Num);
}
break;
case 4:
System.out.println("請輸入更改元素序列號:");
int n4=sc.nextInt();
System.out.println("請輸入更改數字");
int n44=sc.nextInt();
Node w4=new Node(n44,n4);
L.revise(w4);
break;
case 5:
System.out.println("請輸入要插入元素的資料");
int n5=sc.nextInt();
System.out.println("請輸入將元素插入到的位置:");
int n55=sc.nextInt();
Node w5=new Node(n5,n55);
L.insertElem(w5);
break;
case 6:
System.out.println("鏈表遍歷如下:");
L.ergod();
break;
case 7:
System.out.println("反轉鏈表后,資料如下:");
L.reverseElem();
L.ergod();
break;
case 8:
System.out.println("退出程式完畢");
flag=false;
break;
default:
System.out.println("輸入有誤,請重新輸入");
break;
}
}
}
}
雙向鏈表
雙向鏈表邏輯結構:

和單鏈表一樣先創建一個節點類:
public class Node {
int data;//鏈表中真實資料
int Num;//記錄下標從一開始
Node lnext;//記錄前一個節點或左邊結點
Node rnext;//記錄后一個結點或右結點
public Node(){}
public Node(int data){
this.data=data;
lnext=null;
rnext=null;
}
public Node(int data,int Num){
this.data=data;
this.Num=Num;
lnext=null;
rnext=null;
}
}
創建一個雙向鏈表類:
public class DoubleLinkedList {
private Node first;
private Node last;
private int total;
public DoubleLinkedList(){}
public boolean isEmpty(){}//判斷鏈表是否為空
public void add(Node newNode){}//增加元素
public void delete(Node delNode){}//洗掉元素
public Node findElem(Node findNode){}//查找元素
public void revise(Node reNode){}//更改元素
public void insertElem(Node newNode){}//往中間插入元素
public void ergod(){}//遍歷元素
}
判斷鏈表是否為空
public boolean isEmpty(){
return first==null;
}
增加
public void add(Node newNode){
if(isEmpty()){
first=newNode;
last=newNode;
}else{
newNode.lnext=last;
last.rnext=newNode;
last=newNode;
}
newNode.Num=++total;
}
洗掉
public void delete(Node delNode){
if(isEmpty()){
System.out.println("鏈表為空,無洗掉選項");
}
else if(delNode.Num==first.Num){
first=first.rnext;
first.lnext=null;
Node newptr=first;
while(newptr!=null){
newptr.Num--;
newptr=newptr.rnext;
}
total--;
}
else if(delNode.Num==last.Num){
Node tmp=last.lnext;
last.lnext.rnext=null;
last.lnext=null;
last=tmp;
total--;
}
else {
Node cur = first;
while (cur != null && cur.Num != delNode.Num) {//找到被修改元素
cur = cur.rnext;
}
if (cur != null) {
cur.lnext.rnext=cur.rnext;
cur.rnext.lnext=cur.lnext;
Node newptr = cur.rnext;
while (newptr != null) {
newptr.Num--;
newptr = newptr.rnext;
}
total--;
} else {
System.out.println("查無此元素");
}
}
}
查找
public Node findElem(Node findNode){
if(isEmpty()){
System.out.println("鏈表為空,無法查找");
return null;
}
Node cur=first;
while(cur!=null&&cur.Num!=findNode.Num)
cur=cur.rnext;//從頭往后查找
return cur;
}
更改
public void revise(Node reNode){
if(isEmpty()){
System.out.println("鏈表為空,無法查找");
return;
}
Node cur=first;
while(cur!=null&&cur.Num!=reNode.Num)
cur=cur.rnext;
if(cur!=null){
cur.data=reNode.data;
}else{
System.out.println("查無此元素");
}
}
插入
public void insertElem(Node newNode){
if(isEmpty()){
first=newNode;
last=newNode;
return;
}
Node cur=first;
while(cur!=null&&cur.Num!= newNode.Num) {//找到被修改元素
cur = cur.rnext;
}
if(cur!=null){
newNode.lnext=cur.lnext;
cur.lnext.rnext=newNode;
newNode.rnext=cur;
cur.lnext=newNode;
while(cur!=null){
cur.Num++;
cur=cur.rnext;
}
total++;
}
}
遍歷雙向鏈表
public void ergod(){
if(isEmpty()){
System.out.println("鏈表為空,無法遍歷");
return;
}
Node cur=first;
while(cur!=null){
System.out.println(cur.Num+"\t"+cur.data);
cur=cur.rnext;
}
}
整體代碼實作
public class DoubleLinkedList {
private Node first;
private Node last;
private int total;
public DoubleLinkedList(){}
//判斷是否為空
public boolean isEmpty(){
return first==null;
}
//增加元素
public void add(Node newNode){
if(isEmpty()){
first=newNode;
last=newNode;
}else{
newNode.lnext=last;
last.rnext=newNode;
last=newNode;
}
newNode.Num=++total;
}
//洗掉元素
public void delete(Node delNode){
if(isEmpty()){
System.out.println("鏈表為空,無洗掉選項");
}
else if(delNode.Num==first.Num){
first=first.rnext;
first.lnext=null;
Node newptr=first;
while(newptr!=null){
newptr.Num--;
newptr=newptr.rnext;
}
total--;
}
else if(delNode.Num==last.Num){
Node tmp=last.lnext;
last.lnext.rnext=null;
last.lnext=null;
last=tmp;
total--;
}
else {
Node cur = first;
while (cur != null && cur.Num != delNode.Num) {//找到被修改元素
cur = cur.rnext;
}
if (cur != null) {
cur.lnext.rnext=cur.rnext;
cur.rnext.lnext=cur.lnext;
Node newptr = cur.rnext;
while (newptr != null) {
newptr.Num--;
newptr = newptr.rnext;
}
total--;
} else {
System.out.println("查無此元素");
}
}
}
//查找元素
public Node findElem(Node findNode){
if(isEmpty()){
System.out.println("鏈表為空,無法查找");
return null;
}
Node cur=first;
while(cur!=null&&cur.Num!=findNode.Num)
cur=cur.rnext;//從頭往友查找
return cur;
}
//更改元素
public void revise(Node reNode){
if(isEmpty()){
System.out.println("鏈表為空,無法查找");
return;
}
Node cur=first;
while(cur!=null&&cur.Num!=reNode.Num)
cur=cur.rnext;
if(cur!=null){
cur.data=reNode.data;
}else{
System.out.println("查無此元素");
}
}
//往中間插入元素插入元素
public void insertElem(Node newNode){
if(isEmpty()){
first=newNode;
last=newNode;
return;
}
Node cur=first;
while(cur!=null&&cur.Num!= newNode.Num) {//找到被修改元素
cur = cur.rnext;
}
if(cur!=null){
newNode.lnext=cur.lnext;
cur.lnext.rnext=newNode;
newNode.rnext=cur;
cur.lnext=newNode;
while(cur!=null){
cur.Num++;
cur=cur.rnext;
}
total++;
}
}
//遍歷鏈表
public void ergod(){
if(isEmpty()){
System.out.println("鏈表為空,無法遍歷");
return;
}
Node cur=first;
while(cur!=null){
System.out.println(cur.Num+"\t"+cur.data);
cur=cur.rnext;
}
}
}
操作雙向鏈表
import java.util.Scanner;
public class DemoDoubleLinkedList {
public static void menu(){
System.out.println(" 1.增加元素");
System.out.println(" 2.洗掉元素");
System.out.println(" 3.查找元素");
System.out.println(" 4.更改元素");
System.out.println(" 5.插入元素");
System.out.println(" 6.遍歷鏈表");
System.out.println(" 7.退出");
}
public static void main(String[] args){
DoubleLinkedList D=new DoubleLinkedList();
Scanner sc=new Scanner(System.in);
boolean flag=true;
while(flag){
menu();
int key=sc.nextInt();
switch(key){
case 1:
System.out.println("請輸入數字:");
int n1=sc.nextInt();
Node w1=new Node(n1);
D.add(w1);
break;
case 2:
System.out.println("請輸入洗掉元素序列號:");
int n2=sc.nextInt();
Node w2=new Node();
w2.Num=n2;
D.delete(w2);
break;
case 3:
System.out.println("請輸入查找元素資料:");
int n3=sc.nextInt();
Node w3=new Node(n3);
if(D.findElem(w3)!=null){
System.out.println("找到此元素,序列為:"+D.findElem(w3).Num);
}
break;
case 4:
System.out.println("請輸入更改元素序列號:");
int n4=sc.nextInt();
System.out.println("請輸入更改數字");
int n44=sc.nextInt();
Node w4=new Node(n44,n4);
D.revise(w4);
break;
case 5:
System.out.println("請輸入要插入元素的資料");
int n5=sc.nextInt();
System.out.println("請輸入將元素插入到的位置:");
int n55=sc.nextInt();
Node w5=new Node(n5,n55);
D.insertElem(w5);
break;
case 6:
System.out.println("鏈表遍歷如下:");
D.ergod();
break;
case 7:
System.out.println("退出程式完畢");
flag=false;
break;
default:
System.out.println("輸入有誤,請重新輸入");
break;
}
}
}
}
環形鏈表
環形鏈表和單項鏈表差不多,只不過是將首尾連接了起來形成一個環;
也是先創建一個結點:
public class Node {
int data;
Node next;
public Node(){}
public Node(int data){
this.data=data;
next=null;
}
}
這里僅展示增加和遍歷方法,其余方法可借鑒單向鏈表中的方法
public class CircleLink {
private Node first;
private Node last;
public void add(Node newNode){
if(first==null){
first=newNode;
last=newNode
last.next=first;
}else {
last.next = newNode;
newNode.next = first;
last = newNode;
}
}
//遍歷環形鏈表
public void show(){
Node empty=first;
if(empty==null){
System.out.println("鏈表為空,無法遍歷");
return;
}
do{
System.out.printf("this is %dth data\n",empty.data);
empty=empty.next;
}while(empty!=first);
}
}
利用環形鏈表約瑟夫問題的解決
有n個人,編號為1~n,從第一個人開始報數,從1開始報,報到m的人會死掉,然后從第m+1個人開始,重復以上程序,在死了n-1個人后,問最后一個人的編號是?
public class CircleLink {
private Node first;
private Node last;
public void add(int n){
for(int i=1;i<=n;i++){
Node newNode=new Node(i);
if(first==null){
first=newNode;
last=newNode;
}
last.next=newNode;
last=newNode;
}
last.next=first;
}
//解決約瑟夫問題
public int solveJ(int n,int m){
if(m == 1 || n < 2){
System.out.println("輸入引數有誤");
return 0;
}
add(n);
int count=1;
Node cur=first;
Node ptr=null;
while(cur.next!=cur){
if(count==m){
ptr.next=cur.next;
cur=ptr.next;
count=1;
}else{
ptr=cur;
cur=cur.next;
count++;
}
}
return cur.data;
}
//遍歷環形鏈表
public void show(){
Node empty=first;
if(empty==null){
System.out.println("this list is null");
return;
}
do{
System.out.printf("this is %dth data\n",empty.data);
empty=empty.next;
}while(empty!=first);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/293717.html
標籤:java
上一篇:在專案中使用OpenFeign
