摘要:一前言最近在回顧數(shù)據(jù)結(jié)構(gòu)與算法,有部分的算法題用到了棧的思想,說起棧又不得不說鏈表了。
一、前言
最近在回顧數(shù)據(jù)結(jié)構(gòu)與算法,有部分的算法題用到了棧的思想,說起棧又不得不說鏈表了。數(shù)組和鏈表都是線性存儲結(jié)構(gòu)的基礎(chǔ),棧和隊列都是線性存儲結(jié)構(gòu)的應(yīng)用~
本文主要講解單鏈表的基礎(chǔ)知識點,做一個簡單的入門~如果有錯的地方請指正
二、回顧與知新說起鏈表,我們先提一下數(shù)組吧,跟數(shù)組比較一下就很理解鏈表這種存儲結(jié)構(gòu)了。
2.1回顧數(shù)組數(shù)組我們無論是C、Java都會學(xué)過:
數(shù)組是一種連續(xù)存儲線性結(jié)構(gòu),元素類型相同,大小相等
數(shù)組的優(yōu)點:
存取速度快
數(shù)組的缺點:
事先必須知道數(shù)組的長度
插入刪除元素很慢
空間通常是有限制的
需要大塊連續(xù)的內(nèi)存塊
插入刪除元素的效率很低
2.2鏈表說明看完了數(shù)組,回到我們的鏈表:
鏈表是離散存儲線性結(jié)構(gòu)
n個節(jié)點離散分配,彼此通過指針相連,每個節(jié)點只有一個前驅(qū)節(jié)點,每個節(jié)點只有一個后續(xù)節(jié)點,首節(jié)點沒有前驅(qū)節(jié)點,尾節(jié)點沒有后續(xù)節(jié)點。
鏈表優(yōu)點:
空間沒有限制
插入刪除元素很快
鏈表缺點:
存取速度很慢
鏈表相關(guān)術(shù)語介紹,我還是通過上面那個圖來說明吧:
確定一個鏈表我們只需要頭指針,通過頭指針就可以把整個鏈表都能推導(dǎo)出來了~
鏈表又分了好幾類:
單向鏈表
一個節(jié)點指向下一個節(jié)點
雙向鏈表
一個節(jié)點有兩個指針域
循環(huán)鏈表
能通過任何一個節(jié)點找到其他所有的節(jié)點,將兩種(雙向/單向)鏈表的最后一個結(jié)點指向第一個結(jié)點從而實現(xiàn)循環(huán)
操作鏈表要時刻記住的是:
節(jié)點中指針域指向的就是一個節(jié)點了!
三、Java實現(xiàn)鏈表算法:
遍歷
查找
清空
銷毀
求長度
排序
刪除節(jié)點
插入節(jié)點
ps:我將head節(jié)點定義在成員變量上:
private static Node head = new Node();
首先,我們定義一個類作為節(jié)點
數(shù)據(jù)域
指針域
為了操作方便我就直接定義成public了。
public class Node { //數(shù)據(jù)域 public Integer data; //指針域,指向下一個節(jié)點 public Node next; public Node() { } public Node(int data) { this.data = data; } public Node(int data, Node next) { this.data = data; this.next = next; } }3.1創(chuàng)建鏈表(增加節(jié)點)
向鏈表中插入數(shù)據(jù):
找到尾節(jié)點進行插入
即使頭節(jié)點.next為null,不走while循環(huán),也是將頭節(jié)點與新節(jié)點連接的(我已經(jīng)將head節(jié)點初始化過了,因此沒必要判斷頭節(jié)點是否為null)~
/** * 向鏈表添加數(shù)據(jù) * * @param value 要添加的數(shù)據(jù) */ public static void addData(int value) { //初始化要加入的節(jié)點 Node newNode = new Node(value); //臨時節(jié)點 Node temp = head; // 找到尾節(jié)點 while (temp.next != null) { temp = temp.next; } // 已經(jīng)包括了頭節(jié)點.next為null的情況了~ temp.next = newNode; }3.2遍歷鏈表
上面我們已經(jīng)編寫了增加方法,現(xiàn)在遍歷一下看一下是否正確~~~
從首節(jié)點開始,不斷往后面找,直到后面的節(jié)點沒有數(shù)據(jù):
/** * 遍歷鏈表 * * @param head 頭節(jié)點 */ public static void traverse(Node head) { //臨時節(jié)點,從首節(jié)點開始 Node temp = head.next; while (temp != null) { if (temp.data != null) { System.out.println("關(guān)注公眾號Java3y:" + temp.data); } //繼續(xù)下一個 temp = temp.next; } }
結(jié)果:
3.3插入節(jié)點插入一個節(jié)點到鏈表中,首先得判斷這個位置是否是合法的,才能進行插入~
找到想要插入的位置的上一個節(jié)點就可以了~
/** * 插入節(jié)點 * * @param head 頭指針 * @param index 要插入的位置 * @param value 要插入的值 */ public static void insertNode(Node head, int index, int value) { //首先需要判斷指定位置是否合法, if (index < 1 || index > linkListLength(head) + 1) { System.out.println("插入位置不合法。"); return; } //臨時節(jié)點,從頭節(jié)點開始 Node temp = head; //記錄遍歷的當(dāng)前位置 int currentPos = 0; //初始化要插入的節(jié)點 Node insertNode = new Node(value); while (temp.next != null) { //找到上一個節(jié)點的位置了 if ((index - 1) == currentPos) { //temp表示的是上一個節(jié)點 //將原本由上一個節(jié)點的指向交由插入的節(jié)點來指向 insertNode.next = temp.next; //將上一個節(jié)點的指針域指向要插入的節(jié)點 temp.next = insertNode; return; } currentPos++; temp = temp.next; } }3.4獲取鏈表的長度
獲取鏈表的長度就很簡單了,遍歷一下,每得到一個節(jié)點+1即可~
/** * 獲取鏈表的長度 * @param head 頭指針 */ public static int linkListLength(Node head) { int length = 0; //臨時節(jié)點,從首節(jié)點開始 Node temp = head.next; // 找到尾節(jié)點 while (temp != null) { length++; temp = temp.next; } return length; }3.5刪除節(jié)點
刪除某個位置上的節(jié)點其實是和插入節(jié)點很像的, 同樣都要找到上一個節(jié)點。將上一個節(jié)點的指針域改變一下,就可以刪除了~
/** * 根據(jù)位置刪除節(jié)點 * * @param head 頭指針 * @param index 要刪除的位置 */ public static void deleteNode(Node head, int index) { //首先需要判斷指定位置是否合法, if (index < 1 || index > linkListLength(head) + 1) { System.out.println("刪除位置不合法。"); return; } //臨時節(jié)點,從頭節(jié)點開始 Node temp = head; //記錄遍歷的當(dāng)前位置 int currentPos = 0; while (temp.next != null) { //找到上一個節(jié)點的位置了 if ((index - 1) == currentPos) { //temp表示的是上一個節(jié)點 //temp.next表示的是想要刪除的節(jié)點 //將想要刪除的節(jié)點存儲一下 Node deleteNode = temp.next; //想要刪除節(jié)點的下一個節(jié)點交由上一個節(jié)點來控制 temp.next = deleteNode.next; //Java會回收它,設(shè)置不設(shè)置為null應(yīng)該沒多大意義了(個人覺得,如果不對請指出哦~) deleteNode = null; return; } currentPos++; temp = temp.next; } }3.6對鏈表進行排序
前面已經(jīng)講過了8種的排序算法了【八種排序算法總結(jié)】,這次挑簡單的冒泡排序吧(其實我是想寫快速排序的,嘗試了一下感覺有點難.....)
/** * 對鏈表進行排序 * * @param head * */ public static void sortLinkList(Node head) { Node currentNode; Node nextNode; for (currentNode = head.next; currentNode.next != null; currentNode = currentNode.next) { for (nextNode = head.next; nextNode.next != null; nextNode = nextNode.next) { if (nextNode.data > nextNode.next.data) { int temp = nextNode.data; nextNode.data = nextNode.next.data; nextNode.next.data = temp; } } } }3.7找到鏈表中倒數(shù)第k個節(jié)點
這個算法挺有趣的:設(shè)置兩個指針p1、p2,讓p2比p1快k個節(jié)點,同時向后遍歷,當(dāng)p2為空,則p1為倒數(shù)第k個節(jié)點
/** * 找到鏈表中倒數(shù)第k個節(jié)點(設(shè)置兩個指針p1、p2,讓p2比p1快k個節(jié)點,同時向后遍歷,當(dāng)p2為空,則p1為倒數(shù)第k個節(jié)點 * * @param head * @param k 倒數(shù)第k個節(jié)點 */ public static Node findKNode(Node head, int k) { if (k < 1 || k > linkListLength(head)) return null; Node p1 = head; Node p2 = head; // p2比怕p1快k個節(jié)點 for (int i = 0; i < k - 1; i++) p2 = p2.next; // 只要p2為null,那么p1就是倒數(shù)第k個節(jié)點了 while (p2.next != null) { p2 = p2.next; p1 = p1.next; } return p1; }3.8刪除鏈表重復(fù)數(shù)據(jù)
這里之前有問題,大家可以到:https://blog.csdn.net/ifollow...
進行參考
3.9查詢鏈表的中間節(jié)點這個算法也挺有趣的:一個每次走1步,一個每次走兩步,走兩步的遍歷完,然后走一步的指針,那就是中間節(jié)點
/** * 查詢單鏈表的中間節(jié)點 */ public static Node searchMid(Node head) { Node p1 = head; Node p2 = head; // 一個走一步,一個走兩步,直到為null,走一步的到達的就是中間節(jié)點 while (p2 != null && p2.next != null && p2.next.next != null) { p1 = p1.next; p2 = p2.next.next; } return p1; }3.10通過遞歸從尾到頭輸出單鏈表
/** * 通過遞歸從尾到頭輸出單鏈表 * * @param head 頭節(jié)點 */ public static void printListReversely(Node head) { if (head != null) { printListReversely(head.next); if (head.data != null) { System.out.println(head.data); } } }3.11反轉(zhuǎn)鏈表
/** * 實現(xiàn)鏈表的反轉(zhuǎn) * * @param head 鏈表的頭節(jié)點 */ public static Node reverseList(Node head) { Node pre = null; Node cur = head; while (cur != null) { Node next = cur.next; cur.next = pre; pre = cur; cur = next; } return pre; } // 翻轉(zhuǎn)完,使用下面的代碼進行遍歷吧: public static void traverse4Reverse(Node head) { //臨時節(jié)點,從首節(jié)點開始 Node temp = head; while (temp != null) { if (temp.data != null) { System.out.println("關(guān)注公眾號Java3y:" + temp.data); } //繼續(xù)下一個 temp = temp.next; } }
反轉(zhuǎn)鏈表參考自:
http://www.cnblogs.com/hanxue112253/p/8533426.html
四、最后理解鏈表本身并不難,但做相關(guān)的操作就弄得頭疼,head.next next next next ....(算法這方面我還是薄弱啊..腦子不夠用了.....)寫了兩天就寫了這么點東西...
操作一個鏈表只需要知道它的頭指針就可以做任何操作了
添加數(shù)據(jù)到鏈表中
遍歷找到尾節(jié)點,插入即可(只要while(temp.next != null),退出循環(huán)就會找到尾節(jié)點)
遍歷鏈表
從首節(jié)點(有效節(jié)點)開始,只要不為null,就輸出
給定位置插入節(jié)點到鏈表中
首先判斷該位置是否有效(在鏈表長度的范圍內(nèi))
找到想要插入位置的上一個節(jié)點
將原本由上一個節(jié)點的指向交由插入的節(jié)點來指向
上一個節(jié)點指針域指向想要插入的節(jié)點
獲取鏈表的長度
每訪問一次節(jié)點,變量++操作即可
刪除給定位置的節(jié)點
首先判斷該位置是否有效(在鏈表長度的范圍內(nèi))
找到想要插入位置的上一個節(jié)點
將原本由上一個節(jié)點的指向后面一個節(jié)點
對鏈表進行排序
使用冒泡算法對其進行排序
找到鏈表中倒數(shù)第k個節(jié)點
設(shè)置兩個指針p1、p2,讓p2比p1快k個節(jié)點,同時向后遍歷,當(dāng)p2為空,則p1為倒數(shù)第k個節(jié)點
刪除鏈表重復(fù)數(shù)據(jù)
操作跟冒泡排序差不多,只要它相等,就能刪除了~
查詢鏈表的中間節(jié)點
這個算法也挺有趣的:一個每次走1步,一個每次走兩步,走兩步的遍歷完,然后走一步的指針,那就是中間節(jié)點
遞歸從尾到頭輸出單鏈表
只要下面還有數(shù)據(jù),那就往下找,遞歸是從最后往前翻。
反轉(zhuǎn)鏈表
有遞歸和非遞歸兩種方式,我覺得是挺難的??梢缘轿医o出的鏈接上查閱~
PS:每個人的實現(xiàn)都會不一樣,所以一些小細(xì)節(jié)難免會有些變動,也沒有固定的寫法,能夠?qū)崿F(xiàn)對應(yīng)的功能即可~
參考資料:
http://www.cnblogs.com/whgk/p/6589920.html
https://www.cnblogs.com/bywallance/p/6726251.html
如果文章有錯的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號:Java3y
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/71055.html
摘要:線程不安全底層數(shù)據(jù)結(jié)構(gòu)是鏈表。的默認(rèn)初始化容量是,每次擴容時候增加原先容量的一半,也就是變?yōu)樵瓉淼谋秳h除元素時不會減少容量,若希望減少容量則調(diào)用它不是線程安全的。 前言 聲明,本文用得是jdk1.8 前一篇已經(jīng)講了Collection的總覽:Collection總覽,介紹了一些基礎(chǔ)知識。 現(xiàn)在這篇主要講List集合的三個子類: ArrayList 底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組。線程不安全 ...
摘要:接口在類庫中有很多具體的實現(xiàn)。接口的意義是為各種具體的集合提供了最大化的統(tǒng)一操作方式。集合類框架的基本接口代表一組對象,每一個對象都是他的子元素不包含重復(fù)元素的有序的,可以包含重復(fù)元素將映射到的對象,不能重復(fù)。 寫在之前: 這篇文章是自己面試過程中,總結(jié)出來的關(guān)于Java集合類的總結(jié)。每次面試之前來出來看看,速度快,也能很迅速的回憶一些細(xì)節(jié)問題。發(fā)布這篇文章,不僅僅是希望大家臨陣磨槍,...
摘要:面試總結(jié)最近兩周面試了幾家公司高級工程師的職位,主要有宜信網(wǎng)信金融阿里高德口袋購物。目前有部分公司已經(jīng)面試通過,兩家在等消息。今天趁熱把常見面試內(nèi)容總結(jié)一下。可以用來完成統(tǒng)一命名服務(wù)狀態(tài)同步服務(wù)集群管理分布式應(yīng)用配置項等管理工作。 面試總結(jié) 最近兩周面試了幾家公司Java高級工程師的職位,主要有宜信、網(wǎng)信金融、阿里高德、口袋購物。目前有部分公司已經(jīng)面試通過,兩家在等消息。今天趁熱把常見...
摘要:實現(xiàn)移除給定的元素要移除的元素返回值表示移除成功方法說明移除單向鏈表中某個位置的元素。的前端樂園原文鏈接寒假前端學(xué)習(xí)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法二鏈表 本系列的第一篇文章: 學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(一),棧與隊列第二篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(二):鏈表第三篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(三):集合第四篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與...
閱讀 1351·2023-04-25 15:21
閱讀 2684·2021-11-24 10:23
閱讀 3409·2021-10-11 10:59
閱讀 3255·2021-09-03 10:28
閱讀 1739·2019-08-26 13:45
閱讀 2329·2019-08-26 12:11
閱讀 929·2019-08-26 12:00
閱讀 1718·2019-08-26 10:44