• 数据结构 | 单链表实现


    ————————————————————————————————————————————

    单链表

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    概念://单链表基本概念图(基本中的基本)

    定义:

    //初始化

    带头结点

    1 void InitList(Node **head)
    2 {
    3     *head = (Node *)malloc( sizeof(Node));
    4     (*head)->next = NULL;
    5 }

    不带头结点

    1 void InitList(Node **head)
    2 {
    3     *head = NULL;
    4 }

    //插入:

    带头结点

     1 void CreatList(Node **head)
     2 {
     3     Node *r = *head, *s;
     4     int a;
     5     while(scanf("%d", &a))
     6     {
     7         if(a != 0)
     8         {
     9             s = (Node *)malloc(sizeof(Node));
    10             s->value = a;
    11             r->next = s;
    12             r = s;
    13         }
    14         else
    15         {
    16             r->next = NULL;
    17             break;
    18         }
    19     }
    20 }

    不带头结点

     1 void CreatList(Node  **head)
     2 {
     3     Node *p, *t;        /*p工作指针,t临时指针*/
     4     int a, i = 1;
     5     while(scanf("%d", &a))
     6     {
     7         if(a != 0)
     8         {
     9             t = (Node *)malloc(sizeof(Node));
    10             t->value = a;
    11             if(i == 1)
    12             {
    13                 *head = t;
    14             }
    15             else
    16             {
    17                 p->next = t;
    18             }
    19             p = t;
    20         }
    21         else
    22         {
    23             p->next = NULL;
    24             break;
    25         }
    26         i++;
    27     }
    28 }

    //操作

    带头结点

    1 Node *temp;
    2 temp = head->next;
    3 while(temp != NULL)
    4 {
    5     //...
    6     temp = temp->next;
    7 }

    不带头结点

    1 Node *temp;
    2 temp = head;
    3 while(temp != NULL)
    4 {
    5     //...
    6     temp = temp->next;
    7 }

     

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    如何在单链表中插入节点:

    //头插法

    在堆中申请一个新的内存空间用来存放结点,填充信息域,把Head指针的指向擦除并指向新的结点,新的结点指向原来的第一个结点的地址;

    示例:

    输入:0 1 2 3 4 5 6 7 8 9

    输出:

    分析:

    //第一次插入节点

    //循环i执行第二次插入

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    //尾插法

    将数据插在链表的尾部,修改最后节点的指针指向新节点,新节点的指针指向NULL

    示例:

    输入:0 1 2 3 4 5 6 7 8 9

    输出:

    分析:

    //第一次插入节点

    //循环i执行第二次插入

    示例2

    分析://与上一例同理

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    链表传参的三种方式

    //实参传head的地址,形参定义双指针

    在该种方式中关于为什么要在AddNode方法前加 **,分析在本文末尾

    //实参传指针head,形参取地址

    //返回值调用

    利用函数的返回值,返回链表头。

    缺点是不能返回多个函数。

    示例:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    释放链表空间

     1 void ReleaseHead(struct Test **head) //释放链表空间
     2 {
     3     struct Test *temp;
     4     while(*head != NULL)
     5     {
     6         temp = *head;
     7         *head = (*head) ->next;
     8         free(temp);
     9     }
    10 }

    示例:

    输出:

    //输出执行成功,此时head==NULL;

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    关于为什么要使用双指针调用(新增/释放节点时)

    示例:

    输出:

    //使用双指针即正确输出

    //使用注释掉的语句(单指针)则head指针的地址为NULL,此时head没有申请分配到地址

    结论:

    当调用AddNode传递的是&head,接收的形参是**head时,链表正常。

    当传递的是head,接收的形参是*head时,指针head在AddNode中没有被修改,依然处于未分配内存空间的状态。

    分析:

    在这里和正常函数值传递是一样的,假设int a,作为参数传入时没有被修改,修改的是拷贝的临时变量a,所以需要a的指针。在这里同理,也是需要传入head的指针,即指向Data结构体的指针的指针。

    如果主函数调用的是AddNode(head);,函数调用时取head的地址 void AddNode(struct Data *&head),结果也是有效的

    一般来说, 初始化链表之类的需要双指针(例如:翻转链表因为不是在原始链表上翻转,而是返回新的链表头,所以也需要双指针)。像求链表长度、插入节点、打印输出就只要单指针。

    在子函数中传递指针时,子函数的形参要用指针的地址,就是双重指针,也叫二级指针。定义二重指针目的是为了当指针作为函数参数时候,在链表调用时候能改变头指针的地址,从而能调动整个链表,用一级指针的话只能改变一个结点的值。

  • 相关阅读:
    转:验证日期的正则表达式比较全面地验证
    IIS应用地址池监控
    Net预编译 真的好用与否
    关键字检索,找到所有数据
    vue 文件上传自定义实现
    docker 基础(一)
    input表单中嵌入百度地图
    linux系统光盘开机自动挂载-配置本地yum源
    linux学习笔记基础篇(一)
    构建apache web 服务器
  • 原文地址:https://www.cnblogs.com/hughdong/p/6748058.html
Copyright © 2020-2023  润新知