C语言及程序设计进阶例程-18 链表中结点的插入和删除

简介: 贺老师教学链接  C语言及程序设计进阶 本课讲解回顾:动态分配和撤销内存#include <stdio.h>#include <malloc.h>struct Student{ int num; float score; struct Student *next;};int main( ){ struct Studen

贺老师教学链接  C语言及程序设计进阶 本课讲解


回顾:动态分配和撤销内存

#include <stdio.h>
#include <malloc.h>
struct Student
{
    int num;
    float score;
    struct Student *next;
};


int main( )
{
    struct Student *p;
    p=malloc(sizeof(struct Student));
    p->num=31001;
    p->score=89.5;
    printf("%d  %.1f\n", p->num, p->score);
    free(p);
    return 0;
}


遍历链表
void traverse(Node *h)
{
    Node *p;
    p = h;  /*p指向头结点*/
    while(p!=NULL)  
    {
        printf("%-5d", p->data);  /*“访问”结点,此处用最简单的操作:读取输出*/
        p = p->next; /*p指向下一个结点,继续处理*/
    }
    printf("\n");
    return;
}


创建一个链表
#include <stdio.h>
#include <malloc.h>
typedef struct NODE
{
    int data;
    struct NODE *next;
} Node;
Node *createLinkList(int n);
void traverse(Node *h);


int main( )
{
    Node *head;
    head = createLinkList(5);
    traverse(head);
    return 0;
}


Node *createLinkList(int n)
{
    Node *h=NULL, *p, *last;  /*h指向头结点,p指向新增结点,last指向尾结点*/
    int d;   /*用于输入要插入的元素的值*/
    int i;
    for(i=0; i<n; i++)
    {
        scanf("%d", &d);
        p = (Node *)malloc(sizeof(Node));  /*p指向新增的结点*/
        p->data = d;    /*为数据域赋值*/
        p->next = NULL;   /*指针域为空*/
        if (h==NULL) /*如果h==NULL为真,说明p为第一个结点,由h指向该结点*/
            h = p;
        else  /*否则,原最后一个结点指向新增的结点,新结点加在链表尾*/
            last->next = p;
        last= p;   /*last保持指向最后一个结点的角色*/
    }
    return h;
};


void traverse(Node *h)
{
    Node *p;
    p = h;  /*p指向头结点*/
    while(p!=NULL)
    {
        printf("%-5d", p->data);  /*“访问”结点,此处用最简单的操作:读取输出*/
        p = p->next; /*p指向下一个结点,继续处理*/
    }
    printf("\n");
    return;
}


插入结点应用——建立有序链表
#include <stdio.h>
#include <malloc.h>
typedef struct NODE
{
    int data;
    struct NODE *next;
} Node;
Node *insertNode(Node *h, int b);
void traverse(Node *h);


int main( )
{
    int b[]= {67, 25, 78, 99, 87},i;
    Node *head=NULL;
    for(i=0; i<5; i++)
        head=insertNode(head, b[i]);
    traverse(head);
    return 0;
}
Node *insertNode(Node *h, int b)
{
    Node *q1=h,*q2,*p;
    p=(Node*)malloc(sizeof(Node));  /*生成新结点*/
    p->data=b;
    if(h==NULL)   /*当前链表为空,p作为首结点*/
    {
        h=p;     /*头结点就是p,将p赋值给h*/
        p->next=NULL;  /*p的指针域赋值为空,表示尚无下一个结点*/
    }
    else if(p->data<h->data) /*要插入的元素值小于首结点元素,插入结点作为首结点*/
    {
        h=p;  /*将头结点h赋值为p*/
        p->next=q1; /*p的下一个结点是原先的首结点(见q1的初始化,其值为h)*/
    }
    else  /*在中间找到插入p的位置,将其插入*/
    {
        /*先找到合适的位置,q1的初值是h,即从头结点开始考察*/
        while((q1!=NULL&&p->data>=q1->data))
        {
            q2=q1;         /*q2记录q1的值*/
            q1=q1->next;   /*q1继续向后试探,直到a1*/
        }
        /*将新结点p插在q2后*/
        p->next=q2->next;  /*p的下一个结点为当前q2的下一结点,即p1*/
        q2->next=p;    /*q2的下一个结点y变为p,不再是q1*/
    }
    return h;
}


void traverse(Node *h)
{
    Node *p;
    p = h;  /*p指向头结点*/
    while(p!=NULL)
    {
        printf("%-5d", p->data);  /*“访问”结点,此处用最简单的操作:读取输出*/
        p = p->next; /*p指向下一个结点,继续处理*/
    }
    printf("\n");
    return;
}


删结点应用——在有序表中删除
#include <stdio.h>
#include <malloc.h>
typedef struct NODE
{
    int data;
    struct NODE *next;
} Node;
Node *insertNode(Node *h, int b);
Node *deleteNode(Node *h, int b);
void traverse(Node *h);


int main( )
{
    int b[]= {67, 25, 78, 99, 87},i;
    Node *head=NULL;
    for(i=0; i<5; i++)
        head=insertNode(head, b[i]);
    traverse(head);
    head=deleteNode(head, 43);
    traverse(head);
    head=deleteNode(head, 78);
    traverse(head);
    return 0;
}
Node *insertNode(Node *h, int b)
{
    Node *q1=h,*q2,*p;
    p=(Node*)malloc(sizeof(Node));  /*生成新结点*/
    p->data=b;
    if(h==NULL)   /*当前链表为空,p作为首结点*/
    {
        h=p;     /*头结点就是p,将p赋值给h*/
        p->next=NULL;  /*p的指针域赋值为空,表示尚无下一个结点*/
    }
    else if(p->data<h->data) /*要插入的元素值小于首结点元素,插入结点作为首结点*/
    {
        h=p;  /*将头结点h赋值为p*/
        p->next=q1; /*p的下一个结点是原先的首结点(见q1的初始化,其值为h)*/
    }
    else  /*在中间找到插入p的位置,将其插入*/
    {
        /*先找到合适的位置,q1的初值是h,即从头结点开始考察*/
        while((q1!=NULL&&p->data>=q1->data))
        {
            q2=q1;         /*q2记录q1的值*/
            q1=q1->next;   /*q1继续向后试探,直到a1*/
        }
        /*将新结点p插在q2后*/
        p->next=q2->next;  /*p的下一个结点为当前q2的下一结点,即p1*/
        q2->next=p;    /*q2的下一个结点y变为p,不再是q1*/
    }
    return h;
}


Node *deleteNode(Node *h, int b)
{
    Node *p, *q;
    p=h;   /*p首先指向头结点*/
    if(h==NULL)  /*链表为空时不能删除*/
        printf("List is null, delete fail.\n");
    else
    {
        /*首先找到要删除的结点*/
        while(b!=p->data&&p->next!=NULL)
        {
            q=p;    /*q记录p的值*/
            p=p->next;   /*p接着指向下一个结点,q一直保持是p的上一个结点*/
        }
        if(b==p->data)   /*要删除的结点p在链表中存在*/
        {
            if(p==h) /*要删除的结点就是头结点时,令h指向p的下一个结点即可*/
                h = p->next;
            else   /*否则,删除q的下一个结点p*/
                q->next = p->next;
            free(p);  /*释放p结点*/
        }
        else
            printf("%d not found, delete fail.\n", b);
    }
    return h;
}


void traverse(Node *h)
{
    Node *p;
    p = h;  /*p指向头结点*/
    while(p!=NULL)
    {
        printf("%-5d", p->data);  /*“访问”结点,此处用最简单的操作:读取输出*/
        p = p->next; /*p指向下一个结点,继续处理*/
    }
    printf("\n");
    return;
}


目录
相关文章
|
算法 C语言
【C语言程序设计——循环程序设计】求解最大公约数(头歌实践教学平台习题)【合集】
采用欧几里得算法(EuclideanAlgorithm)求解两个正整数的最大公约数。的最大公约数,然后检查最大公约数是否大于1。如果是,就返回1,表示。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。作为新的参数传递进去。这个递归过程会不断进行,直到。有除1以外的公约数;变为0,此时就找到了最大公约数。开始你的任务吧,祝你成功!是否为0,如果是,那么。就是最大公约数,直接返回。
537 18
|
Serverless C语言
【C语言程序设计——循环程序设计】利用循环求数值 x 的平方根(头歌实践教学平台习题)【合集】
根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码,求解出数值x的平方根;运用迭代公式,编写一个循环程序,求解出数值x的平方根。注意:不能直接用平方根公式/函数求解本题!开始你的任务吧,祝你成功!​ 相关知识 求平方根的迭代公式 绝对值函数fabs() 循环语句 一、求平方根的迭代公式 1.原理 在C语言中,求一个数的平方根可以使用牛顿迭代法。对于方程(为要求平方根的数),设是的第n次近似值,牛顿迭代公式为。 其基本思想是从一个初始近似值开始,通过不断迭代这个公式,使得越来越接近。
517 18
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
856 16
|
C语言
【C语言程序设计——循环程序设计】统计海军鸣放礼炮声数量(头歌实践教学平台习题)【合集】
有A、B、C三艘军舰同时开始鸣放礼炮各21响。已知A舰每隔5秒1次,B舰每隔6秒放1次,C舰每隔7秒放1次。编程计算观众总共听到几次礼炮声。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。开始你的任务吧,祝你成功!
407 13
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
739 3
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
975 2
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
819 1
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
311 2