【趣学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;
}