【新手】关于C语言链表的创建和相关API实现

本文介绍了链表作为非线性数据结构的特点,包括易于修改但查询效率低,以及与数组的区别。讲解了单向非循环链表的结构,并提供了C语言实现链表的基本操作,如创建、遍历、判断空、计算长度、排序、插入和删除节点的代码示例。
摘要由CSDN通过智能技术生成

介绍::本次的内容有两部分,一.我对链表的图文理解,二.具体代码的实现

一、什么是链表?

        在我理解里就是非线性数据结构,与数组正相反,那么它的特点就是容易修改(即删除和插入等操作),但不容易查询,速度比数组慢很多。并且,数组的创建需要一整片链接的内存空间,而链表则不需要,是以离散的方式存储在硬盘,相对灵活很多。【链表是什么和链表特性】

        链表还分为循环链表和非循环链表,我目前只会非循环。【链表有哪些类型】

        链表可以用来实现栈,树,队列等数据结构,对处理实际问题有着广泛的应用【将来的应用,其实我也不是很清楚,就概略讲讲已经知道的吧】

        单向非循环链表的具体结构由头节点+N数量的节点组成,而N数量的节点每个节点都由两个区域组成,一是数据域,二是指针域,数据域用于保存实际数据,指针域用于保存下一个节点的地址,两个区域组成一个节点,而头部节点较为特殊,因为它数据域不会存放数据,只负责作为一个链表的头部指向下一个节点,但我们实际遍历链表,实际是从头节点的下一个节点开始的。头节点只是为了方便以后各种对链表的操作而存在。这样,就可以完成一个由头部出发的单向非循环链表【细节】

 

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct Node
{
    int data ;            //这是链表的数据域
    struct Node * pNext;  //这是链表的指针域
}NODE,*PNODE;             //这里用了typedef函数,NODE表示这个数据结构的简写,*PNODE则表示这个数据结构的内存地址

PNODE create_list(void)   //创建链表的函数,分成两部分,第一是由用户输入需要的长度,第二部分是由用户手动赋值
{
    int len;              
    int val;              //将会被用来承载键盘输入的值
    printf("请输入要生成的节点数");
    scanf("%d",&len);
    PNODE pHead = (PNODE)malloc(sizeof(NODE)); //首先生成一个头节点,方便接下来的操作
    if (pHead == NULL)
    {
        printf("内存分配失败??");
        exit(-1);
    }
    PNODE pTail = pHead;      //由于在赋值过程中,我们需要不断创造节点,必须有一个指针始终指向尾节点才能方便我们为新的节点赋值
    pTail->pNext = NULL;      
    for(int i=0;i<len;++i)    //开始循环,次数由一开始输入的长度决定
    {
        printf("请输入第%d个节点的值:",i+1);
        scanf("%d",&val);
        PNODE pNew = (PNODE)malloc(sizeof(NODE)); //pNew就是新节点,每轮循环都会创建
        if (pNew == NULL)     
        {
            printf("内存分配失败??");
            exit(-1);
        }
        pNew->data=val;     //首先把值赋给新节点的数据域
        pNew->pNext=NULL;   //然后把新节点的指针域清空,因为这将会并入到链表里成为最后一个节点
        pTail->pNext=pNew;  //然后把上一个尾节点的指针指向新节点
        pTail=pNew;         //新节点成为了新的尾节点
    }
    return pHead;           //将这个链表头指针return出去
}

void show_list(PNODE pHead) //用于遍历,观察链表
{
    PNODE p;                       //创建一个节点用来遍历链表
    for ( p = pHead->pNext;p->pNext!=NULL; p=p->pNext) //次数就是当尾节点指针域出现NULL的时候停下
    {   
        printf("%d  ",p->data);
    }
    printf("%d  \n",p->data);  //虽然此时尾节点指针域是NULL,但它仍属于链表,所以再打印一次(这里可以改进)
}

bool is_empty(PNODE pHead)  //用于判断链表是否为空
{
    if(NULL == pHead->pNext)//头节点下面没有任何数据则为空
    {
        printf("链表为空");
        return true;
    }
    else
        return false;
}

int lenght_list(PNODE pHead)    //判断链表长度
{
    PNODE p= pHead->pNext;     //创建一个节点用来遍历链表
    int len;                    //用来计数
    for (len=0;p->pNext!=NULL;len++)
    {
        p=p->pNext;
    }
    return len;
}

void sort_list(PNODE pHead)     //排序,这次用的是选择排序,在这里面就涉及了泛型的知识,不论是对数组还是链表我们都用同一种逻辑处理的,但具体实现方式却不一样
{
    PNODE p,q;
    int t,i,x;
    int len=lenght_list(pHead);
    for(i=0,p=pHead->pNext;i<len;++i,p=p->pNext)
    {
        for(x=i,q=p->pNext;x<len;++x,q=q->pNext)
        {
            if(p->data>q->data)
            {
                t=p->data;
                p->data=q->data;
                q->data=t;
            }
        }
    }
}

bool insert_list(PNODE pHead,int pos,int val)   //对链表的插入操作
{
    int len = lenght_list(pHead);               
    PNODE p=pHead;
    int i=0;
    if (len<pos)    //我的规则是插入的位置最少也得是尾节点后面一个,否则错误。
    {
        printf("节点有误,插入失败");
        return false;
    }
    while (NULL!=p & i< pos-1)  //这里我们把一个临时节点P遍历到插入位置的前一个位置,比如我要在5的位置插入,那现在P已经来到了4
    {
        p=p->pNext;
        i++;
    }
    PNODE pNew=(PNODE)malloc(sizeof(NODE)); //创建一个新节点,即将要插入的节点
    if (NULL==pNew)
    {
        printf("动态分配内存失败\n");
        exit(-1);
    }
    pNew->data=val;   //把值赋给新节点
    pNew->pNext=p->pNext;   //将新节点指向下一个节点
    p->pNext=pNew;          //将上一个节点指向新节点,这样就完成了一个节点的嵌入
}

bool delete_arr(PNODE pHead,int pos)    //删除
{
    int len = lenght_list(pHead);  //这上半部分仍然是做一个判断,判断删除位置是否正确
    PNODE p=pHead;
    int i=0;
    if (len<pos)
    {
        printf("节点有误,删除失败");
        return false;
    }
    while (NULL!=p & i< pos-1)  //这里我们依然通过临时P节点找到要删除的上一个节点,如要删5,现在P到了4
    {
        p=p->pNext;
        i++;
    }
    PNODE t=p->pNext;           //我们用一个临时节点T将P的指针域保存起来,否则P的下一个节点删除时候就无法,也无法释放内存了
    p->pNext=p->pNext->pNext;   //现在我们直接将P节点指向下下个节点,既跨过了即将被删除的节点
    free(t);                    //释放被删除节点的内存
    t=NULL;
    if(len==lenght_list(pHead)-1)   //最后做一轮判断,如果节点长度少了1,那么删除成功,删除失败的处理方法各位可以自己完善
    {
        printf("删除成功");
        return true;
    }
    return false;
}

int main(void)      //调试
{
    PNODE pHead = NULL;
    pHead = create_list();
    show_list(pHead);
    sort_list(pHead);
    show_list(pHead);
    insert_list(pHead,2,8);
    show_list(pHead);
    delete_arr(pHead,3);
    show_list(pHead);
    return 0; 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值