C 鏈表的操作(C語言實現)

原博客地址:http://blog.csdn.net/lpp0900320123/article/details/20356143

簡述

最近在做外部FLASH的動態存儲(鏈表方式),對鏈表理解嚴重欠缺,在此標記補補。
學習數據結構,毋庸置疑鏈表必須學好,後面的棧、隊列、樹、圖都是以鏈表爲基礎的;鏈表的種類很多,有單鏈表、雙鏈表、循環鏈表、非循環鏈表;在此,我們以非循環單鏈表爲例,來講鏈表的創建、求長度、排序、插入和排序。

什麼是鏈表

鏈表包含以下特徵:
(1)由n個節點離散分配;
(2)每個節點通過指針連接;
(3)每一個節點由一個前驅節點和一個後驅節點;
(4)首節點沒有前驅節點,尾節點沒有後驅節點。

滿足上面的4條,我們就稱爲鏈表;鏈表既然由很多個節點,那節點又由什麼組成?節點由兩個部分組成,一是數據域,用來存放有效數據;二是指針域,用來指向下一個節點;下面用C語言來構建鏈表數據結構,首先應該構造出節點,然後再把所有的節點連起來,就構成了鏈表。

節點的構造

typedef struct Node  
{  
    int data;//數據域,用來存放數據域;  
    struct Node *pNext;//定義一個結構體指針,指向下一次個與當前節點數據類型相同的節點  
}NODE,*PNODE;  //NODE等價於 struct Node; PNODE等價於struct Node *; 此處用大寫是爲了與變量區分,可以讓人容易變出是個數據類型  

typedef 只是給數據類型取個別名,即 typedef 數據類型 別名;我們知道struct Node 是我們定義的數據類型。

鏈表的創建

在創建鏈表之前,我們需要需要了解一下專業術語:
1. 首節點:存放第一個有效數據的節點;
2. 尾節點:存放最後一個有效數據的節點;
3. 頭節點:頭節點的數據類型與首節點的數據類型相同,並且頭節點是首節點前面的那個節點,並不存放有效數據;頭節點的存在只是爲了方便鏈表的操作;
4. 頭指針:指向頭節點的指針;
5. 尾指針:指向尾節點的指針。

首先,我們應該創建一個頭節點,並用頭指針指向它,用C語言描述:用malloc向計算機申請一塊內存,並定義一個指向與頭節點數據類型相同的指針(一定要判斷申請內存是否成功)。

然後,要知道要創建鏈表的長度,用一個循環來每次創建一個節點,並把每個節點連在一起;
鏈表示意圖

假如我們要在頭節點phead後面插入節點p:
(1)把頭節點的指針域指向P節點,即pHead->pNext=p;
(2)把p節點的指針域指向NULL,即p->pNext=NULL;

這樣就可以了嗎? 想想我們就可以發現,當我們要插入多個節點時,頭節點始終指向最後添加的一個數據,以前的節點通過頭指針此時已經找不到了;我們定義一個尾指針pTail,始終用來指向鏈表的結尾,每次只在pTail後面添加節點。

僞算法:
(1)定義一個尾指針pTail,並初始化,使它指向頭節點,即pTail=pHead;
(2)在pTail後面添加節點,修改指針:
        pTail->pNext=p;
        p->pNext=NULL;
        pTail=p; //使pTail指向鏈表最後一個元素

程序代碼如下:

PNODE Create_List(void)  
{  
    int len;  //存放鏈表的長度  
    int i;   //循環變量  
    int val;//用來臨時存放用戶輸入的結點的值  
    PNODE List;  
    PNODE pHead=(PNODE)malloc(sizeof(NODE));//分配一個頭節點  
    if(NULL==pHead)  
    {  
        printf("Memory allocation failure");  
        exit(-1);  
    }  
    else  
    {   PNODE pTail=pHead;  
        pHead->pNext=NULL;   
        printf("please input the length of list: ");  //需要一個指針始終指向鏈表的結尾  
        scanf("%d",&len);  
        for(i=0;i<len;i++)  
        {  
            PNODE p=(PNODE)malloc(sizeof(NODE));  
            if(NULL==p)  
            {  
                printf("Memory allocation failure");  
                exit(-1);  
            }  
            else  
            {     
                printf("please input the value of list: ");  
                scanf("%d",&val);  
                p->data=val;  
                pTail->pNext=p;  
                p->pNext=NULL;  
                pTail=p;  
            }  
        }  
    }  
    return pHead;  
}  

向鏈表中插入元素

鏈表中插入元素
假如要在節點2的前面插入節點p,我們首先要找到節點2的前驅節點1,假設現在q指針指向節點1,則
(1)p->pNext=q->pNext;
(2)q->pNext=p;

程序代碼如下:

//鏈表的第pos有效元素前面插入元素val,首先我們應該找到第pos個元素前面一個元素的位置;  
//當鏈表有3個元素時,pos=4,將不會進行插入操作  
bool Insert_List(PNODE pHead,int pos,int val)  
{  
    int i=0;  
    PNODE p=pHead;  
    while((NULL!=p)&&(i<pos-1)) //  
    {  
        p=p->pNext;  
        i++;  
    }  
    if(p==NULL||i>pos-1)  //把鏈表爲空的情況考慮進去了;i>pos-1 可以防止用戶輸入錯誤;  
        return false;  

    //程序執行到這之後,i=pos-1;p指針指向鏈表第pos個有效節點的前驅,即指向第pos-1節點;  
    PNODE q=(PNODE)malloc(sizeof(NODE));  
    q->data=val;  
    q->pNext=p->pNext;  
    p->pNext=q;  
}  

刪除鏈表中的元素

刪除鏈表中的元素
假如要刪除節點2,只需要把節點1指針域指針指向節點3,但不要忘記釋放節點2所佔的內存,否則將會造成內存泄漏;首先必須找到節點2的前驅節點1,假設p指向節點1。

(1)q=p->pNext; //首先用q保存要刪除節點的地址;
(2)p->pNext=q->pNext; //q->pNext=p->pNext->pNext; 修改指針使節點1指向節點3;
(3)free(q); //釋放節點2所佔的內存;

程序代碼如下:

bool Delete_List(PNODE pHead,int pos,int *val)  
{  
    int i=0;  
    PNODE p=pHead;  
    while((NULL!=p)&&(i<pos-1))  
    {  
        p=p->pNext;  
        i++;  
    }  
    if(p==NULL||i>pos-1)  //把鏈表爲空的情況考慮進去了;i>pos-1 可以防止用戶輸入錯誤;  
        return false;  

    //程序執行到這之後,i=pos-1;  
    PNODE q=p->pNext;  //q指向待刪除的節點;  
    *val=q->data;  
    p->pNext=q->pNext; //修改鏈表指針指向;  
    free(q);           //釋放q所指向節點的內存;  
    q=NULL;//千萬不可以忘記,否則會出現野指針;  
}  

鏈表元素的排序

快速排序和冒泡排序的思想對於鏈表這個數據結構同樣適用,下面是一個用選擇排序來實現鏈表的排序;

程序代碼如下:

//鏈表有效元素的個數  
int Length_List(PNODE pHead)  
{   int len=0;  //定義變量要記得初始化;  
    PNODE p=pHead->pNext;  
    while(NULL!=p)  
    {  
        len++;  
        p=p->pNext;  
    }  
    return len;  
}  
//對鏈表中的元素進行排序  
void Sort_List(PNODE pHead)  
{  
    int i,j;  
    int temp;  
    int len=Length_List(pHead);  
    PNODE p,q;//指向鏈表第一個有效元素  

    for(i=0,p=pHead->pNext;i<len-1;i++/*,p=p->pNext*/)  
    {  
        for(j=i+1,q=p->pNext;j<len;j++,q=q->pNext)  
        {  
            //交換數據  
            if(p->data>q->data)  
            {  
                temp=p->data;  
                p->data=q->data;  
                q->data=temp;  
            }  
        }  
    }  
}  

和數組排序很像,只是這裏需要兩個指針p、q不停地移動,來獲取鏈表中的數據元素;

發佈了37 篇原創文章 · 獲贊 28 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章