zoukankan      html  css  js  c++  java
  • 链表(C语言实现)

    #include <stdio.h>
    #include <stdlib.h>
    
    /*自由定义类型,类似于c++模板*/
    /*链表的头是head,head无意义:head->1st node->2nd node->NULL*/
    
    
    typedef int type;
    
    struct Node{
        type data;
        Node* next;
    };
    /*创建链表,一个空的head节点,返回head*/
    Node* Create()
    {
        Node* head = (Node*)malloc(sizeof(Node));
        head->next = NULL;
        return head;
    }
    /*判断链表是否为空。空表的head->next为NULL*/
    int IsEmpty(Node* head)
    {
        return head ->next== NULL;//1 is empty
    }
    /*清空链表,但是head还在还占内存*/
    void MakeEmpty(Node* head)
    {
        Node* p = head;
        while (p != NULL)
        {
            Node* del = p;//p储存下
            p = p->next;//储存p后面的节点
            free(del);//删除当前p节点
        }
        head->next = NULL;//重要,因为IsEmpty的依据是->next==NULL
    }
    /*指定位置插入元素,n=0在head后第一个元素前插入,=1在第1个元素后面插入*/
    void Insert(type val, Node* head, int n)
    {
        /*新建节点*/
        Node* new_node = (Node*)malloc(sizeof(Node));
        if (new_node == NULL)
        {
            printf("new_node malloc failed!
    ");
            return;
        }
        new_node->data = val;
        new_node->next = NULL;
        /*插入*/
        Node* p = head;
        while (n--)
        {
            p = p->next;
            if (p->next == NULL)
            {
                printf("Already End!
    ");//此时p已经是最后一个节点
                break;
            }
        }
        new_node->next = p->next;//这里很重要!
        p->next = new_node;
    }
    /*删除指定位置节点*/
    void Delete(Node* head, int n)
    {
        /*如果空就返回*/
        if (IsEmpty(head))
        {
            printf("Empty now!");
            return;
        }
        else
        {
            Node* p = head;
            while (n--)
            {
                p = p->next;
                if (p->next == NULL)
                {
                    printf("Already End!
    ");
                    break;
                }
            }
            Node* tmp = p->next;//链表不能对上访问,就是说遍历到p你想知道p的上一个不行的,得重新遍历,除非是双向链表。
            p->next = tmp->next;//目的是删除p->next。把其后一个接到前一个的后面。删除中间那个。
            free(tmp);
        }
    }
    
    void Print(Node* head)
    {
        if (IsEmpty(head))
        {
            printf("Already Empty!
    ");
        }
        else
        {
            Node* p = head->next;
            while (p != NULL)
            {
                printf("%d
    ", p->data);
                p = p->next;
            }
        }
        printf("
    ");
    }
    
    int main()
    {
        Node* head=Create();
        
        Insert(1, head, 0);
        Insert(2, head, 1);
        Insert(3, head, 2);
        Print(head);
    
        Insert(4, head, 2);
        Print(head);
    
        Delete(head, 1);
        Print(head);
    
        MakeEmpty(head);
        Print(head);
    
        //free(head);
    
        return 0;
    }

    这段代码,注释很完整了,相信我多年之后看还能快速明白主旨。不过有个问题,我习惯把断电设在return 0;或者system(“pause”)处,先看看结果:

    但是一旦继续程序就挂了:

    以前也遇到过,不过经验不足没有解决。问题肯定是处在MakeEmpty上。

    void MakeEmpty(Node* head)
    {
        Node* p = head->next;
        while (p != NULL)
        {
            Node* del = p;//p储存下
            p = p->next;//储存p后面的节点
            free(del);//删除当前p节点
        }
        head->next = NULL;//重要,因为IsEmpty的依据是->next==NULL
    }

    改成如上形式。

    开始时如果把head赋给p,开始就把head内存给删除了,最终是链表的每个节点都delete了。如果想删除head,在return前面加free(head);

    但是为什么我空着head,就不会挂掉,而通过循环del就会挂掉呢?

    我想是回收机制的问题。在main return时,主线程终止了,堆内会把分配的变量都回收销毁。但是可能是这个head的指针跟实际的内存块链接已经断了,导致它销毁发生错误,才会出现这样的内存错误。

    可以试下:

    void MakeEmpty(Node* head)
    {
        Node* p = head;
        while (p != NULL)
        {
            Node* del = p;//p储存下
            p = p->next;//储存p后面的节点
            free(del);//删除当前p节点
        }
        //head->next = NULL;//重要,因为IsEmpty的依据是->next==NULL
    }

    这样,只要不print是没问题的。就是说,如果没有head->next,就可以。而加上这句,就是你把内存全释放了,head也没有,还在head的next挂个NULL。return时,它认为你的head还有意义,准备销毁,不过它的内存已经释放,所以重复释放会出错。

    我靠,终于一边写,一边找到问题的根本。

  • 相关阅读:
    关于overflow:hidden的作用(溢出隐藏、清除浮动、解决外边距塌陷等等)
    float详解
    五 使用并美化网页文本
    代码校验工具 SublimeLinter 的安装与使用
    Sublime Text3 快捷键
    word选择+快捷键
    Word1-提取图片文字
    javascript window对象属性和方法
    word教程字体和段落设置
    Word2 word输入公式+文字转表格
  • 原文地址:https://www.cnblogs.com/wyc199288/p/5184416.html
Copyright © 2011-2022 走看看