1. 程式人生 > >C語言單鏈表及基本操作的實現

C語言單鏈表及基本操作的實現

        資料結構中,單向連結串列(又名單鏈表、線性連結串列)是連結串列的一種,其特點是連結串列的連結方向是單向的,對連結串列的訪問要通過從頭部開始,依序往下讀取。

        下面的程式碼是使用指標實現的一個單鏈表,稱為動態單鏈表;當然,也可以使用陣列實現一個單鏈表,為靜態單鏈表,後面學習之後,再用陣列實現單鏈表。

完整程式碼如下:

一、定義標頭檔案:list.h

#ifndef LIST_H_INCLUDED
#define LIST_H_INCLUDED
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;

List MakeEmpty(List L);     //生成空連結串列L

void DestroyList(List L);   //銷燬連結串列L

_Bool IsEmpty(List L);        //判定連結串列是否為空

_Bool IsLast(Position P, List L);   //判定位置P的節點是否為尾結點

int Length(List L);  //檢視連結串列長度

Position Find(int X, List L); //在連結串列L中查詢資料項為X的第一個結點

void Delete(int X, List L); //在連結串列L中刪除資料項為X的第一個結點

Position FindPrevious(int X, List L); //在連結串列L中查詢資料項為X的第一個結點的前驅位置

Position FindNext(int X,List L); //在連結串列L中查詢資料項為X的第一個結點的後繼位置

void Insert(int X, List L, Position P); //在連結串列L中P位置插入資料項為X的結點

void DeleteList(List L); //刪除連結串列L頭結點外的所有結點

Position Header(List L);  //獲得連結串列L中頭結點位置

Position First(List L);   //獲得連結串列L中第一個資料結點的位置

Position Advance(Position P); //獲得P位置的後繼結點位置

int Retrieve(Position P); //獲取P位置結點的資料項

struct Node
{
    int data;
    Position next;
};

#endif // LIST_H_INCLUDED

二、各個函式的實現: list.c

#include "list.h"
#include <malloc.h>
#include <stdlib.h>
#include<stdio.h>

/*初始化:建立一個空的單鏈表*/
List MakeEmpty(List L)
{
    L = (PtrToNode)malloc(sizeof(PtrToNode));  //建立一個頭結點
    if(!L)
    {
        printf("申請空間失敗!\n");
        exit(0);
    }
    L->data = 0; //無效值,不賦值的話就是隨機值
    L->next = NULL;
    return L;
}

/*銷燬連結串列L*/
void DestroyList(List L)
{
    Position P, Temp;
    P = L;
    while(P->next != NULL)
    {
        Temp = P->next;
        free(P);
        P = Temp;
    }
}

/*測試空表*/
_Bool IsEmpty(List L)
{
    return L->next == NULL; //Return ture if L is empty
}

/*測試是否為尾節點*/
_Bool IsLast(Position P, List L)
{
    return P->next == NULL; //Return ture if P is the last position in List L
}

/*返回連結串列長度*/
int Length(List L)
{
    int length = 0;
    Position P;
    P = L->next;
    while(P)
    {
        length++;
        P = P->next;
    }
    return length;
}

/*查詢給定元素在表中的位置*/
Position Find(int X, List L)
{
    Position P;
    P = L->next;
    while(P != NULL && P->data != X)
    {
        P = P->next;
    }
    return P;   //Return Position of X in L; NULL if not found
}

/*刪除表中某個元素X*/
void Delete(int X, List L)
{
    Position P, Temp;
    P = FindPrevious(X, L); //首先找到該元素的先前節點
    if(!IsLast(P, L))
    {
        Temp = P->next;     //此時Temp即是X所在結點
        P->next = Temp->next;
        free(Temp);
    }
}

/*查詢表元X的前驅*/
Position FindPrevious(int X, List L)
{
    Position P;
    P = L;
    while(P->next != NULL && P->next->data != X)
    {
        P = P->next;
    }
    return P;
}

/*查詢表元X的後繼*/
Position FindNext(int X,List L)
{
    Position P;
    P = L;
    while(P != NULL && P->data != X) //當P->next == X 時,說明此事P結點即為X所在元素的結點
    {
        P = P->next;
    }
    P = P->next; //此時P即為X所在結點位置,P重新賦值為P的下一個即後繼結點
    return P;
}

/*向表L中P位置之後插入元素*/
void Insert(int X, List L, Position P)
{
    Position Temp;
    Temp = malloc(sizeof(struct Node));
    if(Temp == NULL)
    {
        printf("申請空間失敗!\n");
        exit(0);
    }
    Temp->data = X;
    Temp->next = P->next;
    P->next = Temp;
}

/*清空連結串列L*/
void DeleteList(List L)
{
    Position P, Temp;
    P = L->next;    //P此時為頭結點
    while(P != NULL)    //從頭結點開始,從前往後,依次釋放每一個結點,清除
    {
        Temp = P->next;
        free(P);
        P = Temp;
    }
    L->next = NULL; //保留頭結點
}

/*獲取位置P後繼結點的位置*/
Position Advance(Position P)
{
    if(P != NULL)
    {
        P = P->next;
    }
    return P;
}

/*獲取位置為P的結點的資料項*/
int Retrieve(Position P)
{
    if(P != NULL)
        return P->data;
    else
        return 0;
}

/*獲取連結串列L第一個結點的位置*/
Position First(List L)
{
    if(L->next != NULL)
        return L->next;
    else
        return L; //為空就返回頭結點位置
}

/*獲取連結串列L頭結點位置*/
Position Header(List L)
{
    return L;
}

三、main函式測試 : Main.c

#include "list.h"
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    List list = NULL, p;
    int i;
    list = MakeEmpty(list);

    if(IsEmpty(list))
        printf("空表!\n");
    else
        printf("非空!\n");

    p = list;
    for(i=0; i<5; i++)
    {
        Insert(i*5, list, p);
        p = Advance(p);
        printf("已插入值為%d的新節點\n", i*5);
    }

    printf("連結串列長度為%d\n", Length(list));

    p = FindNext(5, list);
    printf("資料項為5的結點的後繼結點資料項為%d \n", Retrieve(p));

    Delete(10, list);

    p = FindNext(5, list);
    printf("資料項為5的結點的後繼結點資料項為%d \n", Retrieve(p));

    p = First(list);
    printf("第一個結點資料項為%d\n", Retrieve(p));

    printf("頭結點位置為%p\n", Header(list));

    return 0;
}