单链表的算法

简介:

要点

在顺序表的算法文章中,我们讨论了线性表的顺序存储结构——顺序表。

顺序表是用一组地址连续的存储单元来保存数据的,所以它具有随机存取的特点。即查找快速,但是做插入或删除动作是,需要移动大量元素,效率较低。

 

链表

链表是线性表的链式存储结构,它相比于顺序表,在插入和删除元素时,效率要高很多。

链表,是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。

每个数据单元有两部分组成,一个是数据域,存储数据值;另一个是指针域,指向下一个数据单元。这样的数据单元叫做结点

当多个结点通过指针指向,关联起来,就形成了一个链,即链表。



单链表

链表可分为单链表、双链表、循环链表。

本文先介绍单链表。

单链表就是沿着单方向的链表。例如: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, 59);

printf("Insert element\n");

if (OK != statu) {

printf("Insert failed!\n");

else {

printList(pHead);

}

// 在头部位置尝试插入元素

statu = insertElem(&pHead, 02);

if (OK != statu) {

printf("Insert failed!\n");

else {

printList(pHead);

}

// 中间位置尝试插入元素

statu = insertElem(&pHead, 37);

if (OK != statu) {

printf("Insert failed!\n");

else {

printList(pHead);

}

// 尝试在不合理的位置上插入元素

statu = insertElem(&pHead, 9915);

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;

}

 

 本文转自静默虚空博客园博客,原文链接:http://www.cnblogs.com/jingmoxukong/p/4381343.html,如需转载请自行联系原作者

相关文章
|
存储 算法 Java
算法系列之递归反转单链表
递归反转链表的基本思路是将当前节点的next指针指向前一个节点,然后递归地对下一个节点进行同样的操作。递归的核心思想是将问题分解为更小的子问题,直到达到基本情况(通常是链表末尾)。
580 5
算法系列之递归反转单链表
|
存储 算法 Go
算法学习:数组 vs 链表
算法学习:数组 vs 链表
587 0
|
存储 缓存 算法
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
404 0
|
存储 监控 算法
员工电脑监控系统中的 C# 链表算法剖析-如何监控员工的电脑
当代企业管理体系中,员工电脑监控已成为一个具有重要研究价值与实践意义的关键议题。随着数字化办公模式的广泛普及,企业亟需确保员工对公司资源的合理利用,维护网络安全环境,并提升整体工作效率。有效的电脑监控手段对于企业实现这些目标具有不可忽视的作用,而这一过程离不开精妙的数据结构与算法作为技术支撑。本文旨在深入探究链表(Linked List)这一经典数据结构在员工电脑监控场景中的具体应用,并通过 C# 编程语言给出详尽的代码实现与解析。
322 5
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
365 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
323 0
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
429 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
【链表】算法题(二) ----- 力扣/牛客
【链表】算法题(二) ----- 力扣/牛客
【链表】算法题(一) ----- 力扣 / 牛客
【链表】算法题(一) ----- 力扣 / 牛客
|
算法 Java
[Java·算法·中等] LeetCode21. 合并两个有序链表
[Java·算法·中等] LeetCode21. 合并两个有序链表
384 2