zoukankan      html  css  js  c++  java
  • 单链表的基本操作

    首先指出我在学习过程中纠结的几个点:

    1.初始化单链表的时候为什么要用二级指针?

    反正那会也没学长指导,状态还差了点,但搜了很久后还是想明白了。

    说白了你可以选择在定义头节点L的时候就初始化, 也可以定义了后用二级指针或者一级指针的引用传进函数InitList来初始化

    2.为什么会需要头结点?

    若头结点的指针域为空(NULL),表明链表是空表。头结点对于链表来说,不是必须的,在处理某些问题时,给链表添加头结点会使问题变得简单。

    >>ADT:

    typedef struct Node
    {
        DataType data;
        struct Node *next;
    }Node, *LinkList;

    >>初始化:

    void InitList(LinkList *L)
    {
        *L = (Node*)malloc(sizeof(Node));
        (*L)->next = NULL;
    }

    >>判断链表是否为空:

    int Empty(Node *L)
    {
        if (L->next==NULL) return 1;
        else return 0;
    }

    >>建立链表:
    (1)头插法(逆序存储)

    Node *CreatList1(DataType a[], int n)
    {
        Node *s = NULL;
        Node *L = (Node*)malloc(sizeof(Node));
        L->next = NULL;
        for (int i = 0; i < n; i++) {
            s = (Node*)malloc(sizeof(Node));
            s->data = a[i];
            s->next = L->next;
            L->next = s;
        }
        return L;
    }

    (2)尾插法

    Node *CreatList2(DataType a[], int n)
    {
        Node *s = NULL, *rear = NULL;
        Node *L = (Node*)malloc(sizeof(Node));
        rear = L;
        for (int i = 0; i < n; i++) {
            s = (Node*)malloc(sizeof(Node));
            s->data = a[i];
            rear->next = s;
            rear = s;
        }
        rear->next = NULL;
        return L;
    } 

    >>遍历链表:

    void PrintList(Node *L)
    {
        Node *p = L->next;
        while (p!=NULL) {
            printf("%d", p->data);
            p = p->next;
        }
    }

    >>链表长度:

    int Length(Node *L)
    {
        Node *p = L->next;
        int cnt = 0;
        while (p!=NULL) {
            cnt++;
            p = p->next;
        }
        return cnt;
    }

    >>查找节点

    (1)按值查找

    Node *Get(Node *L, DataType x)
    {
        Node *p = L->next;
        while (p&&p->data!=x) p = p->next;
        return p;
    }

    (2)按位查找

    Node *Locate(Node *L, int n)
    {
        if (n<=0) return NULL;
        Node *p = L;
        for (int i = 0; i < n; i++)
            p = p->next;
        return p;
    }

    >>插入节点

    int Insert(Node *L, int n, DataType x)
    {
        if (n<=0) return 0;
        Node *s = NULL, *p = L;
        int cnt = 0;
        while (p!=NULL&&cnt<n-1) {
            cnt++;
            p = p->next;
        }
        if (p==NULL) return 0;
        else {
            s = (Node*)malloc(sizeof(Node));
            s->data = x;
            s->next = p->next;
            p->next = s;
            return 1;
        }
    }

    >>删除节点

    int Delete(Node *L, int n)
    {
        if (n<=0) return 0;
        Node *p = L;
        int cnt = 0;
        while (p!=NULL&&cnt<n-1) {
            cnt++;
            p = p->next;
        }
        if (p==NULL||p->next==NULL) return 0;
        else {
            Node *q = p->next;//单独设置一个指针指向被删除结点进行存储,以防丢失
            p->next = q->next;
            free(q);//手动释放该结点,防止内存泄漏
            return 1;
        }
    }

    这些只是相对来说还不错的实现方法,当然也有别的写法,可以多看下别人的博客

    总结:

    线性表的链式存储相比于顺序存储,有两大优势:

    1.链式存储的数据元素在物理结构没有限制,当内存空间中没有足够大的连续的内存空间供顺序表使用时,可能使用链表能解决问题。(链表每次申请的都是单个数据元素的存储空间,可以利用上一些内存碎片)

    2.链表中结点之间采用指针进行链接,当对链表中的数据元素实行插入或者删除操作时,只需要改变指针的指向,无需像顺序表那样移动插入或删除位置的后续元素,简单快捷。


    链表和顺序表相比,不足之处在于,当做遍历操作时,由于链表中结点的物理位置不相邻,使得计算机查找起来相比较顺序表,速度要慢。


    感谢以下博客 

    https://www.cnblogs.com/ciyeer/p/9025871.html

    https://blog.csdn.net/u012234115/article/details/39717215

    https://www.cnblogs.com/longl/p/6414433.html

  • 相关阅读:
    Did not find handler method for springMVC资源文件扫描不到---关于spring的那些坑
    mysql中OPTIMIZE TABLE的作用
    Linux环境下apache性能测试工具ab使用详解
    sqlite数据库 adb 从配置到查询表中数据全过程-----献给初学的自己
    c3p0参数解释
    linux下如何启动/停止/重启mysql:
    [MySQL] 变量(参数)的查看和设置
    mysql运行参数详解
    单例模式 理解,简单通透
    this的一些场景
  • 原文地址:https://www.cnblogs.com/wizarderror/p/10632258.html
Copyright © 2011-2022 走看看