【趣学C语言和数据结构100例】46-50

简介: 本文介绍五道关于链表操作的C语言编程题,涵盖删除指定值节点、查找最小值节点、删除指定范围内节点、查找两链表公共节点及链表拆分等操作。通过实例代码详细解析了每种操作的实现方法,包括暴力破解与最优解的对比,旨在帮助读者深入理解链表数据结构及其应用,提升编程技能。

【趣学C语言和数据结构100例】

问题描述

  1. 在带头结点的单链表中,删除所有值为 x 的结点,并释放其空间,假设值为 x 的结点不唯一,试编写算法以实现上述操作。

  2. 试编写在带头结点的单链表中寻找一个最小值结点的高效算法(假设该结点唯一)

  3. 设在一个带表头结点的单链表中,所有结点的元素值无序,试编写一个函数,删除表中所有介于给定的两个值(作为函数参数给出)之间的元素(若存在)。

  4. 给定两个单链表,试分析找出两个链表的公共结点。(暴力破解,最优解)

  5. 设 C={a1, b1, a2, b2, ..., an, bn} 为线性表,采用带头结点的单链表存放,设计一个就地算法将其拆分为两个线性表,使得 A={a1, a2, ..., an}, B={bn, bn-1, ..., b1}。

    代码分析

    ==46.带头结点的单链表删指定值==

//如果带头结点,则已经定义好L的头结点,可以直接使用L,L->next
Lnode *pre=L,*p=L->next

//如果不带头结点,则需要先定义L的结点
L=(Node *) malloc(sizeof (LNode));
L->next=NULL;

分析:无返回值+对链表操作+传入删除值,故函数命名为void 函数命(LiukList &L,int x),使用while循环,条件为p !=NULL(不到最后一直遍历),如果p的值为指定的x,则使pre的next和当前的p的next连接,即跳过p,并且释放p,使用free(p),使p=pre->next;继续,如果p的值不为指定的x,则pre和p都向后移动一位,使用p=p->next

//如果遍历,则while循环,条件为p != NULL
while(p){
   }

==47.带头结点的单链表找一个最小值结点==
分析:设置工作指针和存储的最小指针。工作指针:通常为Lnode pre=L,p=L->next,使用while(p)循环遍历,如果当前的工作指针的值<最小指针的值,则继续替换存储,然后继续都向后移动一位。到结束输出最小的值。

==48.带表头结点的单链表删除指定范围的值==
分析:可以参考41,只需要把p的值为指定的x改为范围,其余一样。

==49.两个单链表找公共结点(暴力破解,最优解)==

有两个链表:abcde和fgde,如下图
a->b->c
        ↘
          d->e
        ↗
   f->g

解法1(暴力破解):
分析返回值为Lnode 类型,则函数名为Lnode 函数名(LiiukList L1,LiiukList L2),分析进入函数后需要访问两个链表的工作指针p和q,初始化为Lnode * p=L1->next;使用while(p)循环遍历,使用while(q)循环继续内部遍历,如果p==q则返回p为公共结点,否则使q->向后移动,内部遍历后,没有找到结果,则外部循环移动,并且内部遍历从头遍历。到最后如果没有找到,则返回为NULL

解法2(最优解):

//链表的长度
int length=0;
while(p){
   
    lenth++;
    p=p->next;
}

分析:计算两个的长度,从他们的相差的位置开始。注意:计算链表的长度后使p和q指向L->next。使长度大的先移动差位。然后使用while遍历访问,此时可以同时移动到他们相等时,即可找到公共结点。到最后如果没有找到,则返回为NULL

解法1(暴力破解)的时间复杂度为O(m*n) //平方级
解法2(最优解)的时间复杂度为O(m+n+min(m,n)) //常量级

==50.链表的拆分==

    // 创建链表
    LiukList L = (LiukList)malloc(sizeof(LNode));
    L->next=NULL;
    // 分配链表头结点
    LiukList L = new Lnode; 
    L->next = nullptr;

分析:对A 进行正序,对B进行逆序,即对A 进行尾插,对B进行头插。初始化: 创建一个新的链表 B,并将其头结点 B->next 初始化为 NULL。创建节点ra,p,q(ra指针负责A的,p 指针用于工作,q 指针保存下一个,防断链,B就用B即可)
使用while(p)循环遍历,将第一个赋值给A即ra的下一个(A 的尾部),并更新ra,使p向后移动,如果不为空,则使用q记录p的下一个,防止断链。使p的下一个指向B 的下一个,并且令B 指向p当前的p(B 的头部),使p=q,即A继续,并且已经移动一位。最后在A的末尾加入NULL。返回B。

代码实现

#include <stdio.h>
#include <cstring>
#include <ctype.h>
#include <math.h>
int main() {
   

//    46.在带头结点的单链表工中,别除所有值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法以实现上述操作。
void Del_x(LiukList &L,int x){
   
    Lnode *pre=L,*p=L->next;
    while(p){
   
        if(p->data=x){
   
            pre->next=p->next;
            free(p);
            p=pre->next;
        }
        else{
   
            pre=p;
            p=p->next;    
        }
    }

}     

//    47.试编写在带头结点的单链表工中徐一个最小值结点的高效算法(假设该结点唯一) 
void Del_min(LiukList &L){
   
    Lnode *pre=L,*p=L->next;  //工作 
    Lnode *minpre=L,*min=L->next;  //最小 
    while(p){
   
        if(p->data<min->data){
   
            min=p;
            minpre=pre;
        }
        pre=p;
        p=p->next;    
    }
    minpre->next=min->next;
    free(min);

}

//    48.设在一个带表头结点的单链表中,所有结点的元素值无序,试编写一个函数,删除表中所有介于给定的两个值(作为函数参数给出)之间的元素(若存在)。
void Del_x(LiukList &L,int min,int max){
   
    Lnode *pre=L,*p=L->next;
    while(p){
   
        if(p->data<max && p->data<max>min){
   
            pre->next=p->next;
            free(p);
            p=pre->next;
        }
        else{
   
            pre=p;
            p=p->next;    
        }
    }

}     

//    49.给定两个单链表,试分析找出两个链表的公共结点。
//    暴力破解 
void * publis_node(LiukList L1,LiukList L2){
   
    Lnode *p=L1->next;
    Lnode *q=L2->next;
    while(p){
   
        while(q){
   
            if(p==q){
   
                return p;
            }
            q=p->next; 
        }
        p=p->next;
        q=L2->next;
    }
    return 0;
} 

//    最优解 
Lnode *func(LiukList L1,LiukList L2){
   
    Lnode *p=L1->next;
    Lnode *q=L2->next;
    int lenth1=0,lenth2=0;
    while(p){
   
        lenth1++;
        p=p->next;
    }
    while(q){
   
        lenth2++;
        q=q->next;
    }
    p=L1->next;
    q=L2->next;
    int lenth=lenth1-lenth2
    if(lenth>0){
   
        while(leath--){
   
            p=p->next    
        }
    }
    else{
   
        while(leath--){
   
            q=q->next    
        }
    }
    while(p){
   
        if(p==q){
   
            return p; 
        }
        p=p->next;
        q=q->next;
    }
    return 0;    
}


//    50.设 C={a1,bi,a2,b...,an,b,}为线性表,采用带头结点的单链表存放,设计一个就地算法将其拆分为两个线性表,使得 A-{a1,a2,….,an},B={b.,...,b2, bi}。
LiukList splitList(LiukList& A) {
   
    LiukList B = new Lnode; // 分配 B 链表的头结点
    B->next = nullptr;

    Lnode* p = A;
    Lnode* a = A; // A 链表的尾指针
    Lnode* b = B; // B 链表的尾指针

    while (p->next != NULL) {
   
        // 处理 a 元素
        a->next = p->next;
        a = a->next;
        p = a->next; // 移动到下一个节点

        if (p != NULL) {
   
            // 处理 b 元素
            b->next = p;
            b = b->next;
            p = p->next; // 移动到下一个节点
        }
    }

    a->next = NULL; // A 链表结尾置空
    b->next = NULL; // B 链表结尾置空

    return B;
}

    return 0;
}

总结

本文介绍了五个链表操作的问题及其C语言实现,这些问题涉及删除特定值的节点、查找最小值节点、删除指定范围内的节点、查找两个链表的公共节点以及拆分链表。这些算法问题覆盖了链表操作的多个方面,展示了数据结构在解决实际问题中的应用。

删除特定值的节点问题要求我们在带头结点的单链表中删除所有值为x的节点。这个问题的解决关键在于使用两个指针遍历链表,当发现目标节点时,跳过这些节点并释放内存。

查找最小值节点问题要求我们在带头结点的单链表中寻找一个最小值节点。这个问题的解决需要我们使用两个指针分别记录当前节点和最小值节点,遍历链表直到找到最小值。

删除指定范围内的节点问题要求我们在带表头结点的单链表中删除所有介于给定的两个值之间的元素。这个问题的解决可以参考删除特定值的节点问题,只需将条件从单一值变为值的范围。

查找两个链表的公共节点问题要求我们分析找出两个链表的公共节点。这个问题可以通过暴力破解和最优解两种方法解决。暴力破解方法的时间复杂度为O(m*n),而最优解的时间复杂度为O(m+n+min(m,n))。

拆分链表问题要求我们将一个带头结点的单链表拆分为两个线性表。这个问题的解决需要我们对链表进行遍历,将元素分配到两个新链表中,一个进行正序排列,另一个进行逆序排列。

这些算法的实现不仅展示了C语言在处理链表时的能力,也体现了算法设计的基本思想,如指针操作、条件判断和循环控制。通过这些算法的学习,我们可以更好地理解数据结构和算法的基本概念,提高解决实际问题的能力。

总的来说,这些算法问题不仅锻炼了编程能力,也加深了对数据结构和算法的理解。通过这些问题的解决,我们可以逐步提高自己的编程技能,为将来的学习和工作做好准备。这些算法的掌握对于计算机专业的学生和软件开发人员来说都是非常重要的。通过这些练习,我们可以逐步提高自己的编程技能,为将来的学习和工作做好准备。同时,这些问题的解决也体现了算法在处理链表时的灵活性和效率,为我们在实际开发中遇到类似问题提供了解决思路。

目录
相关文章
|
1月前
|
机器学习/深度学习 算法 C语言
【趣学C语言和数据结构100例】11-15
本文介绍了五个C语言编程问题及其实现,包括矩阵对角线元素之和、有序数组插入、数组逆序、杨辉三角输出和魔方阵生成。每个问题不仅涉及基本的数组操作,还涵盖了算法设计的核心思想,如循环、条件判断和递归。通过解决这些问题,读者可以加深对C语言和数据结构的理解,提升编程技能。这些问题的解决过程展示了如何有效处理数组和矩阵,以及如何利用算法优化程序性能,为实际应用提供了宝贵的实践经验。
56 4
【趣学C语言和数据结构100例】11-15
|
23天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
34 1
|
1月前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
45 4
|
1月前
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
43 4
|
1月前
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
39 4
|
1月前
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
49 4
|
1月前
|
存储 算法 vr&ar
【趣学C语言和数据结构100例】71-75
本文介绍了五个C语言数据结构问题及其实现,涵盖链表与二叉树操作,包括按奇偶分解链表、交换二叉树左右子树、查找节点的双亲节点、计算二叉树深度及求最大关键值。通过递归和遍历等方法,解决了理论与实际应用中的常见问题,有助于提升编程能力和数据结构理解。
37 4
|
1月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】66-70
本书《趣学C语言和数据结构100例》精选了5个典型的数据结构问题及C语言实现,涵盖链表与数组操作,如有序集合的集合运算、有序序列表的合并、数组中两顺序表位置互换、三递增序列公共元素查找及奇偶数重排。通过详细解析与代码示例,帮助读者深入理解数据结构与算法设计的核心思想,提升编程技能。
34 4
|
1月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】51-55
本文介绍了五个关于链表操作的C语言实现案例,包括删除单链表中的重复元素、从两个有序链表中查找公共元素、判断一个链表是否为另一链表的连续子序列、判断循环双链表是否对称及合并两个循环单链表。每个案例都详细解析了算法思路与实现方法,涵盖了链表操作的多种场景,旨在帮助读者深入理解链表数据结构的应用,提升算法设计与编程能力。
39 4
|
1月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】16-20
本文精选了五个C语言编程问题,涵盖数组操作、字符串处理等基础领域。包括查找二维数组中的鞍点、折半查找法、统计文章中字符数量、电文解密及字符串连接。每个问题都附有详细的代码实现与分析,旨在帮助读者理解算法逻辑,提升编程技巧。通过这些实践,不仅能锻炼编程能力,还能加深对数据结构和算法的理解,为未来的学习和工作打下坚实基础。
63 4