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

简介: 本文介绍了五个关于C语言和数据结构的经典问题及其实现方法,涵盖查找链表共同后缀、删除重复节点、重新排列链表元素、合并有序链表以及特定条件下的链表排序。每个问题通过具体的算法设计,不仅展示了链表操作的灵活性,还强调了效率优化的重要性。通过这些问题的探讨,读者可以深入理解链表的基本操作和高级应用,提升解决实际问题的能力。

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

问题描述

61.假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,可共享相同的后缀存储空间,例如,loading 和 being 的存储映像如下图所示,设 strl 和 str2 分别指向两个单词所在单链表的头结点,链表结点结构为 data next。请设计个时间上尽可能高效的算法,找出由 st1 和 str2 所指向两个链表共同后缀的起始位置(如图中字符i所在结点的位置 P)。

62.用单链表保存m 个整数,结点的结构为[data][link],且|data|<n(n 为正整数)。现要求设计一个时间复杂度尽可能高效的算法,对于链表中 data 的绝对值相等的结点,仅保留第欠出现的结点而删除其余绝对值相等的结点。例如,若给定的单链表 head 如下

63.设线性表L=(a1.a.a3.…,an2,an1.am)采用带头结点的单链表保存,链表中的结点定义如下

typedef struct LNode{
   
    int data;
    struct Lnode* next;
}LNode, LinkList:

请设计一个空间复杂度为o(1)且时间上尽可能高效的算法,重新排列工中的各结点,得到线性表L'=(a1,an,a2,an-1,a3,an2.…)

64.将两个按值有序排列的非空线性链表合并为一个按值有序的线性链表

65.设线性表L=(X1,X2,…,Xn-2,Xn-1,Xn)中存储整型数据,采用带头结点的单链表保存。中奇数位序的数据元素按升序存放,偶数位序的数据元素按降序存放。请设计一个空间复杂度为 0(1)且时间上尽可能高效的算法,将链表中的元素按从小到大的顺序排序

代码分析

==61.带头结点的单链表,共同后缀的起始位置==
分析:返回节点+对AB不操作,故函数名为Lnode * 函数名(LiukList str1,LiukList str2).。使用while(p)循环遍历,先记录并计算,str1和str2的长度,先使长度小的先移动他们的差,然后再不到最后的情况下,同时移动,找到相同节点。返回该位置。

==62.单链表中删除绝对值一样的节点==
分析:传入一个数组和n,故函数名为void 函数名(LiukList L,int n)。创建一个动态数组存储(n+1大小)并初始化为0,然后开始遍历,使用三目运算符,使负的变为正,即(m=p->next->data > 0 ?p->next->data:-p->next->data;),如果再数组中为0,则记录,并继续,如果不为0,则使跳过其。知道循环结束。

==63.重新排列,a1,an,a2,an-1,a3,an2.…==
思路:1.找到链表的中点 2.反转链表的后半部分,使用头插法 3.交替合并链表的前半部分和反转后的后半部分,使用尾插法。

具体分析:找到链表的中间节点:使用两个指针 p 和 q。p 每次移动一步,q 每次移动两步。当 q 到达链表末尾时,p 刚好位于中间节点。分割链表:q 现在指向后半部分的头节点,将 p 的 next 指向 NULL,以断开链表。 反转后半部分链表:使用指针 r 来保存当前节点的下一个节点。然后将当前节点 q 的 next 指向前半部分的头节点 p 的 next,并将 p 的 next 更新为 q。继续这个过程,直到后半部分的所有节点都被反转并插入到前半部分的开头。使用指针 p 指向前半部分的头节点,指针 q 指向反转后的后半部分的头节点。交替地将 q 的节点插入到 p 的后面,直到 q 的所有节点都被合并。

==64.两个值有序非空线性链表合并一个按值有序的链表==
分析:返回为一个链表,传入的只要A会改变,故函数名为Linklist func(Linklist A,Linklist B),定义p和q分别指向A和B,先创造C的头部,令A,B中小的赋值,使用while循环一起遍历,使值小的在C的后面,并更新C的尾部,在结束循环时,在C的尾部加入指向NULL。返回C即可。

==65.奇数位序的数据元素按升序存放,偶数位序的数据元素按降序存放->原地条件下->按从小到大的顺序排序==
分析:传入链表对其操作并返回。故函数名为:Linklist func(Linklist &L)。定义p并使其指向头节点的下一个的下一个,p 指向链表中第三个节点。使后面的断链即,指向NULL。从p开始使用while循环遍历,定义一个pre指向L从头开始遍历,知道插入位置,使用尾插法插入,并更新p的位置,一直找到其对于的位置。

代码实现

#include<stdio.h>
int main(){
   
//    61.假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,可共享相同的后缀存储空间,例如,loading 和 being 的存储映像如下图所示,设 strl 和 str2 分别指向两个单词所在单链表的头结点,链表结点结构为 data next。请设计个时间上尽可能高效的算法,找出由 st1 和 str2 所指向两个链表共同后缀的起始位置(如图中字符i所在结点的位置 P)。
Lnode* func(Linklist str1,Linklist L2){
   
    int m=0,n=0;
    Lnode* p=str1->next,q=str2->next;
    while(p){
   
        m++;
        p=p->next;
    }
    while(q){
   
        n++;
        q=q->next;
    }
    p=str1;
    q=str2;
    while(m>n){
   
        p=p->next;
        m--;
    }
    while(m<n){
   
        q=q->next;
        n--;
    }
    while(p){
   
        if(p==q){
   
            return p;
        }
        p=p->next;
        q=q->next;
    }
    retrun p;
}

//62.用单链表保存m 个整数,结点的结构为[data][link],且|data|<n(n 为正整数)。现要求设计一个时间复杂度尽可能高效的算法,对于链表中 data 的绝对值相等的结点,仅保留第欠出现的结点而删除其余绝对值相等的结点。例如,若给定的单链表 head 如下
void func(Linklist &L,int n){
   
    int *q;
    q = malloc(sizeof(int) * (n + 1));
    for(int i=0;i<n;n++){
   
        *(q+i)=0;
    }
    Lnode* p=L,*r;
    while(p->next !=NULL){
   
        m=p->next->data > 0 ?p->next->data:-p->next->data;
        if(*(q+m)==0){
   
            *(q+m)=1;
            p=p->next;
        }else{
   
            r=p->nrxt;
            p->next=r->next;
            free(r);
        }
    }
    free(q);
}

//63.设线性表L=(a1.a.a3.…,an2,an1.am)采用带头结点的单链表保存,链表中的结点定义如下typedef struct LNode{int data;struct node*next;}LNode, *LinkL ist:请设计一个空间复杂度为o(1)且时间上尽可能高效的算法,重新排列工中的各结点,得到线性表L'=(a1,an,a2,an-1,a3,an2.…)
Lnode* fun(Linklist &L){
   
    Lnode *p=L,*q=L,*r;
//    找到链表的中间节点:使用两个指针 p 和 q。p 每次移动一步,q 每次移动两步。当 q 到达链表末尾时,p 刚好位于中间节点。
    while(p->next!=NULL){
   
        p=p->next;
        q=q->next;
        if(q->next!=NULL){
    
            q=q->next; 
        }
    }
//    分割链表:q 现在指向后半部分的头节点,将 p 的 next 指向 NULL,以断开链表。 
    q=p->next;
    p->next=NULL;
//    反转后半部分链表:使用指针 r 来保存当前节点的下一个节点。
//    然后将当前节点 q 的 next 指向前半部分的头节点 p 的 next,并将 p 的 next 更新为 q。
//    继续这个过程,直到后半部分的所有节点都被反转并插入到前半部分的开头。
    while(q){
   
        r=q->next;
        q->next=p->next;
        p->next=q;
        q=r;
    }
//    使用指针 p 指向前半部分的头节点,指针 q 指向反转后的后半部分的头节点。
//    交替地将 q 的节点插入到 p 的后面,直到 q 的所有节点都被合并。
    q=p->next;
    p=L->next;
    while(q){
   
        r=q->next;
        q->next=p->next;
        p->next=q;
        p=p->next;
        q=r;
    }
}

//    64.将两个按值有序排列的非空线性链表合并为一个按值有序的线性链表
Linklist func(Linklist A,Linklist B){
   
    Linklist C;
    Lnode *p=A,*q=B,*r;
    if(p->data < q->data){
   
        C=A;
        r=A;
        p=p->next;
    }else{
   
        C=B;
        r=B;
        q=q->next;
    }
    while(p&&q){
   
        if(p->data < q->data){
   
            r->next=p;
            r=p;
            p=p->next;
        }else{
   
            r->next=q;
            r=q;
            q=q->next;
        }
    }
    r->next=(p!=NULL)?p:q;
    return C;
}

//    65.设线性表L=(X1,X2,…,Xn-2,Xn-1,Xn)中存储整型数据,采用带头结点的单链表保存。中奇数位序的数据元素按升序存放,偶数位序的数据元素按降序存放。请设计一个空间复杂度为 0(1)且时间上尽可能高效的算法,将链表中的元素按从小到大的顺序排序
Linklist func(Linklist &L){
   
    Lnode *p=L->next->next;        //p 指向链表中第三个节点
    L->next->next=NULL;        //断链  

    Lnode *pre,*q;
    while(p){
   
        q=p->next;        
        pre=L;        //从头开始 
        while(p->next->data < pre->data && p->next!=NULL){
   
            pre=pre->next;
        }        //找到插入位置 
        p->next=pre->next;
        pre->next=p;
        p=q;
    }    
}

    return 0;
}

总结

本文介绍了五个数据结构问题及其C语言实现,这些问题涵盖了链表操作的多个方面,包括查找共同后缀、删除重复节点、重新排列链表元素、合并有序链表以及对特定条件下的链表元素进行排序。这些算法不仅锻炼了我们对链表操作的理解和编程能力,也展示了数据结构在解决实际问题中的应用。

查找共同后缀的问题要求我们找出两个单词单链表的共同后缀起始位置。这个问题的解决关键在于计算两个链表的长度,并从后向前比较节点,找到共同的起始节点。

删除重复节点的问题要求我们删除链表中绝对值相同的节点,只保留第一次出现的节点。这个问题可以通过使用一个额外的数组来记录已经出现过的绝对值,从而实现高效的删除操作。

重新排列链表元素的问题要求我们将链表中的元素重新排列,使得奇数位置的元素和偶数位置的元素交替出现。这个问题的解决需要我们找到链表的中点,反转后半部分链表,然后交替合并前后两部分。

合并有序链表的问题要求我们将两个有序链表合并为一个有序链表。这个问题可以通过比较两个链表的头节点,将较小的节点依次加入新链表,直到两个链表都遍历完毕。

对特定条件下的链表元素进行排序的问题要求我们将奇数位序的元素按升序存放,偶数位序的元素按降序存放的链表重新排序。这个问题的解决需要我们重新调整链表节点的连接顺序,使得所有元素按从小到大的顺序排列。

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

总的来说,这些算法问题不仅锻炼了编程能力,也加深了对数据结构和算法的理解。通过这些问题的解决,我们可以逐步提高自己的编程技能,为将来的学习和工作做好准备。这些算法的掌握对于计算机专业的学生和软件开发人员来说都是非常重要的。通过这些练习,我们可以逐步提高自己的编程技能,为将来的学习和工作做好准备。

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