最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#數(shù)據(jù)結(jié)構(gòu)與算法揭秘四 雙向鏈表

 更新時(shí)間:2012年11月01日 20:55:54   投稿:mdxy-dxy  
上節(jié)說(shuō)過(guò)這節(jié)會(huì)講雙向鏈表,環(huán)形鏈表和應(yīng)用舉例,我們開(kāi)始吧!?。?!

首先,明白什么是雙向鏈表。所謂雙向鏈表是如果希望找直接前驅(qū)結(jié)點(diǎn)和直接后繼結(jié)點(diǎn)的時(shí)間復(fù)雜度都是 O(1),那么,需要在結(jié)點(diǎn)中設(shè)兩個(gè)引用域,一個(gè)保存直接前驅(qū)結(jié)點(diǎn)的地址,叫 prev,一個(gè)直接后繼結(jié)點(diǎn)的地址,叫 next,這樣的鏈表就是雙向鏈表(Doubly Linked List)。雙向鏈表的結(jié)點(diǎn)結(jié)構(gòu)示意圖如圖所示。

雙向鏈表結(jié)點(diǎn)的定義與單鏈表的結(jié)點(diǎn)的定義很相似, ,只是雙向鏈表多了一個(gè)字段 prev。其實(shí),雙向鏈表更像是一根鏈條一樣,你連我,我連你,不清楚,請(qǐng)看圖。

雙向鏈表結(jié)點(diǎn)類(lèi)的實(shí)現(xiàn)如下所示

//一個(gè)鏈條的類(lèi)

public class DbNode<T>
{

//當(dāng)前的數(shù)據(jù)所在
private T data; //數(shù)據(jù)域記錄的數(shù)據(jù)的 
private DbNode<T> prev; //前驅(qū)引用域 前驅(qū) 引用位置 
private DbNode<T> next; //后繼引用域 后來(lái)鏈條的位置

//構(gòu)造器 這是不是初始化 
public DbNode(T val, DbNode<T> p)
{
data = val;
next = p;
}

//構(gòu)造器 這是不是初始化
public DbNode(DbNode<T> p)
{
next = p;
}

//構(gòu)造器  吧這個(gè)鏈子相應(yīng)值 傳遞給他
public DbNode(T val)
{
data = val;
next = null;
}

//構(gòu)造器  構(gòu)造一個(gè)空的鏈子
public DbNode()
{
data = default(T);
next = null;
}

//數(shù)據(jù)域?qū)傩?br />public T Data
{
get
{
return data;
}
set
{
data = value;
}
}

//前驅(qū)引用域?qū)傩?br />public DbNode<T> Prev
{
get
{
return prev;
}
set
{
prev = value;
}
}

//后繼引用域?qū)傩?br />public DbNode<T> Next
{
get
{
return next;
}
set
{
next = value;
}
}
}

說(shuō)了這么多雙向鏈表接點(diǎn)的類(lèi)的屬性,我們要看一看他的相關(guān)的操作。這里只做一些畫(huà)龍點(diǎn)睛地方的描述

操作:設(shè) p是指向雙向鏈表中的某一結(jié)點(diǎn),即 p存儲(chǔ)的是該結(jié)點(diǎn)的地址,現(xiàn)要將一個(gè)結(jié)點(diǎn) s 到結(jié)點(diǎn) p 的后面,的源代碼如下所示:操作如下: 

? p.Next.Prev = s;
? s.Prev = p;
? s.Next = p.Next;
? p.Next = s;

過(guò)程如圖所示(以 p 的直接后繼結(jié)點(diǎn)存在為例) 。

注意:引用域值的操作的順序不是唯一的,但也不是任意的,操作?必須放到操作?的前面完成,否則 p 直接后繼結(jié)點(diǎn)的就找不到了。這一點(diǎn)需要讀者把每個(gè)操作的含義搞清楚。此算法時(shí)間操作消耗在查找上,其時(shí)間的復(fù)雜度是O(n).

下面,看他的刪除操作,以在結(jié)點(diǎn)之后刪除為例來(lái)說(shuō)明在雙向鏈表中刪除結(jié)點(diǎn)的情況。 設(shè) p是指向雙向鏈表中的某一結(jié)點(diǎn),即 p存儲(chǔ)的是該結(jié)點(diǎn)的地址,現(xiàn)要將一個(gè)結(jié)點(diǎn) s到結(jié)點(diǎn) p的后面 。偽代碼如下:操作如下:

? p.Next = P.Next.Next;
? p.Next.Prev = p.Prev;

刪除過(guò)程如圖所示(以 p的直接后繼結(jié)點(diǎn)存在為例)

相應(yīng)的算法的時(shí)間復(fù)雜度也是消耗到結(jié)點(diǎn)的查找上,其復(fù)雜度應(yīng)該是O(n)

查找操作與單鏈表的極其的類(lèi)似,也是從頭開(kāi)始遍歷。相應(yīng)偽代碼如圖所示:

current.next=p.next.next

current.prev=p.next.prev;

相應(yīng)的偽代碼如下圖所示:

該算法的時(shí)間復(fù)雜度,是一個(gè)個(gè)的遍歷的過(guò)程中,顧時(shí)間復(fù)雜度是O(n)

獲取當(dāng)前的雙向鏈表長(zhǎng)度與 查找類(lèi)似,不做過(guò)多的贅述,這里,我們把雙向鏈表基本概念和操作基本介紹完了,下面介紹一個(gè)重要的鏈表——環(huán)形鏈表。

首先,還是老樣子,看看環(huán)形鏈表的定義。有些應(yīng)用不需要鏈表中有明顯的頭尾結(jié)點(diǎn)。在這種情況下,可能需要方便地從最后一個(gè)結(jié)點(diǎn)訪問(wèn)到第一個(gè)結(jié)點(diǎn)。此時(shí),最后一個(gè)結(jié)點(diǎn)的引用域不是空引用,而是保存的第一個(gè)結(jié)點(diǎn)的地址(如果該鏈表帶結(jié)點(diǎn),則保存的是頭結(jié)點(diǎn)的地址) ,也就是頭引用的值。我們把這樣的鏈表結(jié)構(gòu)稱(chēng)之為環(huán)形鏈表。他就像小朋友手拉手做游戲。如圖所示。

用鏈表如圖所示:

這里基本添加,刪除,操作的操作與單鏈表簡(jiǎn)直是一模一樣,這里就沒(méi)有必要寫(xiě)這些東西。我們主要看他們一些簡(jiǎn)單應(yīng)用。

應(yīng)用舉例一 已知單鏈表 H,寫(xiě)一算法將其倒置,即實(shí)現(xiàn)如圖所示的操作,其中(a)為倒置前,(b)為倒置后。

算法思路:由于單鏈表的存儲(chǔ)空間不是連續(xù)的,所以,它的倒置不能像順表那樣,把第 i 個(gè)結(jié)點(diǎn)與第 n-i 個(gè)結(jié)點(diǎn)交換(i 的取值范圍是 1 到 n/2,n 為單鏈表的長(zhǎng)度) 。其解決辦法是依次取單鏈表中的每個(gè)結(jié)點(diǎn)到新鏈表中去。并且,為了節(jié)省內(nèi)存資源,把原鏈表的頭結(jié)點(diǎn)作為新鏈表的頭結(jié)點(diǎn)。存儲(chǔ)整數(shù)的單鏈表的倒置的算法實(shí)現(xiàn)如下:

public void ReversLinkList(LinkList<int> H)
{
Node<int> p = H.Next;
Node<int> q = new Node<int>();
H.Next = null;

while (p != null)
{
q = p;
p = p.Next;
q.Next = H.Next;
H.Next = q;
}
}
該算法要對(duì)鏈表中的結(jié)點(diǎn)順序掃描一遍才完成了倒置,所以時(shí)間復(fù)雜度為O(n),但比同樣長(zhǎng)度的順序表多花一倍的時(shí)間,因?yàn)轫樞虮碇恍枰獟呙枰话氲臄?shù)據(jù)元素。這個(gè)是不是你已經(jīng)頭腦糊了嗎?如果糊了把,請(qǐng)看我的圖例的解釋。

舉例2,約瑟夫環(huán)問(wèn)題,題目如下:

已知n個(gè)人(以編號(hào)1,2,3...n分別表示)圍坐在一張圓桌周?chē)?。從編?hào)為k的人開(kāi)始報(bào)數(shù),數(shù)到m的那個(gè)人出列;他的下一個(gè)人又從1開(kāi)始報(bào)數(shù),數(shù)到m的那個(gè)人又出列;依此規(guī)律重復(fù)下去,直到圓桌周?chē)娜巳砍隽?。求最后出列的人相?yīng)的編號(hào)。

  void JOSEPHUS(int n,int k,int m) //n為總?cè)藬?shù),k為第一個(gè)開(kāi)始報(bào)數(shù)的人,m為出列者喊到的數(shù)

  {

  /* p為當(dāng)前結(jié)點(diǎn) r為輔助結(jié)點(diǎn),指向p的前驅(qū)結(jié)點(diǎn) list為頭節(jié)點(diǎn)*/

  LinkList p,r,list; /*建立循環(huán)鏈表*/

  for(int i=0;i<n;i++)

  {

  p=(LinkList)LNode;

  p.data=i;

  if(list==NULL)

  list=p;

  else

  r.link=p;

  r=p;

  }

  p.link=list; /*使鏈表循環(huán)起來(lái)*/

  p=list; /*使p指向頭節(jié)點(diǎn)*/

  /*把當(dāng)前指針移動(dòng)到第一個(gè)報(bào)數(shù)的人*/

  for(i=0;i<k;i++)

  {

  r=p;

  p=p.link;

  }

  /*循環(huán)地刪除隊(duì)列結(jié)點(diǎn)*/

  while(p.link!=p)

  {

  for(i=0;i<m-1;i++) 

  {

  r=p;

  p=p.link;

  }

  r.link=p.link;

  console.writeline("被刪除的元素:{0} ",p.data);

  free(p);

  p=r.node.;

  } 

  console.writeLine("\n最后被刪除的元素是:{0}",P.data);

    具體的算法,如圖所示:

      這個(gè)算法的時(shí)間的復(fù)雜度是O(n2)
  

  }

還和大家分享的一個(gè)例子,就是我做做一個(gè)類(lèi)似與網(wǎng)易郵箱的產(chǎn)品時(shí)候,幾千萬(wàn)甚至數(shù)以?xún)|級(jí)的大數(shù)量登錄的時(shí)候,發(fā)現(xiàn)用戶(hù)登錄的時(shí)候真慢,你猜我開(kāi)始是怎么做的,就是直接查數(shù)據(jù)庫(kù),這當(dāng)然是不行的。這怎么辦了, 最后,我在一個(gè)高人的指教下,發(fā)現(xiàn)登錄的時(shí)候速度飛快,怎么搞的。我把所有的數(shù)據(jù)庫(kù)的數(shù)據(jù)讀入到內(nèi)存中,然后把數(shù)據(jù)用鏈表把他們串起來(lái),到我查詢(xún)某個(gè)用戶(hù)時(shí)候,只比較用戶(hù)的 字節(jié)數(shù)。

這就是我眼中的鏈表結(jié)構(gòu)。

相關(guān)文章

  • 詳解C#讀取Appconfig中自定義的節(jié)點(diǎn)

    詳解C#讀取Appconfig中自定義的節(jié)點(diǎn)

    我們往往需要在App.config中自定義一些節(jié)來(lái)滿足實(shí)際需要,而不依賴(lài)于App.config的appSettings,下面通過(guò)一個(gè)簡(jiǎn)單的實(shí)例來(lái)說(shuō)明自定義配置節(jié)點(diǎn)的設(shè)置與讀取
    2015-06-06
  • C#語(yǔ)言中字符類(lèi)char的使用方法(總結(jié))

    C#語(yǔ)言中字符類(lèi)char的使用方法(總結(jié))

    下面小編就為大家?guī)?lái)一篇C#語(yǔ)言中字符類(lèi)char的使用方法(總結(jié))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • SQLite在C#中的安裝與操作技巧

    SQLite在C#中的安裝與操作技巧

    SQLite,是一款輕型的數(shù)據(jù)庫(kù),用于本地的數(shù)據(jù)儲(chǔ)存。其優(yōu)點(diǎn)有很多,下面通過(guò)本文給大家介紹SQLite在C#中的安裝與操作技巧,感興趣的的朋友參考下吧
    2017-08-08
  • C# listview添加combobox到單元格的實(shí)現(xiàn)代碼

    C# listview添加combobox到單元格的實(shí)現(xiàn)代碼

    從別處轉(zhuǎn)來(lái)的,自己進(jìn)行了一些小的修改,還不錯(cuò),你自己先拖一個(gè)ListView1和一個(gè)ComboBox1,需要的朋友可以參考下
    2014-06-06
  • C#實(shí)現(xiàn)軟件開(kāi)機(jī)自啟動(dòng)的示例代碼

    C#實(shí)現(xiàn)軟件開(kāi)機(jī)自啟動(dòng)的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)軟件開(kāi)機(jī)自啟動(dòng),且不需要管理員權(quán)限,文中的示例代碼講解詳細(xì),需要的小伙伴可以參考一下
    2023-07-07
  • C#中類(lèi)與接口的區(qū)別個(gè)人總結(jié)

    C#中類(lèi)與接口的區(qū)別個(gè)人總結(jié)

    這篇文章主要介紹了C#中類(lèi)與接口的區(qū)別個(gè)人總結(jié),本文講解了類(lèi)與接口的區(qū)別、接口的用處主要體現(xiàn)在下面幾個(gè)方面、一些接口的疑問(wèn)等內(nèi)容,需要的朋友可以參考下
    2015-06-06
  • C#中進(jìn)程的掛起與恢復(fù)

    C#中進(jìn)程的掛起與恢復(fù)

    這篇文章主要介紹了C#中進(jìn)程的掛起與恢復(fù)操作方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03
  • C# 調(diào)用WebService的方法

    C# 調(diào)用WebService的方法

    這篇文章主要介紹了C# 調(diào)用WebService的方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-08-08
  • c#數(shù)字圖像處理的3種方法示例分享

    c#數(shù)字圖像處理的3種方法示例分享

    這篇文章主要介紹了c#數(shù)字圖像處理的3種方法示例,需要的朋友可以參考下
    2014-02-02
  • C#組件系列 你值得擁有的一款Excel處理神器Spire.XLS

    C#組件系列 你值得擁有的一款Excel處理神器Spire.XLS

    又一款Excel處理神器Spire.XLS,這篇文章主要為大家詳細(xì)介紹了第三方組件Spire.XLS,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09

最新評(píng)論

隆昌县| 沙雅县| 内黄县| 高邑县| 马山县| 汉中市| 临漳县| 瑞安市| 梅州市| 舞钢市| 衡阳市| 沈阳市| 江城| 韶关市| 辰溪县| 孟州市| 赤壁市| 库伦旗| 青海省| 垦利县| 西丰县| 宾川县| 凌云县| 繁峙县| 纳雍县| 黄冈市| 宕昌县| 馆陶县| 周口市| 湘潭县| 永济市| 兴海县| 天祝| 巨鹿县| 涞水县| 房产| 涿州市| 盘山县| 甘孜| 富平县| 乐都县|