Java實(shí)現(xiàn)鏈表的常見(jiàn)操作算法詳解
鏈表分為單鏈表,雙向鏈表和循環(huán)鏈表,是一種鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),由一個(gè)個(gè)結(jié)點(diǎn)鏈?zhǔn)綐?gòu)成,結(jié)點(diǎn)包含數(shù)據(jù)域和指針域,其中單鏈表是只有一個(gè)指向后驅(qū)結(jié)點(diǎn)的指針,雙向鏈表除頭結(jié)點(diǎn)和尾結(jié)點(diǎn)外,每個(gè)結(jié)點(diǎn)都有一個(gè)前驅(qū)指針和一個(gè)后繼指針,循環(huán)鏈表的尾結(jié)點(diǎn)的指針指向頭結(jié)點(diǎn).
相比數(shù)組而言,鏈表的插入和刪除比較快,查詢慢.
本文主要以單鏈表為例,介紹下鏈表的常用算法操作.
單鏈表的結(jié)構(gòu):

在java語(yǔ)言中,鏈表的每個(gè)結(jié)點(diǎn)用Node類來(lái)表示:
package com.linkedlist;
public class Node {
private int data;// 結(jié)點(diǎn)數(shù)據(jù)
private Node next;// 下一個(gè)結(jié)點(diǎn)
public Node(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
定義一個(gè)鏈表操作類,里面包含常用的操作:
package com.linkedlist;
import java.util.Hashtable;
public class LinkedListOperator {
private Node head = null;// 頭結(jié)點(diǎn)
// 在鏈表的末尾增加一個(gè)結(jié)點(diǎn)
private void addNode(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
Node temp = head;
while (temp.getNext() != null) {
temp = temp.getNext();
}
temp.setNext(newNode);
}
// 打印鏈表結(jié)點(diǎn)
private void printLink() {
Node curNode = head;
while (curNode != null) {
System.out.println(curNode.getData());
curNode = curNode.getNext();
}
System.out.println("===========");
}
// 求鏈表長(zhǎng)度
private int getLength() {
int len = 0;
Node curNode = head;
while (curNode != null) {
len++;
curNode = curNode.getNext();
}
return len;
}
// 刪除某一個(gè)結(jié)點(diǎn)
private boolean delNode(int index) {
if (index < 1) {
return false;
}
if (index == 1) {
head = head.getNext();
return true;
}
Node preNode = head;
Node curNode = head.getNext();
int n = 1;
while (curNode.getNext() != null) {
if (n == index) {
preNode.setData(curNode.getData());
preNode.setNext(curNode.getNext());
return true;
}
preNode = preNode.getNext();
curNode = curNode.getNext();
n++;
}
if (curNode.getNext() == null) {
preNode.setNext(null);
}
return false;
}
// 鏈表排序:選擇排序法,從小到大
private void sortList() {
Node curNode = head;
while (curNode != null) {
Node nextNode = curNode.getNext();
while (nextNode != null) {
if (curNode.getData() > nextNode.getData()) {
int temp = curNode.getData();
curNode.setData(nextNode.getData());
nextNode.setData(temp);
}
nextNode = nextNode.getNext();
}
curNode = curNode.getNext();
}
}
// 去掉重復(fù)元素
private void distinctLink() {
Hashtable<Integer, Integer> map = new Hashtable<Integer, Integer>();
Node curNode = head;
Node preNode = null;
while (curNode != null) {
if (map.containsKey(curNode.getData())) {
preNode.setData(curNode.getData());
preNode.setNext(curNode.getNext());
} else {
map.put(curNode.getData(), 1);
preNode = curNode;
}
curNode = curNode.getNext();
}
}
// 返回倒數(shù)第k個(gè)結(jié)點(diǎn),定義兩個(gè)指針,第一個(gè)指針向前移動(dòng)K-1次,之后兩個(gè)指針同時(shí)前進(jìn),
// 當(dāng)?shù)谝粋€(gè)指針到達(dá)末尾時(shí),第二個(gè)指針?biāo)诘奈恢眉礊榈箶?shù)第k個(gè)結(jié)點(diǎn)
private Node getReverNode(int k) {
if (k < 1) {
return null;
}
Node first = head;
Node second = head;
for (int i = 0; i < k - 1; i++) {
first = first.getNext();
}
while (first.getNext() != null) {
first = first.getNext();
second = second.getNext();
}
return second;
}
// 反轉(zhuǎn)鏈表
private void reserveLink() {
Node preNode = null;
Node curNode = head;
Node tempNode = null;
while (curNode != null) {
tempNode = curNode.getNext();
curNode.setNext(preNode);
preNode = curNode;
curNode = tempNode;
}
head = preNode;
}
// 尋找鏈表的中間結(jié)點(diǎn)
private Node getMiddleNode() {
Node slowNode = head;
Node quickNode = head;
while (slowNode.getNext() != null && quickNode.getNext() != null) {
slowNode = slowNode.getNext();
quickNode = quickNode.getNext().getNext();
}
return slowNode;
}
// 判斷鏈表是否有環(huán)
private boolean isRinged() {
if (head == null) {
return false;
}
Node slowNode = head;
Node quickNode = head;
while (slowNode.getNext() != null && quickNode.getNext() != null) {
slowNode = slowNode.getNext();
quickNode = quickNode.getNext().getNext();
if (slowNode.getData() == quickNode.getData()) {
return true;
}
}
return false;
}
// 刪除指定結(jié)點(diǎn)
private boolean delNode(Node node) {
if (node.getNext() == null) {
return false;// 在不知道頭結(jié)點(diǎn)的情況下,沒(méi)法刪除單鏈表的尾結(jié)點(diǎn)
}
node.setData(node.getNext().getData());
node.setNext(node.getNext().getNext());
return true;
}
// 判斷兩個(gè)鏈表是否相交:相交的鏈表的尾結(jié)點(diǎn)相同
private boolean isCross(Node n1, Node n2) {
while (n1.getNext() != null) {
n1 = n1.getNext();
}
while (n2.getNext() != null) {
n2 = n2.getNext();
}
if (n1.getData() == n2.getData()) {
return true;
}
return false;
}
// 求相交鏈表的起始點(diǎn)
private Node getFirstCrossNode(LinkedListOperator l1, LinkedListOperator l2) {
int len = l1.getLength() - l2.getLength();
Node n1 = l1.head;
Node n2 = l2.head;
if (len > 0) {
for (int i = 0; i < len; i++) {
n1 = n1.getNext();
}
} else {
for (int i = 0; i < len; i++) {
n2 = n2.getNext();
}
}
while (n1.getData() != n2.getData()) {
n1 = n1.getNext();
n2 = n2.getNext();
}
return n1;
}
public static void main(String[] args) {
LinkedListOperator llo = new LinkedListOperator();
llo.addNode(10);
llo.addNode(4);
llo.addNode(6);
llo.addNode(8);
llo.printLink();
// llo.delNode(4);
// llo.sortList();
// llo.distinctLink();
// System.out.println(llo.getReverNode(3).getData());
// llo.reserveLink();
// System.out.println(llo.getMiddleNode().getData());
// System.out.println(llo.isRinged());
llo.delNode(llo.head.getNext().getNext());
llo.printLink();
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java鏈表中添加元素的原理與實(shí)現(xiàn)方法詳解
- Java實(shí)現(xiàn)刪除排序鏈表中的重復(fù)元素的方法
- java 數(shù)據(jù)結(jié)構(gòu)之刪除鏈表中的元素實(shí)例代碼
- java實(shí)現(xiàn)單鏈表增刪改查的實(shí)例代碼詳解
- Java數(shù)據(jù)結(jié)構(gòu)之鏈表、棧、隊(duì)列、樹(shù)的實(shí)現(xiàn)方法示例
- JAVA實(shí)現(xiàn)雙向鏈表的增刪功能的方法
- Java實(shí)現(xiàn)單向鏈表反轉(zhuǎn)
- java數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)雙向鏈表的示例
- java實(shí)現(xiàn)單鏈表中是否有環(huán)的方法詳解
- java實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)單鏈表示例(java單鏈表)
- java單向鏈表的實(shí)現(xiàn)實(shí)例
- Java實(shí)現(xiàn)鏈表中元素的獲取、查詢和修改方法詳解
相關(guān)文章
使用@SpringBootTest注解進(jìn)行單元測(cè)試
這篇文章主要介紹了使用@SpringBootTest注解進(jìn)行單元測(cè)試,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
淺談java 單例模式DCL的缺陷及單例的正確寫(xiě)法
這篇文章主要介紹了淺談java 單例模式DCL的缺陷及單例的正確寫(xiě)法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
Java實(shí)現(xiàn)的百度語(yǔ)音識(shí)別功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的百度語(yǔ)音識(shí)別功能,較為簡(jiǎn)明扼要的分析了Java調(diào)用百度語(yǔ)音接口相關(guān)操作步驟,并給出了具體的語(yǔ)音識(shí)別用法代碼示例,需要的朋友可以參考下2018-08-08
SpringBoot使用Aspect切面攔截打印請(qǐng)求參數(shù)的示例代碼
這篇文章主要介紹了SpringBoot使用Aspect切面攔截打印請(qǐng)求參數(shù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
SpringBoot使用Feign調(diào)用其他服務(wù)接口
這篇文章主要介紹了SpringBoot使用Feign調(diào)用其他服務(wù)接口,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
springboot單獨(dú)使用feign簡(jiǎn)化接口調(diào)用方式
這篇文章主要介紹了springboot單獨(dú)使用feign簡(jiǎn)化接口調(diào)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
java JVM原理與常識(shí)知識(shí)點(diǎn)
在本文中小編給大家分享的是關(guān)于java的JVM原理和java常識(shí),有興趣的朋友們可以學(xué)習(xí)下2018-12-12

