C语言-链表(操作:增、删、改、查)

定义:链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构。
特点:链表由一系列节点(链表中每一个元素称为节点)组成,节点在运行时动态生成(malloc),每个节点包括两个部分:

  • 一个是存储数据元素的数据域
  • 另一个是存储下一个节点地址的指针域

链表的操作:增、删、改、查

链表的创建、链表的遍历、链表的释放

#include 
#include 
// 定义节点结构体
typedef struct student
{
    // 数据域
    int num;  // 学号
    int score; // 分数
    char name[20]; // 姓名
    // 指针域
    struct student *next;
}STU;

void link_creat_head(STU **p_head, STU *p_new)
{
    STU *p_mov = *p_head;
    if(*p_head  == NULL)  // 当第一次加入链表为空时,head执行p_new
    {
        *p_head = p_new;
        p_new->next=NULL;
    }
    else  // 第二次及以后加入链表
    {
        while (p_mov->next != NULL) {
            p_mov = p_mov->next;  // 找到原有链表的最后一个节点
        }

        p_mov->next = p_new;  // 将新申请的节点加入链表
        p_new->next = NULL;
    }
}

// 链表的遍历
void link_print(STU *head)
{
    STU *p_mov;   // 定义新的指针 用来保存链表的首地址
    p_mov = head;

    while (p_mov != NULL)   // 当指针保存最后一个结点的指针域是NULL时,循环结束。
    {
        printf("num=%d score=%d name:%s\n", p_mov->num, p_mov->score, p_mov->name);

        p_mov = p_mov->next;   // 注意千万不要使用p_mov++ 因为当前链表不一定是连续的内存地址
    }
}

// 链表的释放
void link_free(STU **p_head)
{
    STU *pb = *p_head;   // 定义一个指针变量保存头结点的地址
    while (*p_head != NULL)
    {
        // 先保存p_head指向的节点的地址
        pb = *p_head;
        // p_head保存下一个节点的地址
        *p_head = (*p_head)->next;
        // 释放结点并防止野指针
        free(pb);
        pb = NULL;
    }
}

int main()
{
    STU *head = NULL, *p_new = NULL;
    int num,i;
    printf("input init number:\n");
    scanf("%d", &num);
    for(i = 0; i<num; i++)
    {
        p_new = (STU*)malloc(sizeof(STU));  // 申请一个新节点
        printf("input num/score/name:\n");  // 给新节点赋值
        scanf("%d %d %s", &p_new->num, &p_new->score, &p_new->name);

        link_creat_head(&head, p_new);  // 将新节点加入链表
        // &head 是一级指针的地址(二级指针)
    }

    link_print(head);

	link_free(&head);
	
    return 0;
}


也可参考这个链接

/*尾插法建立链表*/
#include 
#include 

struct list     //创建链表的结构体
{
    int    data;                //创建数据域
    struct list *next;          //创建指针域
};

int main(int argc,char *argv[])
{
    int n;                      //设置结点的个数
    int i;                      //设置创建的结点的个数
    struct list *head = (struct list *)malloc(sizeof(struct list));
    //创建头结点用malloc分配内存
    head->next = NULL;          //头结点指针初始化
    struct list *p;             //创建p结点,p结点用于记录链表尾结点
    p = head;                   //p结点指针赋值为头结点
    printf("input init number:\n");
    scanf("%d",&n);

    /* 链表的创建*/
    for(i=0;i<n;i++)            //循环创建结点
    {
        struct list *p1=(struct list *)malloc(sizeof(struct list));
        //创建p1结点,并分配内存
        scanf("%d",&p1->data);  //给p1结点赋值
        p->next = p1;
        p1->next = NULL;        //让插在尾部的p1结点的指针指向NULL
        p = p1;
    }

     /*链表的遍历*/
    p = head;                   //从头结点开始遍历
    while(p->next != NULL)      //只要p结点下一个结点不为空,证明还有结点存在,打印p后面结点的数据
    {
        printf("%d",p->next->data);
        p = p->next;            //p结点移动到下一个结点
    }
    printf("\n");

    /*清空链表*/
    p=head->next;               //让p结点指向头结点下一位
    while(head->next!=NULL)     //当头结点下一位一直不为空时
    {
        head->next=p;           //将头结点下一位赋予p
        p=p->next;              //新的p结点=头结点下一位的下一位 直到尾结点=头结点
        free(head->next);
        head->next=NULL;        //确保头结点下一位为空
    }
    printf("clean the list sucessfuly!\n");
    return 0;
}


链表节点的查找

#include 
#include 
// 定义节点结构体
typedef struct student
{
    // 数据域
    int num;  // 学号
    int score; // 分数
    char name[20]; // 姓名
    // 指针域
    struct student *next;
}STU;

void link_creat_head(STU **p_head, STU *p_new)
{
    STU *p_mov = *p_head;
    if(*p_head  == NULL)  // 当第一次加入链表为空时,head执行p_new
    {
        *p_head = p_new;
        p_new->next=NULL;
    }
    else  // 第二次及以后加入链表
    {
        while (p_mov->next != NULL) {
            p_mov = p_mov->next;  // 找到原有链表的最后一个节点
        }

        p_mov->next = p_new;  // 将新申请的节点加入链表
        p_new->next = NULL;
    }
}

// 链表的遍历
void link_print(STU *head)
{
    STU *p_mov;   // 定义新的指针 用来保存链表的首地址
    p_mov = head;

    while (p_mov != NULL)   // 当指针保存最后一个结点的指针域是NULL时,循环结束。
    {
        printf("num=%d score=%d name:%s\n", p_mov->num, p_mov->score, p_mov->name);

        p_mov = p_mov->next;   // 注意千万不要使用p_mov++ 因为当前链表不一定是连续的内存地址
    }
}


// 链表的释放
void link_free(STU **p_head)
{
    STU *pb = *p_head;   // 定义一个指针变量保存头结点的地址
    while (*p_head != NULL)
    {
        // 先保存p_head指向的节点的地址
        pb = *p_head;
        // p_head保存下一个节点的地址
        *p_head = (*p_head)->next;
        // 释放结点并防止野指针
        free(pb);
        pb = NULL;
    }
}

// 链表节点的查找

// 按照学号查找
STU * link_search_num(STU *head,int num)
{
    STU *p_mov;   // 定义的指针变量保存第一个结点的地址
    p_mov = head;
    while (p_mov != NULL)  // 当没有到达最后一个结点的指针域时循环继续
    {
        // 如果找到是当前结点的数据,则返回当前结点的地址
        if(p_mov->num == num)  // 找到了
        {
            return p_mov;
        }
        // 如果没有找到,则继续对比下一个结点的指针域
        p_mov = p_mov->next;
    }
    // 当循环结束的时候还没有找到,说明要查找的数据不存在,返回NULL进行标识
    return NULL;  // 没有找到
}

// 按照姓名查找
STU * link_search_name(STU *head,char *name)
{
    STU *p_mov;
    p_mov = head;
    while (p_mov != NULL)
    {
        if(strcmp(p_mov->name,name) == 0)  // 找到了   strcmp函数比较两个字符串的内容是否一致
        {
            return p_mov;
        }
        p_mov = p_mov->next;
    }
    return NULL;   // 没有找到
}

int main()
{
    STU *head = NULL, *p_new = NULL;
    int num,i;
    printf("input init number:\n");
    scanf("%d", &num);
    for(i = 0; i<num; i++)
    {
        p_new = (STU*)malloc(sizeof(STU));  // 申请一个新节点
        printf("input num/score/name:\n");  // 给新节点赋值
        scanf("%d %d %s", &p_new->num, &p_new->score, &p_new->name);

        link_creat_head(&head, p_new);  // 将新节点加入链表
        // &head 是一级指针的地址(二级指针)
    }

    link_print(head);

    // 查学号
#if 0
    STU *pb;
    while (1)
    {
        printf("input num:\n");
        scanf("%d",&num);
        pb = link_search_num(head,num);
        if(pb!=NULL)
        {
            printf("found!!!\n");
        }
        else
        {
            printf("not found\n");
        }
    }
#endif


#if 1
    STU *pb;
    char name[32] = "";
    while (1)
    {
        printf("input name:\n");
        scanf("%s",name);
        pb = link_search_name(head,name);
        if(pb!=NULL)
        {
            printf("found!!!\n");
        }
        else
        {
            printf("not found\n");
        }
    }
#endif

    link_free(&head);
    return 0;
}


链表节点的删除、链表中插入一个节点


#include 
#include 
// 定义节点结构体
typedef struct student
{
    // 数据域
    int num;  // 学号
    int score; // 分数
    char name[20]; // 姓名
    // 指针域
    struct student *next;
}STU;

void link_creat_head(STU **p_head, STU *p_new)
{
    STU *p_mov = *p_head;
    if(*p_head  == NULL)  // 当第一次加入链表为空时,head执行p_new
    {
        *p_head = p_new;
        p_new->next=NULL;
    }
    else  // 第二次及以后加入链表
    {
        while (p_mov->next != NULL) {
            p_mov = p_mov->next;  // 找到原有链表的最后一个节点
        }

        p_mov->next = p_new;  // 将新申请的节点加入链表
        p_new->next = NULL;
    }
}

// 链表的遍历
void link_print(STU *head)
{
    STU *p_mov;   // 定义新的指针 用来保存链表的首地址
    p_mov = head;

    while (p_mov != NULL)   // 当指针保存最后一个结点的指针域是NULL时,循环结束。
    {
        printf("num=%d score=%d name:%s\n", p_mov->num, p_mov->score, p_mov->name);

        p_mov = p_mov->next;   // 注意千万不要使用p_mov++ 因为当前链表不一定是连续的内存地址
    }
}


// 链表的释放
void link_free(STU **p_head)
{
    STU *pb = *p_head;   // 定义一个指针变量保存头结点的地址
    while (*p_head != NULL)
    {
        // 先保存p_head指向的节点的地址
        pb = *p_head;
        // p_head保存下一个节点的地址
        *p_head = (*p_head)->next;
        // 释放结点并防止野指针
        free(pb);
        pb = NULL;
    }
}

// 链表节点的查找

// 按照学号查找
STU * link_search_num(STU *head,int num)
{
    STU *p_mov;   // 定义的指针变量保存第一个结点的地址
    p_mov = head;
    while (p_mov != NULL)  // 当没有到达最后一个结点的指针域时循环继续
    {
        // 如果找到是当前结点的数据,则返回当前结点的地址
        if(p_mov->num == num)  // 找到了
        {
            return p_mov;
        }
        // 如果没有找到,则继续对比下一个结点的指针域
        p_mov = p_mov->next;
    }
    // 当循环结束的时候还没有找到,说明要查找的数据不存在,返回NULL进行标识
    return NULL;  // 没有找到
}

// 按照姓名查找
STU * link_search_name(STU *head,char *name)
{
    STU *p_mov;
    p_mov = head;
    while (p_mov != NULL)
    {
        if(strcmp(p_mov->name,name) == 0)  // 找到了   strcmp函数比较两个字符串的内容是否一致
        {
            return p_mov;
        }
        p_mov = p_mov->next;
    }
    return NULL;   // 没有找到
}



// 链表结点的删除
void link_delete_num(STU **p_head, int num)
{
    STU *pb, *pf;
    pb = pf = *p_head;
    if(*p_head == NULL)  // 链表为空,不用删
    {
        printf("null ,no need to del");
        return ;
    }
    while (pb->num != num && pb->next != NULL)  // 循环找,要删除的结点
    {
        pf = pb;
        pb = pb->next;
    }
    if (pb->num == num)  // 找到了一个节点的num和num相同
    {
        if(pb == *p_head)  // 要删除的节点是头节点
        {
            *p_head = pb->next;  // 让保存头结点的指针,保存后一个结点的地址。
        }
        else
        {
            pf->next = pb->next;  // 前一个节点的指针域,保存要删除的,后一个结点的地址。
        }
        // 释放空间
        free(pb);
        pb = NULL;
    }
    else  // 没有找到
    {
        printf("not found...\n");
    }
}


// 链表的插入:按照学号的顺序插入
void link_insert_num(STU **p_head,STU *p_new)
{
    STU *pb, *pf;
    pb = pf = *p_head;
    if(*p_head == NULL)   // 链表为空链表
    {
        *p_head = p_new;
        p_new->next = NULL;
        return ;
    }
    while ( ( p_new->num >= pb->num )  &&  ( pb->next != NULL ) )
    {
        pf = pb;
        pb = pb->next;
    }

    if(p_new->num < pb->num)  // 找到一个节点的num比新来的节点num大
    {
        if(pb == *p_head) // 找到的节点是头节点,插在最前面
        {
            p_new->next = *p_head;
            *p_head = p_new;
        }
        else
        {
            pf->next = p_new;
            p_new->next = pb;
        }
    }
    else  // 没有找到pb的num比p_new->num大的节点,插在最后
    {
        pb->next = p_new;
        p_new->next = NULL;
    }
}




int main()
{
    STU *head = NULL, *p_new = NULL;
    int num,i;
    printf("input init number:\n");
    scanf("%d", &num);
    for(i = 0; i<num; i++)
    {
        p_new = (STU*)malloc(sizeof(STU));  // 申请一个新节点
        printf("input num/score/name:\n");  // 给新节点赋值
        scanf("%d %d %s", &p_new->num, &p_new->score, &p_new->name);

        link_creat_head(&head, p_new);  // 将新节点加入链表
        // &head 是一级指针的地址(二级指针)
    }

    link_print(head);

    // 删除操作
//    printf("delete: input num:\n");
//    scanf("%d", &num);
//    link_delete_num(&head, num);

//    link_print(head);


    // 链表中插入一个节点
    while (1)
    {
        printf("Please enter the content(num score name) you want to insert\n");
        p_new = (STU*)malloc(sizeof(STU));  // 申请一个新节点
        scanf("%d %d %s", &p_new->num, &p_new->score, &p_new->name);
        link_insert_num(&head, p_new);
        link_print(head);
    }


    // 查学号
#if 0
    STU *pb;
    while (1)
    {
        printf("input num:\n");
        scanf("%d",&num);
        pb = link_search_num(head,num);
        if(pb!=NULL)
        {
            printf("found!!!\n");
        }
        else
        {
            printf("not found\n");
        }
    }
#endif


#if 0
    STU *pb;
    char name[32] = "";
    while (1)
    {
        printf("input name:\n");
        scanf("%s",name);
        pb = link_search_name(head,name);
        if(pb!=NULL)
        {
            printf("found!!!\n");
        }
        else
        {
            printf("not found\n");
        }
    }
#endif

    link_free(&head);
    return 0;
}



你可能感兴趣的:(c语言基础,c语言,链表)