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

C語言雙向鏈表的原理與使用操作

 更新時間:2022年05月23日 10:50:40   作者:Mi?ronin  
雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數(shù)據(jù)結(jié)點中都有兩個指針,分別指向直接后繼和直接前驅(qū)。本文主要介紹了C語言算法中雙向鏈表的實現(xiàn),需要的可以參考一下

一.引入

我們在單鏈表中,有了next指針,這個指針是用來指向下一個節(jié)點的,如果我們需要查找下一個結(jié)點的時間復雜度為o(1),如果我們需要查找上一個節(jié)點的時候,那么時間復雜度就變?yōu)閛(n)了,需要從頭進行遍歷一遍;這時我們就會想:如果可以向前查找就方便了許多,因此我們引入了雙向鏈表。

二.雙向鏈表的定義

雙向鏈表:是在單鏈表的每個節(jié)點中,再設(shè)置一個指向前驅(qū)結(jié)點的指針域。

顧名思義就是鏈表由單向的變成了雙向的,每一個節(jié)點由原來的一個指針變?yōu)閮蓚€指針,一個用來指向直接后繼,另一個用來指向直接前驅(qū)。

三.雙向鏈表與單鏈表對比

通過對比可以更好認識二者的聯(lián)系與區(qū)別。

3.1圖示對比

單鏈表:

雙向鏈表:

3.2代碼對比

單鏈表代碼如下:

typedef struct Node{ //定義單鏈表結(jié)點類型
	int data; //數(shù)據(jù)域,可以是別的各種數(shù)據(jù)類型
	struct Node *next; //指針域
}LNode, *LinkList;

雙向鏈表代碼如下:

typedef struct DulNode{
	int data;			// 	數(shù)據(jù)域
	struct DulNode *prior;		//  向前的指針
	struct DulNode *next;		//  向后的指針
}DulNode,*DuLinkList;

四.雙向鏈表的操作

雙向鏈表是單鏈表中擴展出來的結(jié)構(gòu),所以有很多的操作是和單鏈表相同的,如求長度,查找元素,獲取一個元素,這里我們對雙向鏈表進行創(chuàng)建,插入,刪除,銷毀的一系列操作。

4.1雙向鏈表的創(chuàng)建

雙向鏈表在初始化時,要給首尾兩個節(jié)點分配內(nèi)存空間。成功分配后,需要將首節(jié)點的prior指針和尾節(jié)點的next指針都指向NULL,這是十分關(guān)鍵的一步,因為這是之后用來判斷空表的條件。并且當鏈表為空時,要將首節(jié)點的next指向尾節(jié)點,尾節(jié)點的prior指向首節(jié)點。

pElem CreatList(){
	pElem head = (pElem)malloc( sizeof(eElem) );
	assert( head != NULL );		//進行斷言
	head->next = head->prior = NULL;//初始化鏈表指針置空
	return head;
}

4.2雙向鏈表的插入

雙向鏈表的插入其實并不復雜,只是在原有單鏈表的基礎(chǔ)上多了連接一個向前的指針而已。但是需要注意的是操作的順序很重要,不可以寫反了。

以下面這個為例,假設(shè)存儲元素e的結(jié)點為s,要實現(xiàn)將結(jié)點s插入到結(jié)點p和p->next之間

核心代碼就只有以下四行:

s->prior=p; //把p賦值給s的前驅(qū)
s->next=p->next;// 把p->next賦值給s的后繼
p->next->prior=s;// 把s賦值給p->next的前驅(qū)
p->next=s;   //把s賦值給p的后繼

切記順序不可以記錯 在寫代碼的時候可以將操作步驟畫出來,理清實施步驟的順序。

4.3雙向鏈表的刪除

如果將插入操作的原理理解后,那么刪除就很好理解了。

刪除只需要兩個步驟:

核心代碼只有三行:

p->prior->next=p->next; //把p->next賦值給p->prior的后繼
p->next->prior=p->prior;//把p->prior賦值給p->next的前驅(qū)
free(p); //釋放結(jié)點

4.4雙向鏈表的銷毀

銷毀一個雙向鏈表的操作同單鏈表的相似。指針不斷向后運動,每運動一個結(jié)點,釋放上一個結(jié)點。

代碼如下:

void DestroyList( pElem head ){
	pElem tmp;
	while( head->next != NULL ){
		tmp = head;		//  指針不斷后移
		head = head->next;
		free(tmp);
	}
	free(head);
}

五.總結(jié)

雙向鏈表相比于單鏈表來說,是更復雜一些的,畢竟多了一個prior指針,對于插入和刪除需要特別注意這兩種操作的核心思想以及操作順序。另外雙向鏈表,帶來了方便,可以有效提高算法的時間性能。

六.全部代碼

這里引用一位大佬寫的代碼,將頭插法和尾插法創(chuàng)建表都寫了,寫的很細節(jié),很清楚大家可以參考一下。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int status;
typedef int elemtype;
typedef struct node{
    elemtype data;
    struct node * next;
    struct node * prior;
}node;
typedef struct node* dlinklist;
status visit(elemtype c){
    printf("%d ",c);
}
/*雙向鏈表初始化*/
status initdlinklist(dlinklist * head,dlinklist * tail){
    (*head)=(dlinklist)malloc(sizeof(node));
    (*tail)=(dlinklist)malloc(sizeof(node));
    if(!(*head)||!(*tail))
        return ERROR;
    /*這一步很關(guān)鍵*/ 
    (*head)->prior=NULL;
    (*tail)->next=NULL;
    /*鏈表為空時讓頭指向尾*/
    (*head)->next=(*tail);
    (*tail)->prior=(*head);
}
/*判定是否為空*/
status emptylinklist(dlinklist head,dlinklist tail){
    if(head->next==tail)
       return TRUE;
    else
       return FALSE;
} 
/*尾插法創(chuàng)建鏈表*/ 
status createdlinklisttail(dlinklist head,dlinklist tail,elemtype data){
    dlinklist pmove=tail,pinsert;
    pinsert=(dlinklist)malloc(sizeof(node));
    if(!pinsert)
         return ERROR;
    pinsert->data=data;
    pinsert->next=NULL;
    pinsert->prior=NULL;
    tail->prior->next=pinsert;
    pinsert->prior=tail->prior;
    pinsert->next=tail;
    tail->prior=pinsert;
} 
/*頭插法創(chuàng)建鏈表*/ 
status createdlinklisthead(dlinklist head,dlinklist tail,elemtype data){
    dlinklist pmove=head,qmove=tail,pinsert;
    pinsert=(dlinklist)malloc(sizeof(node));
    if(!pinsert)
        return ERROR;
    else{
        pinsert->data=data;
        pinsert->prior=pmove;
        pinsert->next=pmove->next;
        pmove->next->prior=pinsert;
        pmove->next=pinsert;
    }
}
/*正序打印鏈表*/ 
status traverselist(dlinklist head,dlinklist tail){
    /*dlinklist pmove=head->next;
    while(pmove!=tail){
        printf("%d ",pmove->data);
        pmove=pmove->next;
    }
    printf("\n");
    return OK;*/
    dlinklist pmove=head->next;
    while(pmove!=tail){
        visit(pmove->data);
        pmove=pmove->next;
    }
    printf("\n");
}
/*返回第一個值為data的元素的位序*/
status locateelem(dlinklist head,dlinklist tail,elemtype data){
    dlinklist pmove=head->next;
    int pos=1;
    while(pmove&&pmove->data!=data){
        pmove=pmove->next;
        pos++;
    }
    return pos;
}
/*返回表長*/
status listlength(dlinklist head,dlinklist tail){
    dlinklist pmove=head->next;
    int length=0;
    while(pmove!=tail){
        pmove=pmove->next;
        length++;
    }
    return length;
}
/*逆序打印鏈表*/
status inverse(dlinklist head,dlinklist tail){
    dlinklist pmove=tail->prior;
    while(pmove!=head){
        visit(pmove->data);
        pmove=pmove->prior;
    }
    printf("\n");
}
/*刪除鏈表中第pos個位置的元素,并用data返回*/
status deleteelem(dlinklist head,dlinklist tail,int pos,elemtype *data){
    int i=1;
    dlinklist pmove=head->next;
    while(pmove&&i<pos){
        pmove=pmove->next;
        i++;
    }
    if(!pmove||i>pos){
        printf("輸入數(shù)據(jù)非法\n");
        return ERROR;
    }
    else{
        *data=pmove->data;
        pmove->next->prior=pmove->prior;
        pmove->prior->next=pmove->next;
        free(pmove);
    }
}
/*在鏈表尾插入元素*/
status inserttail(dlinklist head,dlinklist tail,elemtype data){
    dlinklist pinsert;
    pinsert=(dlinklist)malloc(sizeof(node));
    pinsert->data=data;
    pinsert->next=NULL;
    pinsert->prior=NULL;
    tail->prior->next=pinsert;
    pinsert->prior=tail->prior;
    pinsert->next=tail;
    tail->prior=pinsert;
    return OK;
} 
int main(void){
    dlinklist head,tail;
    int i=0;
    elemtype data=0;
    initdlinklist(&head,&tail);
    if(emptylinklist(head,tail))
        printf("鏈表為空\n");
    else
        printf("鏈表不為空\n");
    printf("頭插法創(chuàng)建鏈表\n"); 
    for(i=0;i<10;i++){
        createdlinklisthead(head,tail,i);
    }
    traverselist(head,tail);
    for(i=0;i<10;i++){
        printf("表中值為%d的元素的位置為",i); 
        printf("%d位\n",locateelem(head,tail,i));
    }
    printf("表長為%d\n",listlength(head,tail));
    printf("逆序打印鏈表");
    inverse(head,tail);
    for(i=0;i<10;i++){
        deleteelem(head,tail,1,&data);
        printf("被刪除的元素為%d\n",data);
    }
    traverselist(head,tail);
    if(emptylinklist(head,tail))
        printf("鏈表為空\n");
    else
        printf("鏈表不為空\n");
        printf("尾插法創(chuàng)建鏈表\n");
    for(i=0;i<10;i++){
        //inserttail(head,tail,i);
        createdlinklisttail(head,tail,i);
    }
    traverselist(head,tail);
    printf("逆序打印鏈表");
    inverse(head,tail);
}

到此這篇關(guān)于C語言雙向鏈表的原理與使用操作的文章就介紹到這了,更多相關(guān)C語言雙向鏈表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實現(xiàn)井字棋詳解

    C語言實現(xiàn)井字棋詳解

    這篇文章主要為大家介紹了C語言如何實現(xiàn)井字棋,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • C++選擇排序算法實例詳解

    C++選擇排序算法實例詳解

    這篇文章主要為大家詳細介紹了C++選擇排序算法實例,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • C++學習之Lambda表達式的用法詳解

    C++學習之Lambda表達式的用法詳解

    Lambda?表達式(lambda?expression)是一個匿名函數(shù),Lambda表達式基于數(shù)學中的λ演算得名。本文就來為大家詳細講講C++中Lambda表達式的使用,需要的可以參考一下
    2022-07-07
  • Qt QChart 創(chuàng)建圖表的實現(xiàn)方法

    Qt QChart 創(chuàng)建圖表的實現(xiàn)方法

    這篇文章主要介紹了Qt QChart 創(chuàng)建圖表的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • c++中的bind使用方法

    c++中的bind使用方法

    bind是這樣一種機制,它可以預先把指定可調(diào)用實體的某些參數(shù)綁定到已有的變量,產(chǎn)生一個新的可調(diào)用實體,這種機制在回調(diào)函數(shù)的使用過程中也頗為有用。接下來通過本文給大家介紹c++中的bind使用方法,感興趣的朋友一起看看吧
    2022-01-01
  • C++智能指針實例詳解

    C++智能指針實例詳解

    這篇文章主要介紹了C++智能指針實例詳解,需要的朋友可以參考下
    2014-07-07
  • C++?二進制文件讀寫方式及示例詳解

    C++?二進制文件讀寫方式及示例詳解

    這篇文章主要為大家介紹了C++?二進制文件讀寫實現(xiàn)方式及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • 使用C++實現(xiàn)給PDF文檔添加文字水印

    使用C++實現(xiàn)給PDF文檔添加文字水印

    這篇文章主要為大家詳細介紹了如何通過第三方國產(chǎn)庫Spire.PDF?for?C++來實現(xiàn)給PDF文檔添加文字水印,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-11-11
  • QT實現(xiàn)單詞檢索軟件的示例代碼

    QT實現(xiàn)單詞檢索軟件的示例代碼

    本文主要介紹了QT實現(xiàn)單詞檢索軟件的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++中的哈希容器unordered_map使用示例

    C++中的哈希容器unordered_map使用示例

    這篇文章主要介紹了C++中的哈希容器unordered_map使用示例,本文直接給出實例代碼,并講解了一些hash table的知識,需要的朋友可以參考下
    2015-06-06

最新評論

肃南| 合山市| 长兴县| 含山县| 明溪县| 太康县| 滨海县| 乐都县| 临夏市| 益阳市| 枣强县| 钟祥市| 武强县| 莱西市| 视频| 樟树市| 德江县| 黑龙江省| 张北县| 古田县| 甘肃省| 调兵山市| 景洪市| 镇江市| 铅山县| 邵阳县| 惠水县| 阿瓦提县| 沽源县| 英超| 翼城县| 丹阳市| 安远县| 铁岭县| 长治县| 出国| 巴青县| 四会市| 鱼台县| 马山县| 江北区|