C 实现链表

作者: Void_Caller | 来源:发表于2019-07-27 20:31 被阅读2次

前言

第一次学数据结构,代码写的可能不是很好,大神勿喷,指出来就行。

链表

顾名思义,链表就是每个数据之间有某种连接关系的一张表。

注意:在学习链表之前首先要搞清地址(指针)的概念。

原理

我们知道,数组是一串连续的内存空间,里面存放着我们的数据。
但是链表却不同,他是一堆数据被存放到不连续的内存空间,但每组数据都会有一个变量指向下一组数据的地址(指针),以此来连接起来。

用图来表示就是这样

所以我们很容易就想到用C语言的结构体来储存数据和指向下一个节点的地址,最后个节点由于后面没有别的节点了,所以就指向空(NULL)了。

struct Node // 链表结构
{
    int data;
    struct Node *pNext;
};

操作

无非也就是增删查改之类的,具体实现里的代码注释已经写的很详细了,直接看就可以了。

具体实现(第一次写这种,可能写的不是很好,大神勿喷)

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

struct Node // 链表结构
{
    int data;
    struct Node *pNext;
};

struct LinkedList // 记录链表的初始节点和末节点
{
    struct Node *pLast; // 末节点
    struct Node *root; // 初始节点
};

// Operations

// 添加节点
struct Node *addNode(struct LinkedList *list, int data)
{
    struct Node *m = (struct Node*) malloc(sizeof(struct Node)); // 创建节点
    m -> data = data; // 塞入数据
    m -> pNext = NULL; // 把该节点的下一个节点的指针指向空
    if (list -> pLast != NULL) (list -> pLast) -> pNext = m; // 如果有上一个元素,那就把上一元素的下一节点指针指向本节点
    else list -> root = m; // 没有的话就充当根节点
    list -> pLast = m; // 不管怎么说,把链表的当前节点设为m
    return m;
}

struct Node *addNode(struct LinkedList *list, int data,int index)
{
    struct Node *last = list -> pLast; // 先记录原来的最后一位
    list -> pLast = list -> root; // 把记录最后一位指针的变量赋为第一个,以便遍历
    struct Node *m = 0x0;
    if (index != 0) {
        for (int i = 1;i < index;i ++)
        {
            if ((list -> pLast) -> pNext == NULL) break; // 到尾巴了就跳掉
            list -> pLast = (list -> pLast) -> pNext; // 把pLast一位一位往后移
        }
        // 准备添加元素
        struct Node *next = (list -> pLast) -> pNext; // 先记录原来这个元素的后一个元素地址
        m = addNode(list, data); // 添加元素(会自动和前一个元素链接起来的),但同时和原来的后面一个元素的链也断了
        (list -> pLast) -> pNext = next; // 把后面的那个链接回来
    } else {
        list -> pLast = NULL; // 让addNode方法误以为前面没有元素了
        struct Node *newRoot = addNode(list, data); // 添加元素,此时是全新的一个根节点
        newRoot -> pNext = list -> root; // 和原来的根节点连回来
        list -> root = newRoot; // 重新赋值根节点
        m = list -> root; // 返回新添加的节点
    }
    if (last -> pNext != NULL) list -> pLast = last -> pNext; // 如果在末尾有添加了一个节点,那就指向x那个新的节点
    else list -> pLast = last; // 恢复原来的节点
    return m;
}

void removeNode(struct LinkedList *list, int index)
{
    struct Node *last = 0x0; // 上一个节点,0x0,也就是NULL,是空节点
    struct Node *now = list -> root; // 当前轮到的节点,一开始为root节点
    for (int i = 1;i <= index;i ++)
    {
        if (now -> pNext != NULL) { // 如果还有下一个节点的话
            last = now; // 往下轮,上一个节点就是now节点
            now = now -> pNext; // 往下轮
        }
        else break; // 到尾巴了就退出
    }
    if (last == NULL) // 如果要删除root元素
    {
        if ((list -> root) -> pNext != NULL) // 如果root元素后面还有
        {
            list -> root = (list -> root) -> pNext; // 链上
        } else {
            list -> root = NULL; // 没有的话就把root元素也弄空
        }
    } else {
        last -> pNext = NULL; // 断开上一个的链接
        if (now -> pNext != NULL) // 如果后面还有元素的话
        {
            last -> pNext = now -> pNext; // 链上
        }
    }
    free(now); // 释放删除掉的元素的内存
}

int main(int argc, const char * argv[]) {
    // insert code here...
    struct LinkedList list = {NULL, NULL};
    addNode(&list, 2); // 增
    addNode(&list, 1);
    addNode(&list, 5);
    addNode(&list, 4, 1); // 指定位置增
    addNode(&list, 3);
    
    removeNode(&list, 0); // 删
    
    printf("orgin: 4 1 5 3\n");
    
    // 查
    printf("查询:\n");
    int in = 0;
    scanf("%d",&in);
    struct Node *pSearch = list.root;
    int hasFound = 1;
    for (int i = 0;i < in;i ++)
    {
        if (pSearch -> pNext != NULL)
        {
            pSearch = pSearch -> pNext;
        } else hasFound = 0;
    }
    if (hasFound) printf("%d\n",pSearch -> data);
    else printf("NF!\n");
    
    // 改
    printf("修改:\nindex:\n");
    scanf("%d",&in);
    int to;
    printf("to:\n");
    scanf("%d",&to);
    pSearch = list.root;
    hasFound = 1;
    for (int i = 0;i < in;i ++)
    {
        if (pSearch -> pNext != NULL)
        {
            pSearch = pSearch -> pNext;
        } else hasFound = 0;
    }
    if (hasFound) pSearch -> data = to;
    
    // 遍历
    printf("开始遍历:\n");
    struct Node *pNow = list.root;
    struct Node *pNext;
    int isf = 1;
    while (pNow != NULL)
    {
        if (isf) isf = 0;
        else printf(" ");
        printf("%d",pNow -> data);
        if (pNow -> pNext != NULL) {
            pNext = pNow -> pNext;
            free(pNow);
            pNow = pNext;
        } else {
            free(pNow);
            break;
        }
        
    }
    printf("\n");
    return 0;
}

相关文章

  • 链表

    单链表 C实现 Java实现 双链表 C实现 Java实现

  • Java实现简单的链表-面向初学者

    很久之前用C语言实现过链表,现在已经太久没用C语言。就先用JAVA实现一个简单链表好了,还是使用最原始的C语言实现...

  • c++ 实现队列

    相关资料: 用C++实现一个队列 数据结构代码实现之队列的链表实现(C/C++)

  • C++实现双向循环链表

    本次博文是关于利用C++模板的方式实现的双向循环链表以及双向循环链表的基本操作,在之前的博文C++语言实现双向链表...

  • LeetCode 141 环形链表 Linked List Cy

    有关链表的LeetCode做题笔记合集,Python实现 链表定义 141. 环形链表 Linked List C...

  • Redis 源码--链表。

    因为C语言是一个比较底层的语言,库内没有实现链表,于是Redis自己实现了链表。Redis的链表是一个双向链表。 ...

  • C++语言实现双向链表

    这篇文章是关于利用C++模板的方式实现的双向链表以及双向链表的基本操作,在之前的博文C语言实现双向链表中,已经给大...

  • C实现链表

    demo地址

  • C 实现链表

    前言 第一次学数据结构,代码写的可能不是很好,大神勿喷,指出来就行。 链表 顾名思义,链表就是每个数据之间有某种连...

  • C# 链表

    链表介绍 Unity 用C#写的链表类 简述链表和数组的区别 Unity--链表实现贪吃蛇

网友评论

    本文标题:C 实现链表

    本文链接:https://www.haomeiwen.com/subject/lofyrctx.html