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

简介: 本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。

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

问题描述

86.直接插入排序算法

87.折半插入排序算法

88.冒泡排序算法

89.快速排序算法

90.简单选择排序算法

代码分析

==86.直接插入排序算法 o(n*n)==
基本思想:将一个记录插入到前面已经排好序的子序列中,从而得到一个新的有序子序列。 这个过程重复进行,直到所有记录都被插入。

分析:
1.使用哨兵,即舍弃a[0],从第二个元素开始(i=2),检查当前元素是否小于前一个元素。如果是,则将当前元素存储在a[0]中(作为哨兵)。然后,使用一个内循环(for(j=i-1; a[j]>a[0]; j--))将比a[0]大的元素向后移动,为插入当前元素腾出位置。最后,将a[0]的值放入正确的位置。

2.不用哨兵,对应一个temp作为存储值

==87.折半插入排序算法==
基本思想:折半插入排序算法与直接插入排序类似,区别在于它使用二分查找来确定插入位置。

分析:
从第三个元素开始,依次将每个元素插入到已排序的部分。使用二分查找找到合适的插入位置。将已排序部分的元素向右移动以腾出空间。将当前元素插入到正确的位置。

==88.冒泡排序算法==
基本思想:重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

分析:
在本次代码中加入,如果某一轮没有发生交换,则提前结束排序。

==89.快速排序算法 分治法 有序o(nn) 无序和平均o(nlog 2 n)==
基本思想:
1.选择基准 (Pivot): 从数组中选择一个元素作为基准。 这段代码选择第一个元素 a[low] 作为基准。
2.划分 (Partition): 将数组划分成两个子数组:一个子数组包含所有小于基准的元素,另一个子数组包含所有大于等于基准的元素。 基准元素位于两个子数组之间。 partition 函数完成这个划分过程。
3.递归排序: 递归地对两个子数组进行排序。 func 函数完成这个递归过程。

分析
partition 函数: 这个函数实现数组的划分。它使用两个指针 low 和 high,分别从数组的两端向中间移动。 high 指针寻找小于基准的元素,low 指针寻找大于等于基准的元素。 找到后,交换两个指针指向的元素。 这个过程重复进行,直到 low 和 high 指针相遇。 最后,将基准元素放置在 low 指针的位置。
func 函数: 这个函数是快速排序算法的主函数。它接收数组和排序范围 low 和 high 作为输入。 如果 low < high,则表示排序范围有效,算法进行以下步骤:调用 partition 函数进行划分,得到基准元素的位置 p。递归地对左子数组 a[low...p-1] 和右子数组 a[p+1...high] 进行排序。

==90.简单选择排序算法==
基本思想:
在未排序的数组中找到最小(或最大)的元素,将其与未排序部分的第一个元素交换位置。 重复这个过程,直到整个数组有序。

分析
1.外循环 for(int i=0; i<n-1; i++): 控制排序的轮数。 每一轮都会找到未排序部分的最小元素。
2.最小值索引 min = i: min 变量存储当前轮次中最小元素的索引,初始值为 i(未排序部分的第一个元素)。
3.内循环 for(int j=i+1; j<n; j++): 遍历未排序部分的数组,寻找最小元素。 如果找到更小的元素,则更新 min 的值。
4.交换元素: 如果 min 不等于 i,则说明找到了比 a[i] 更小的元素,需要交换 a[i] 和 a[min] 的值。

代码实现

#include<stdio.h>
int main(){
   
//    86.直接插入排序算法  o(n*n)
//哨兵,舍弃a[0]
//从第二个元素开始(i=2),检查当前元素是否小于前一个元素。
//如果是,则将当前元素存储在a[0]中(作为哨兵)。
//然后,使用一个内循环(for(j=i-1; a[j]>a[0]; j--))将比a[0]大的元素向后移动,为插入当前元素腾出位置。
//最后,将a[0]的值放入正确的位置。
void func(int a[],int n){
    
    for(int i=2;i<=n;i++){
   
        if(a[i]<a[i-1]){
   
            a[0]=a[i];
            int j;
            for(j=i-1;a[j]>a[0];j--){
   
                a[j+1]=a[j];    
            }
            a[j+1]=a[0];
        }    
    }    
}  
//不用哨兵
void func(int a[],int n){
    
    for(int i=1;i<=n;i++){
   
        if(a[i]<a[i-1]){
   
            int temp=a[i];
            int j;
            for(j=i-1;a[j]>a[0] && j>=0;j--){
   
                a[j+1]=a[j];    
            }
            a[j+1]=temp;
        }    
    }    
}  

//    87.折半插入排序算法
//从第三个元素开始,依次将每个元素插入到已排序的部分。
//使用二分查找找到合适的插入位置。
//将已排序部分的元素向右移动以腾出空间。
//将当前元素插入到正确的位置。
void Iusort(int a[],int n){
   
    int low,high,mid,i;
    for(i=2;i<=n;i++){
   
        a[0]=a[i];
        low=1;
        high=i-1;
        while(low<=high){
   
            mid=(low+high)/2;
            if(a[mid]>a[0]){
   
                high=mid-1;
            }else{
   
                low=mid+1;
            }
        }    
        for(int j=i-1;j>=low;j--){
   
            a[j+1]=a[j];
        }
        a[high+1]=a[0]; 
    }
}

//    88.冒泡排序算法
void func(int a[],int n){
   
    for(int i=0;i<n;i++){
   
        bool flag=false;    //flag,用于标记在当前轮次是否发生了交换。如果没有发生交换,说明数组已经有序,可以提前结束排序。
        for(int j=n-1;j>i;j--){
   
            if(a[j]<a[j-1]){
   
                int temp=a[j];
                a[j]=a[j-1];
                a[j-1]=temp;
                flag=true;
            }
        }
        if(flag==true){
   
            return;
        }    
    }
}

//    89.快速排序算法   分治法    有序o(n*n)   无序和平均o(n*log 2 n)
int partition(int a[],int low,int high){
   
    int pivot=a[low];    //基准值
    while(low<high){
   
        while(low<high){
       //防止越界 
            high--;
        }
        a[low]=a[high];
        while(low<high && a[low]<=pivot ){
       //防止越界 
            low++;
        }
        a[high]=a[low];
    }
    a[low]=pivot;
    return low;
}
void func(int a[],int low,int high){
   
    if(low<high){
   
        int p=partition(a,low,high);    //分左右 
        func(a,low,p-1);
        func(a,p+1,high);
    }    
}

//    90.简单选择排序算法   //每次选择最小 
void func(int a[],int n){
   
    for(int i=0;i<n-1;i++){
   
        int min=i;
        for(int j=i+1;j<n;j++){
   
            if(a[i]<a[min]){
   
                min=j;
            }
        }
        if(i!=min){
   
            int temp=a[i];
            a[i]=a[min];
            a[min]=temp;
        }
    }
}    


    return 0;
}

总结

本文介绍了几种常用的排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序,并通过C语言实现了这些算法。这些算法各有特点,适用于不同的场景,是计算机科学中的基础内容。

直接插入排序是一种简单直观的排序方法,它通过构建有序序列,将一个记录插入到已排序的序列中。这种方法类似于我们整理扑克牌时的操作,时间复杂度为O(n^2),在数据量较小或基本有序的情况下效率较高。

折半插入排序是直接插入排序的改进版,它使用二分查找来减少比较次数,从而提高插入排序的效率。这种方法在插入位置确定上更为高效,但移动元素的次数与直接插入排序相同。

冒泡排序以其“冒泡”至序列顶端的特性而得名,通过重复遍历待排序序列,比较并交换相邻元素,直至没有需要交换的元素为止。冒泡排序的时间复杂度为O(n^2),且可以通过提前结束循环来优化。

快速排序是一种分治法的典型应用,通过选择基准值并将数组划分为两个子数组,然后递归地对子数组进行排序。快速排序在平均情况下时间复杂度为O(nlogn),是一种非常高效的排序方法,尤其适用于大规模数据集。

简单选择排序通过不断选择未排序部分的最小元素并将其放到已排序序列的末尾来工作。这种方法的时间复杂度也是O(n^2),实现简单,但在数据量大时效率较低。

这些排序算法的实现不仅展示了算法的多样性,也体现了算法设计的基本思想,如分治、贪心和优化。通过这些算法的学习,我们可以更好地理解数据结构和算法的基本概念,提高解决实际问题的能力。

总的来说,这些排序算法各有优劣,选择哪种算法取决于具体的应用场景和数据特性。例如,对于基本有序的数据,直接插入排序可能更有效;而对于大规模的随机数据集,快速排序或归并排序可能更为合适。通过这些算法的学习,我们不仅能够提高编程技能,还能够培养解决问题的思维能力。这些算法的掌握对于计算机专业的学生和软件开发人员来说都是非常重要的。

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