链表!

  对于数据的存储,在我们初学者来说通常来说第一反应基本上是开数组,谈到多种数据不过就是多开几组数组,或者说用结构体,但是这仅仅只是对于已知数据多少的一种判断,但如果是对于未知数量的不同数据组的存储,那可能会束手无策。但问题总的有解决的途径,所以这种时候,链表就是一个不错的选择!

  链表,基于结构体,并运用指针的存储地址的特性对未知数量的数据进行存储。其特点:

  • n个节点离散分配;
  • 每一个节点之间通过指针相连;
  • 每一个节点有一个前驱节点和一个后继节点;
  • 首节点没有前驱节点,尾节点没有后继节点。

  学习链表需要掌握的一些必备知识:

首节点:存放第一个有效数据的节点

头节点:在单链表的第一个结点之前附设一个结点,它没有直接前驱,称之为头结点,头结点的数据域可以不存储任何信息,指针域指向第一个节点(首节点)的地址。头结点的作用是使所有链表(包括空表)的头指针非空

头指针:指向头节点的指针

尾节点:存放最后一个有效数据的节点

尾指针:指向尾节点的指针

  链表通过我自己的理解,我认为就是通过指针和malloc(开数据空间)函数反复调用结构体,对多组数据的存储。

#include <stdio.h>
#include <stdlib.h>
struct link *AppendNode(struct link *head){    //声明创建节点函数 
    struct link *p = NULL,*pr = head;      //创建p指针,初始化为NULL;创建pr指针,通过pr指针来给指针域赋值 
    int data ;
    p = (struct link *)malloc(sizeof(struct link)) ; //为指针p申请内存空间,必须操作,因为p是新创建的节点 
    if(p == NULL){            //如果申请内存失败,则退出程序 
        printf("NO enough momery to allocate!\n");
        exit(0);
    }
    if(head == NULL){        //如果头指针为NULL,说明现在链表是空表 
        head = p;                                //使head指针指向p的地址(p已经通过malloc申请了内存,所以有地址) 
    }else{                                        //此时链表已经有头节点 ,再一次执行了AppendNode函数 
                                                //注:假如这是第二次添加节点
                                      //因为第一次添加头节点时,pr = head,和头指针一样指向头节点的地址 
        while(pr->next!= NULL){        //当pr指向的地址,即此时的p的指针域不为NULL(即p不是尾节点) 
            pr = pr->next;    //使pr指向头节点的指针域
        }
        pr->next = p;    //使pr的指针域指向新键节点的地址,此时的next指针域是头节点的指针域 
    }
    printf("Input node data:");                   
    scanf("%d",&data);
    p->data = data;             //给p的数据域赋值 
    p->next = NULL;            //新添加的节点位于表尾,所以它的指针域为NULL 
    return head;            //返回head的地址 
}
void DisplayNode(struct link *head){             //输出函数,打印链表 
    struct link *p = head;            // 定义p指针使其指向头节点 
    int j = 1;                                    //定义j记录这是第几个数值 
    while(p != NULL){        //因为p = p->next,所以直到尾节点打印结束 
        printf("%5d%10d\n",j,p->data);            
        p = p->next;        //因为节点已经创建成功,所以p的指向由头节点指向下一个节点(每一个节点的指针域都指向了下一个节点) 
        j++;    
    }
}
void DeleteMemory(struct link *head){            //释放资源函数 
    struct link *p = head,*pr = NULL;            //定义p指针指向头节点 
    while(p != NULL){                //当p的指针域不为NULL 
        pr = p;                                    //将每一个节点的地址赋值给pr指针 
        p = p->next;                    //使p指向下一个节点 
        free(pr);                                //释放此时pr指向节点的内存 
    }
}
//定义结构体 
struct link{
    int data;                 //定义数据域 
    struct link *next;             //定义指针域 
}; 
int main(){
    int i =0;                     //定义i,记录创建的节点数 
    char c;                            
    struct link *head = NULL;        //创建头指针,初始化为NULL 
    printf("DO you wang to append a new node(Y or N)?");
    scanf(" %c",&c);                
    while(c == 'Y' || c == 'y'){    //如果确定继续添加结点 
        head = AppendNode(head);    //通过函数获得链表的地址,AppendNode函数返回的是链表的头指针
                                    //可以根据头指针指向的地址来获取链表中保存的数据 
        DisplayNode(head);            //根据头指针打印链表 
        printf("DO you want to append a new node(Y or N)?");
        scanf(" %c",&c);
        i++; 
    }
    printf("%d new nodes hava been appended!\n",i);
    DeleteMemory(head);            //释放占用的内存 
}

  大佬源码:https://blog.csdn.net/qq_41481924/article/details/85340787

  初学链表,通过注解和理解完整的看懂了一篇,感觉还可以。

  注:学习过程中也发现,链表中对头结点和尾节点的声名至关重要,未作声名则会不知链表地址,不能释放链表所占用的空间,导致程序越用越卡,特此注释,提醒自己!!

posted on 2021-01-20 20:26  云の海  阅读(108)  评论(0编辑  收藏  举报

导航