java資料結構—單鏈表的實現原理
再次學習資料額結構,看到前面的單鏈表,感覺裡面的思路很不錯,自己動手寫程式碼嘗試一下,果然一動手就發現自己並沒有完全理解。這裡主要記錄我花了很長時間才理解的地方,不去考慮增刪改查,我覺得這些功能在很多地方都實現過,不是重點,也有很多資料可查。
單鏈表的原理網上很多,這裡也不解釋,先上程式碼。
這是一個節點類,用於記錄節點內容和物件引用(地址),其中不包含一些基本功能,只寫了必要的函式。
public class Node {
Object data;//節點包含的具體內容
Node next;//節點的引用,用於指向下一個節點
Node (Node i){//建構函式1,用於初始化頭結點
next=i;
}
Node (Object i,Node j){//建構函式2,用於其他節點。
data=i;
next=j;
}
public void setnext(Node nextval){//這個函式作用是把其他節點的引用指向這個節點。
next=nextval;
}
public Object getelement(){//獲取節點的內容
return data;
}
}
這是我第一次做的測試函式
public class main_Node {
public static void main(String[] args) {
Node head;//頭結點
Node current;//表示當前節點
current=head=new Node(null);//初始化為空
current.setnext(new Node(1,head.next));//新增一個節點
current.setnext(new Node(2,current.next));//新增兩個節點
current.setnext(new Node(3,current.next));//新增三個節點
current=head.next;//讓current表示head的下一個節點,也就是第一個節點。
int a=(int)current.getelement();//獲取該節點的內容
System.out.println(a);//列印
}
}
結果為3,這裡就有問題了,我命名讓他指向第一個節點,應該是1才對呀,怎麼會變成第三個呢?debug的結果是這樣的::
可以看出來,這裡的head直接指向的是3,剛好反過來了,所以剛才得出的值是3。
看似很簡單的問題,我還是花了很長時間才發現問題。其實原因是這樣新增節點時,current所指向的節點並沒有變,還是在頭結點位置,新增節點並不能使current表示的節點後移,所以解決辦法是在每次添加了新的節點後把current往後移一下,讓它指向新新增的節點,這樣才能在新新增的節點後面再新增節點。程式碼如下:
public class main_test1 {
public static void main(String[] args) {
test1 head;
test1 current;
current=head=new test1(null);//這裡也表示current指向頭結點
current.setnext(new test1(1,head.next));
current=current.next;//使current指向下一個節點
current.setnext(new test1(2,current.next));
current=current.next;
current.setnext(new test1(3,current.next));
current=current.next;
current=head.next;
int a=(int)current.getelement();
System.out.println(a);
}
}
結果為1。這次正確了,再看debug圖:
看,這下順序就對了。
這裡主要的問題是,沒有想到新增新節點後想在其後面繼續新增,是要先移動當前current所指向的節點的位置的。感覺以後這個思路會給我幫助,記錄下來方便以後複習。
對這篇部落格的一些地方做一些補充,記錄自己思考的結果:
第八點:連結串列有環,如何判斷相交:
我自己想了另一種方法,應該比部落格中的效率高一點,其實也是借鑑了上面的思想,設定三個節點,其中一快一慢(和前面的一個意思,快的前進兩格)指向head1,另一個快指向head2。這裡思路是:如果兩個有環連結串列相交(這裡不考慮兩個無環連結串列相交的情況),那麼當前面設定的三個節點都進入環中的時候,就可以利用head2_fast去追趕head1_low,這裡最關鍵的地方是考慮什麼時候停止追趕,因為環內是可以無限迴圈的。仔細琢磨第5點的原理就能找到關鍵點了,看程式碼理解吧:
public boolean isIntersect(Node head1,Node head2){
//設定三個節點
Node head1_low=head1;
Node head1_fast=head1;
Node head2_fast=head2;
while(head1_fast!=null && head1_fast.next!=null && head2_fast!=null && head2_fast.next!=null){//如果有無環連結串列直接判斷不相交
head1_low=head1_low.next;
head1_fast=head1_fast.next.next;
head2_fast=head2_fast.next.next;
if(head1_low==head2_fast)//過程中如果運氣好,可以直接得到相交
return true;
else if(head1_low==head1_fast){//核心,也就是找到慢指標和快指標相交的點後就進行head2_fast追趕head1_low
do{//這裡有個問題,如果head2除了環之外的部分特別長,那麼這裡是不成立的,就需要設立第四個節點,後面給出
head1_low=head1_low.next;
head2_fast=head2_fast.next.next;
if(head1_low==head2_fast)
return true;
}while(head1_low.next!=head1_fast);//如果相交,head1_low跑一圈內必然能夠相等。
return false;
}
}
return false;
}
給出上面的修正程式碼,其實就是要確認開始追趕時head2_fast已經進入環內,不然會出現head1_low跑完一圈head2_fast還未進環的情況,同樣通過給head2_fast也找個相交點來判斷是否進環:
public boolean isIntersect(Node head1,Node head2){
Node head1_low=head1;
Node head1_fast=head1;
Node head2_low=head2;
Node head2_fast=head2;
while(head1_fast!=null && head1_fast.next!=null && head2_fast!=null && head2_fast.next!=null){
head1_low=head1_low.next;
head1_fast=head1_fast.next.next;
head2_low=head1_low.next;
head2_fast=head2_fast.next.next;
if(head1_low==head2_fast)
return true;
else if(head1_low==head1_fast){
while(head2_low!=head2_fast){
head2_low=head1_low.next;
head2_fast=head2_fast.next.next;
if(head2_fast!=null && head2_fast.next!=null)
return false;
}
do{
head1_low=head1_low.next;
head2_fast=head2_fast.next.next;
if(head1_low==head2_fast)
return true;
}while(head1_low.next!=head1_fast);
return false;
}
else if(head2_low==head2_fast){
while(head1_low!=head1_fast){
head1_low=head1_low.next;
head1_fast=head1_fast.next.next;
if(head1_fast!=null && head1_fast.next!=null)
return false;
}
do{
head1_low=head1_low.next;
head2_fast=head2_fast.next.next;
if(head1_low==head2_fast)
return true;
}while(head1_low.next!=head1_fast);
return false;
}
}
return false;
}
其實變化不大,看一看就明白,不過這樣一來和原方法比較優勢就不明顯了。總之提供一種思路吧(以上方法沒有經過檢驗,可能有瑕疵)。
第九點:兩連結串列相交的第一個公共節點:
博主沒有寫這種方法,也許是他覺得沒必要,因為所有東西部落格上都提到了,有心人應該是自己能推理出來的:
把一個連結串列接到另一個連結串列的尾部,形成環,再用判斷環的入口,就ok了。是不是所有東西部落格裡都有寫到?
相關推薦
java資料結構—單鏈表的實現原理
再次學習資料額結構,看到前面的單鏈表,感覺裡面的思路很不錯,自己動手寫程式碼嘗試一下,果然一動手就發現自己並沒有完全理解。這裡主要記錄我花了很長時間才理解的地方,不去考慮增刪改查,我覺得這些功能在很多地方都實現過,不是重點,也有很多資料可查。 單鏈表的原理網上
資料結構——單鏈表實現
鏈式儲存特點 在鏈式儲存中,節點之間的儲存單元地址可能是不連續的。鏈式儲存中每個結點都包含兩部分:儲存元素本身的資料域和儲存結點地址的指標域。結點中的指標指向的是下一個結點,也就是儲存的下一個結點的地址。 鏈式儲存的實現 1.建立連結串列 在建立連結串列時,頭結點不儲存資料,
資料結構——單鏈表實現及操作(c語言)
#include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #d
資料結構 單鏈表實現 純程式碼
單鏈表操作函式原型宣告 node_t *list_init(); //顯示單鏈表 void display(node_t *head); //在單鏈表上查詢第i個節點的存放地址 node_t *find(node_t *head,int i); //在單鏈表上第I個節點後面
C/C++,資料結構單鏈表實現約瑟夫環
約瑟夫環——圍成一圈,定義一個數值K,從任意位置開始計數,每走K步刪除當前位置結點,直到剩下最後一個結點,求最後一個結點//單鏈表結構以及Find函式參見 2016-1-2 13:56 發表部落格SLi
java資料結構之手動實現單鏈表
package com.example.demo; // 1、定義要儲存物件的類: class Phone {// 此類提供要儲存的資料 private String brand; private double price; public Phon
資料結構(Java):用單鏈表實現多項式相加
要求: 1.已知有兩個多項式Pn(x)和Qm(x),並且在Pn(x)和Qm(x)中指數相差很多,設計演算法,求Pn(x)+Qm(x) 2.進行加法運算時不重新開闢儲存空間。 //定義節點類 class Node{ public int coef;//係數 p
資料結構-單鏈表進階之快慢指標原理(快速查詢法)
面試題:快速找到未知長度單鏈表的中間節點?這個問題的解決方法分為普通方法和高階方法。1.普通方法即我們大家都能一下子想到的,首先遍歷一遍獲取總長度L,然後再次遍歷迴圈至L/2即可;時間複雜度為:O(L+L/2)=O(3/2L)程式碼簡單實現:typedef struct {
資料結構單鏈表的定義(Java)
定義一個介面 public interface ILinarList<E> { public abstract boolean add(E item); //新增元素 public abstract boole
資料結構-單鏈表操作
// // main.c // Link_List // // Created by Smallflyfly on 2018/11/9. // Copyright © 2018 fang. All rights reserved. // #include <stdio.h>
python與資料結構-單鏈表
https://www.bilibili.com/video/av21540971/?p=10 1、python 中變數標識的本質 python 中等號的本質就是一個"引用連結”(變數皆指標),【與c和c++不一樣,c、c++是&表示地址,指標】 2、 3、遍歷連結串列
資料結構-單鏈表
說明 與順序表相比,允許儲存空間不連續,插入刪除時不需要移動大量的元素,只需修改指標即可,但查詢某個元素,只能從頭遍歷整個連結串列。 程式碼 /* ** slink create by yubo.wang 2018.9.12 */ #include <st
資料結構——單鏈表(環)
一、環 標題 二、建立環 //建立環 public void createLoop(){ Entry cur = this.head; while(cur.next != null){
嚴蔚敏版資料結構——單鏈表
嚴蔚敏版資料結構——單鏈表的操作 記得前上個禮拜,我寫過的一個版本的單鏈表的建立。今天寫下了這個嚴蔚敏版的單鏈表。梳理了一下思路,其基本演算法還是一樣的,還是那句話,理解,理解,理解最重要。這個版本的單鏈表我要提醒自己的是:1、這是直接在函式中採用引用L
資料結構--順序表實現資料處理系統(C語言)
#include<stdio.h> #include<stdlib.h> #define MAXSIZE 10 #define OK 1 #define ERROR 0 #define true 1 typedef int Status;
資料結構-單鏈表交換節點
普通情況的結點交換 temp_pre->next = p; p_pre->next = p->next;//key step p->next = temp->next; temp->
資料結構--單鏈表
single_linklist.h #ifndef __SINGLE_LINKLIST_H__ #define __SINGLE_LINKLIST_H__ #include <stdio.h> #include <stdlib.h>
資料結構-單鏈表翻轉
public class Node { private Node next; private int value; public boolean hasNext() { return next != null; }
浙大資料結構 單鏈表逆轉
6-8 單鏈表逆轉 (20 分) 本題要求實現一個函式,將給定的單鏈表逆轉。 函式介面定義: List Reverse( List L ); 其中List結構定義如下: typedef struct Node *PtrToNode; struct Node {
C語言資料結構單鏈表之溫故而知新
拋棄繁雜的定義,以實用,實戰的角度來學習資料結構,這將使得資料結構的學習非常的簡單。前面已經學習了單鏈表的建立操作:http://blog.csdn.net/morixinguan/article/details/68951912這節,將單鏈表溫習的筆記共享出來,然後寫一個例