创建一个没有头结点的单链表(附完整代码)

        creat一个链表

        我们之前简单的看了一些链表的结构,那么现在来创建一个链表,我们已经知道了链表它不需要一块连续的空间就能够实现逻辑上的连续,具体的做法就是对于你要储存的数据,我们不仅仅把它简单的看成是数据,而是把它用结构体来创建一个新的类型,一个带指针域和数据域的类型,而除了最后那个节点的指针域指向NULL外,其他的指针域储存的都是逻辑上下一个结点的地址。

        具体我们怎么操作呢?我提供两个思路,第一种代码(尾插)

Node* creat_list(void)
 {
    int d;//保存每次用户输入的数据,
    Node* phead = NULL ;//指向链表的第一个结点
    Node* tail = NULL ;//指向链表的最后一个结点
    Node* cur = NULL;//指向当前的新结点
    while (1)
    {
        scanf("%d",&d);

        if(d == 0)
        {
            break;
        }
        cur = malloc(sizeof(*cur));
        cur->data = d;
        cur->next = NULL;
        if (phead == NULL)
        {
            phead = cur;
            tail = cur;
        }
        else
        {
            tail->next = cur;
            tail = cur;
        }
    }
    return phead;
 }
 void list_print(Node*phead)
 {
    Node*cur = phead;
    while (cur != NULL)
    {
        printf("%d",cur->data);
        cur = cur->next;
    }
 }

        我们首先搞了两个指针,一个头指针一个尾指针(注意是头指针不是头结点),当然最开始这个链表是空的里面啥也没有,所以这两个指针都是指向空,我们知道虽然链表在逻辑上是连续的,可是在物理上却并不是这样,所以为我们想要去访问链表里面的一个数据就不如顺序表那样方便,我们需要用到遍历才能够去访问,所以我们又定义了一个cur指针,这个指针是指向当前的新节点,什么意思呢?我输入数据是一个一个输入的,所以每输入一个数据我就给他分配一个相同大小的空间,因为cur是一个结构体指针,所以cur可以去访问任意一个和他相同的结构体,那么到时候输出的时候我们就只要移动cur就完事了,用cur->data输出数据,然后再用cur->next移动就可以循环输出了,很明显要想完整输出,cur一开始就得指向第一个结点。我们在回到creat函数里面来,其实最关键的就是看if  else里面的东西。

        明显在第一个数据插入的时候,尾和头指针都要同时指向cur,因为这个时候它既是头也是尾,然后当第二数据来的时候我们就要让第一个数据不在指向NULL而是指向新来的结点,因为现在第一个数据既是phead也是tail,1、也就是用tail->next = cur;这个时候第一个数据已经不是tail了,2、所以我们要把tail这个指针移动到新来的那个cur上去,tail = cur;最后我们再返回一个头指针方便我们打印,大概画个草图如下:

         第一种也就🆗了,然后是第二种也是先给代码(尾插法)

void creat_list2(Node** phead,int x )
 {
    //这个是新节点,而且如果是尾插,很明显这三步都是一样的
    Node*cur = malloc(sizeof(*cur));
    cur->data = x;
    cur->next = NULL;
    
    //如果第一个都是空的,那新节点就是第一个
    if (*phead == NULL)
    {
        *phead = cur;
    }
    else
    {
        //寻找最后那个节点,也就是指针域为空的那个
        Node* tail = *phead;
        while (tail->next != NULL)
        {
            tail = tail->next;
        }
        tail->next = cur;
       // tail = cur;对比creat1,这里不需要这句的原因如下:
       //creat1要是因为它有这步 tail->next = cur;所以如果不更新末尾节点的话,就会去访问空指针
       //因为前面定义了tail == NULL;而creat2不用是因为Node* tail = *phead;所以当phead不为空,那么tail也绝不为空
       //那么tail->next也就不是空指针了。
    }  
 }
void list_print2(Node*phead)
{
    Node* p = phead;
    while (p)
    {
        printf("%d",p->data);
        p = p->next;
    }
    
}

         第二个的逻辑还要稍微简单些,就是去找末尾结点,然后把新来的结点放到末尾结点后面就行了,这个相比上面那种就是说头结点是作为一个参数了,那么它本来就是一个指针类型的,作为参数你想改变它就得用二级指针了,具体算法就是,先看你的头指针是不是指向空,如果是,那么这个新节点就是第一个,用头指针指向它,如果不是就开始找tail。tail的特点就是tail->next == NULL;所以用着作为判断条件来写就ok了,而且tail要从phead开始找,把链表中的每一个结点全部判断一遍,找到了之后直接tail ->next = cur;就搞定了。

        参数到底改不改变

        其实这个我们在函数哪一块已经说过了,特别是swap函数,这里再给大家两张图去理解,传参到底该怎么传。

        头插

        虽然是上面都是讲了尾插,但是其实头插法和尾插法不就是一个东西麻,尾插主要是对tail动手脚,而头插则是对phead操作。比如拿creat1来说,所有的地方都不变,就对else里面的东西改一下

else
{
    cur->next = phead;
    phead = cur;
}

        完整代码

        完整代码全部放在GitCode上面了可以自行下载查看

HPAlways · GitCode

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值