單鏈表的算法


要點

在順序表的算法文章中,我們討論了線性表的順序存儲結構——順序表。

順序表是用一組地址連續的存儲單元來保存數據的,所以它具有隨機存取的特點。即查找快速,但是做插入或刪除動作是,需要移動大量元素,效率較低。

 

鏈表

鏈表是線性表的鏈式存儲結構,它相比於順序表,在插入和刪除元素時,效率要高很多。

鏈表,是用一組任意的存儲單元存儲線性表的數據元素(這組存儲單元可以是連續的,也可以是不連續的)。

每個數據單元有兩部分組成,一個是數據域,存儲數據值;另一個是指針域,指向下一個數據單元。這樣的數據單元叫做結點

當多個結點通過指針指向,關聯起來,就形成了一個鏈,即鏈表。



單鏈表

鏈表可分為單鏈表、雙鏈表、循環鏈表。

本文先介紹單鏈表。

單鏈表就是沿着單方向的鏈表。例如:A->B->C->D->... 只能順序的連下去,即可以從A往下找其他元素,但是反之則不行。

單鏈表結點的結構可表示如下:

typedef int ElemType;

typedef struct LNode {

    ElemType data;

    struct LNode* next;

} LNode, *LinkList;

 

基本算法

插入結點

假設要在單鏈表的a結點和b結點之間插入一個值為x的新結點。

如下圖所示,指針s指向一個值為x的結點,為了插入s

首先讓snext指針指向b,即s->next = p->next;

然后,讓anext指針指向s,即p->next = s;

 

 

刪除結點

假設要刪除單鏈表中的b結點。

首先,找到b結點前面的結點a

如下圖所示,p指針指向a結點。b的下一個結點就是p->next->next

所以,只要讓pnext指針跳過b結點,指向b的下一個結點就OK了,即p->next = p->next->next;

 

參考代碼

以下為本人實現的單鏈表的基本操作。歡迎指正。本人的編譯環境為Visual Studio2010C語言。

基本操作

/***********************************************************************************************************************

[單鏈表操作]

[1] destroyList, 銷毀單鏈表

[2] initList, 初始化一個帶頭結點的空單鏈表,如果傳入一個不為空的單鏈表,將被重置

[3] insertElem, 在單鏈表中第 i 個位置插入元素 elem

[4] removeElem, 在單鏈表中移除第 pos 個元素,並由 elem 返回其值

[5] createList, 根據數組 elems 構建一個單鏈表

[6] isEmptyList, 判斷單鏈表是否為空

[7] getElem, 獲取單鏈表上位置為 pos 的元素

[8] locateElem, 獲取元素 elem 在單鏈表上第一次出現的位置,如果不存在返回 -1

[9] getLength, 獲取單鏈表長度

[10] printList, 打印整個單鏈表

[11] reverseList, 反轉單鏈表

***********************************************************************************************************************/

#include <stdio.h>

#include <stdlib.h>

 

/***********************************************************************************************************************

第一部分,數據結構、宏定義

***********************************************************************************************************************/

#define MAX 5

 

typedef enum {

    OK = 0,

    ERROR = 1

} STATUS_EN;

 

typedef enum {

    TRUE = 0,

    FALSE = -1

} BOOL;

 

typedef int ElemType;

typedef struct LNode {

    ElemType data;

    struct LNode* next;

} LNode, *LinkList;

 

/***********************************************************************************************************************

第二部分,函數實現

***********************************************************************************************************************/

 

/*******************************************************************************

 Funtion      : [1] destroyList

 Description  : 銷毀單鏈表

 Input        : struct LNode **ppHead

 Output       : struct LNode **ppHead

 Return Value : STATUS_EN(OK/ERROR)

 Author       : VictorZhang

 Date         : 2015-03-30

*******************************************************************************/

void destroyList(struct LNode **ppHead) {

    LNode *p = *ppHead;

    LNode *q = p->next;

 

    // 先遍歷刪除所有元素

    while (p && p->next) {

        q = p->next;

        p = q->next;

        free(q);

        q = NULL;

    }

 

    // 最后釋放頭結點

    free(*ppHead);

    *ppHead = NULL;

}

 

/*******************************************************************************

 Funtion      : initList

 Description  : 初始化一個帶頭結點的空單鏈表,如果傳入一個不為空的單鏈表,

                將被重置

 Input        : struct LNode **ppHead

 Output       : struct LNode **ppHead

 Return Value : STATUS_EN(OK/ERROR)

 Author       : VictorZhang

 Date         : 2015-03-30

*******************************************************************************/

STATUS_EN initList(struct LNode **ppHead) {

    if (*ppHead)

        destroyList(ppHead);

 

    LNode *p = (LNode*)malloc(sizeof(LNode));

    p->next = NULL;

    p->data = 0;

    *ppHead = p;

    return OK;

}

 

/*******************************************************************************

 Funtion      : insertElem

 Description  : 在單鏈表中第 i 個位置插入元素 elem

 Input        : struct LNode **ppHead,

                const int pos,

                const ElemType elem

 Output       : struct LNode **ppHead

 Return Value : STATUS_EN(OK/ERROR)

 Author       : VictorZhang

 Date         : 2015-03-30

*******************************************************************************/

STATUS_EN insertElem(struct LNode **ppHead, const int pos, const ElemType elem) {

    LNode *p = *ppHead;

    LNode *s = NULL;

 

    // 尋找鏈表當前最后一個結點

    int i = 0;

    while (p && i < pos) {

        p = p->next;

        i++;

    }

 

    // 未找到末尾結點

    if (!p || i > pos)

        return ERROR;

 

    // 生成新結點

    s = (LNode*) malloc (sizeof(LNode));

    if (!s)

        return ERROR;

 

    // 插入單鏈表中

    s->data = elem;

    s->next = p->next;

    p->next = s;

 

    return OK;

}

 

/*******************************************************************************

 Funtion      : removeElem

 Description  : 在單鏈表中移除第 pos 個元素,並由 elem 返回其值

 Input        : struct LNode **ppHead,

                const int pos,

                ElemType *pElem

 Output       : struct LNode **ppHead,

                ElemType *pElem

 Return Value : STATUS_EN(OK/ERROR)

 Author       : VictorZhang

 Date         : 2015-03-30

*******************************************************************************/

STATUS_EN removeElem(struct LNode **ppHead, const int pos, ElemType *pElem) {

    LNode *p = *ppHead;

    LNode *q = NULL;

    int i = 0;

    while (p && p->next && i < pos) {

        p = p->next;

        i++;

    }

 

    // 刪除位置不合理

    if (!(p->next) || i > pos)

        return ERROR;

 

    // 刪除並釋放結點

    q = p->next;

    p->next = q->next;

    *pElem = q->data;

    free(q);

    return OK;

}

 

/*******************************************************************************

 Funtion      : createList

 Description  : 根據數組 elems 構建一個單鏈表

 Input        : struct LNode **ppHead,

                const ElemType elems[],

                const int n

 Output       : struct LNode **ppHead

 Return Value : STATUS_EN(OK/ERROR)

 Author       : VictorZhang

 Date         : 2015-03-30

*******************************************************************************/

STATUS_EN createList(struct LNode **ppHead, const ElemType elems[], const int n) {

    int i = 0;

    STATUS_EN statu = OK;

 

    // 按序將數組元素插入到單鏈表尾部

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

        statu = insertElem(ppHead, i, elems[i]);

        if (OK != statu)

            return statu;

    }

 

    return OK;

}

 

/*******************************************************************************

 Funtion      : isEmptyList

 Description  : 判斷單鏈表是否為空

 Input        : struct LNode *pHead

 Output       : N/A

 Return Value : BOOL

 Author       : VictorZhang

 Date         : 2015-03-30

*******************************************************************************/

BOOL isEmptyList(struct LNode *pHead) {

    if (NULL == pHead || NULL == pHead->next)

        return TRUE;

    else

        return FALSE;

}

 

/*******************************************************************************

 Funtion      : getElem

 Description  : 獲取單鏈表上位置為 pos 的元素

 Input        : struct LNode *pHead,

                const int pos,

                ElemType *pElem

 Output       : ElemType *pElem

 Return Value : STATUS_EN(OK/ERROR)

 Author       : VictorZhang

 Date         : 2015-03-30

*******************************************************************************/

STATUS_EN getElem(struct LNode *pHead, const int pos, ElemType *pElem) {

    int i = 0;

    LNode *p = pHead->next;

    while (p && i <= pos) {

        if (i == pos) {

            *pElem = p->data;

            return OK;

        } else {

            p = p->next;

            i++;

        }

    }

    return ERROR;

}

 

/*******************************************************************************

 Funtion      : locateElem

 Description  : 獲取元素 elem 在單鏈表上第一次出現的位置,如果不存在返回 -1

 Input        : struct LNode *pHead,

                const ElemType elem

 Output       : N/A

 Return Value : int

 Author       : VictorZhang

 Date         : 2015-03-30

*******************************************************************************/

int locateElem(struct LNode *pHead, const ElemType elem) {

    int pos = 0;

    LNode *p = pHead->next;

    while (p) {

        if (p->data == elem) {

            return pos;

        } else {

            pos++;

            p = p->next;

        }

    }

    return -1;

}

 

/*******************************************************************************

 Funtion      : getLength

 Description  : 獲取單鏈表長度

 Input        : struct LNode *pHead

 Output       : N/A

 Return Value : int

 Author       : VictorZhang

 Date         : 2015-04-02

*******************************************************************************/

int getLength(struct LNode *pHead) {

    if (NULL == pHead || NULL == pHead->next) {

        return 0;

    }

 

    int i = 0;

    LNode *p = pHead->next;

    while (p) {

        p = p->next;

        i++;

    }

    return i;

}

 

/*******************************************************************************

 Funtion      : printList

 Description  : 打印整個單鏈表

 Input        : struct LNode *pHead

 Output       : N/A

 Return Value : N/A

 Author       : VictorZhang

 Date         : 2015-04-02

*******************************************************************************/

void printList(struct LNode *pHead) {

    if (NULL == pHead || NULL == pHead->next) {

        printf("LinkList is empty\n");

        return;

    }

    LNode *p = pHead->next;

    printf("LinkList:");

    while (p) {

        printf(" %d", p->data);

        p = p->next;

    }

    printf("\n");

}

 

/*******************************************************************************

 Funtion      : reverseList

 Description  : 反轉單鏈表

 Input        : struct LNode **ppHead

 Output       : struct LNode **ppHead

 Return Value : N/A

 Author       : VictorZhang

 Date         : 2015-04-02

*******************************************************************************/

void reverseList(struct LNode **ppHead) {

    if (NULL == *ppHead || NULL == (*ppHead)->next) {

        return;

    }

 

    LNode *prev = NULL;

    LNode *cur = (*ppHead)->next;

    LNode *next = NULL;

 

    while (cur) {

        next = cur->next;

        cur->next = prev;

        prev = cur;

        cur = next;

    }

    (*ppHead)->next = prev;

}

測試例部分 

 

 

/***********************************************************************************************************************

第三部分,測試例

***********************************************************************************************************************/

void testCase0() {

printf("================== testCase0 ==================\n");

int len = 0;

BOOL bFlag = FALSE;

ElemType A[MAX] = {4,5,2,1,3};

struct LNode *pHead = NULL;

// 初始化鏈表

initList(&pHead);

printf("Init List\n");

// 獲取鏈表長度

len = getLength(pHead);

printf("Length of List is %d\n", len);

// 根據一個數組來創建單鏈表

createList(&pHead, A, MAX);

printf("After create List\n");

printList(pHead);

// 獲取鏈表長度

len = getLength(pHead);

printf("Length of List is %d\n", len);

// 判斷單鏈表是否為空

bFlag = isEmptyList(pHead);

if (bFlag) {

printf("It is a empty List.\n");

} else {

printf("It is not a empty List.\n");

}

// 銷毀鏈表

printf("Destroy List\n");

destroyList(&pHead);

// 獲取鏈表長度

len = getLength(pHead);

printf("Length of List is %d\n", len);

// 判斷單鏈表是否為空

bFlag = isEmptyList(pHead);

if (bFlag) {

printf("It is a empty List.\n");

} else {

printf("It is not a empty List.\n");

}

}

void testCase1() {

printf("================== testCase1 ==================\n");

STATUS_EN statu;

ElemType A[MAX] = {4,5,2,1,3};

struct LNode *pHead = NULL;

// 初始化鏈表

initList(&pHead);

printf("Init List\n");

createList(&pHead, A, MAX);

printf("After create List\n");

printList(pHead);

// 在尾部位置嘗試插入元素

statu = insertElem(&pHead, 5, 9);

printf("Insert element\n");

if (OK != statu) {

printf("Insert failed!\n");

} else {

printList(pHead);

}

// 在頭部位置嘗試插入元素

statu = insertElem(&pHead, 0, 2);

if (OK != statu) {

printf("Insert failed!\n");

} else {

printList(pHead);

}

// 中間位置嘗試插入元素

statu = insertElem(&pHead, 3, 7);

if (OK != statu) {

printf("Insert failed!\n");

} else {

printList(pHead);

}

// 嘗試在不合理的位置上插入元素

statu = insertElem(&pHead, 99, 15);

if (OK != statu) {

printf("Insert failed!\n");

} else {

printList(pHead);

}

}

void testCase2() {

printf("================== testCase2 ==================\n");

STATUS_EN statu;

ElemType elem;

ElemType A[MAX] = {4,5,2,1,3};

struct LNode *pHead = NULL;

// 初始化鏈表

initList(&pHead);

printf("Init List\n");

createList(&pHead, A, MAX);

printf("After create List\n");

printList(pHead);

// 嘗試移除尾部位置的元素

statu = removeElem(&pHead, 4, &elem);

printf("Remove element pos(%d)\n", 4);

if (OK != statu) {

printf("Remove failed!\n");

} else {

printList(pHead);

}

// 嘗試移除頭部位置的元素

statu = removeElem(&pHead, 0, &elem);

printf("Remove element pos(%d)\n", 0);

if (OK != statu) {

printf("Remove failed!\n");

} else {

printList(pHead);

}

// 嘗試移除中間位置的元素

statu = removeElem(&pHead, 1, &elem);

printf("Remove element pos(%d)\n", 1);

if (OK != statu) {

printf("Remove failed!\n");

} else {

printList(pHead);

}

// 嘗試移除不合理位置的元素

statu = removeElem(&pHead, 11, &elem);

printf("Remove element pos(%d)\n", 11);

if (OK != statu) {

printf("Remove failed!\n");

} else {

printList(pHead);

}

}

void testCase3() {

printf("================== testCase3 ==================\n");

int pos = 4;

STATUS_EN statu;

ElemType elem;

ElemType A[MAX] = {4,5,2,1,3};

struct LNode *pHead = NULL;

// 初始化鏈表

initList(&pHead);

printf("Init List\n");

createList(&pHead, A, MAX);

printf("After create List\n");

printList(pHead);

// 獲取指定位置上的元素

statu = getElem(pHead, pos, &elem);

if (OK != statu) {

printf("Get element failed!\n");

} else {

printf("The elem in pos(%d) is %d\n", pos, elem);

}

// 查找元素在單鏈表中第一次出現的位置

elem = 4;

pos = locateElem(pHead, elem);

printf("%d is in pos(%d) of List\n", elem, pos);

elem = 9;

pos = locateElem(pHead, elem);

printf("%d is in pos(%d) of List\n", elem, pos);

}

void testCase4() {

printf("================== testCase4 ==================\n");

ElemType A[MAX] = {4,5,2,1,3};

struct LNode *pHead = NULL;

// 初始化鏈表

initList(&pHead);

printf("Init List\n");

createList(&pHead, A, MAX);

printf("After create List\n");

printList(pHead);

// 反轉單鏈表

reverseList(&pHead);

printf("Reverse List\n");

printList(pHead);

}

int main() {

testCase0();

testCase1();

testCase2();

testCase3();

testCase4();

return 0;

}

 

 

參考資料

《數據結構》(C語言版) ,嚴蔚敏、吳偉民

《數據結構習題與解析》(B級第3版),李春葆、喻丹丹

 

相關閱讀

歡迎閱讀 程序員的內功——數據結構和算法 系列


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM