C语言数据结构之基本排序算法(一)

前言

本篇文章分析了选择排序法、冒泡排序法和插入排序法的逻辑,给出了C语言实现代码及其复杂度分析。参考自书籍 Fundamentals of Data Structures In C。本篇文章代码均已测试通过,欢迎大家批评指正🙏


引入

在正式讲解排序法之前,我们先来对已排好序的数组搭建一个最基础的排序过程:首先搜索整个数组,比较相邻元素、如果左边的值大于右边的值,则相邻元素交换,遍历上述过程直至相邻元素总保持左边小于右边,实现过程如下:

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define MAX_SIZE 101		// 初始化数组的最大长度
#define SWAP(x, y, t) ((t) = (x), (x) = (y), (y) = (t))     /*  宏定义可适用于任何数据类型,函数定义法见swap */
#define COMPARE(x, y) (((x) < (y)) ? -1 :((x) == (y)) ? 0 : 1)      /* the other way is func: compare() */

void swap(int *x, int *y);          /* change the location of two values */
int compare(int x, int y );         /* 判断两数关系 */
void sort(int [], int);             /* 交换两数位置 */

void main()
{
    int i, n, a, b, num;
    int list[MAX_SIZE];
    printf("Enter the number of numbers to generate: ");
    scanf("%d", &n);
    if(n < 1 || n > MAX_SIZE)
    {
        fprintf(stderr, "Improper value of n\n");           // write the data into the file
        exit(1);					
    }
    /* randomly generate numbers */
    for(i = 0; i < n; i++)
    {
        list[i] = rand() % 1000;
        printf("%d ", list[i]);
    }
    sort(list, n);
    printf("\n Sorted array: \n");
    for(i = 0; i < n; i++)
        printf("%d  ", list[i]);
    printf("\n");
}

/* Actually it's a selection sorting */
void sort(int list[], int n)
{
    int i, j, min, temp;
    for(i = 0; i < n-1; i++)
    {
        min = i;
        for(j = i+1; j < n; j++)
            if(list[j] < list[min])
                min = j;
        SWAP(list[i], list[min], temp);
    }
}

void swap(int *x, int *y)
{
    int temp = *x;
    *x = *y;        // *x指向存储y所指向的地址
    *y = temp;
}

/* compare x and y, return -1 for less than, 0 for equal, 1 for greater */
int compare(int x, int y)
{
    if(x < y) return -1;
    else if(x == y) return 0;
    else return 1;
}

输出为:

在这里插入图片描述


一、选择排序法

选择排序算法(selection sort algorithm)基本思想:搜索整个列表,找到最小项的位置;如果该位置不是列表的第一个位置(即索引值为0),就会交换这两位置的值。(这实际上就是我们在引入中搭建的排序算法)

在使用选择排序法将数组元素按升序排序后,我们还可以查找某个元素是否在该数组中,顺序查找是最简单的思路却不是最佳的方法,在此程序中,我们使用二分查找将复杂度从O(n)降低至O(lgn)。

💻代码实现:

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define MAX_SIZE 101
#define SWAP(x, y, t) ((t) = (x), (x) = (y), (y) = (t))     /*  宏定义可适用于任何数据类型,函数定义法见swap */
#define COMPARE(x, y) (((x) < (y)) ? -1 :((x) == (y)) ? 0 : 1)      /* the other way is func: compare() */

void swap(int *x, int *y);          /* change the location of two values */
int compare(int x, int y );         /* 判断两数关系 */
void sort(int [], int);             /* selection sort */
int binarysearch(int list[], int num, int left, int right);        /* 折半查找法基本思路 */

void main()
{
   int i, n, a, b, num;
    int list[MAX_SIZE];
    printf("Enter the number of numbers to generate: ");
    scanf("%d", &n);
    if(n < 1 || n > MAX_SIZE)
    {
        fprintf(stderr, "Improper value of n\n");           // write the data into the file
        exit(1);
    }
    /* randomly generate numbers */
    printf("The target list: /n");
    for(i = 0; i < n; i++)
    {
        list[i] = rand() % 1000;
        printf("%d ", list[i]);
    }
    sort(list, n);
    printf("\n Sorted array: \n");
    for(i = 0; i < n; i++)
        printf("%d  ", list[i]);
    printf("\n");

    printf("Type the expected value: ");
    scanf("%d", &num);

    a = binarysearch(list, num, 0, n-1);
    printf("Is 【%d】 in this random array?(【1】-> YES, 【-1】-> NO, 0 -> right in the middle)\n", num);
    printf("The answer is 【%d】\n", a);

}

/* 取已排序好的数组内0~n-1的数查找,先取该范围内中间的数进行判断,若该数小于则右边界减一,若大于则左边界加一 */
int binarysearch(int list[], int num, int left, int right)
{
    int middle;
    while(left <= right)
    {
        middle = (right + left) / 2;
        switch (COMPARE(list[middle], num))
        {
        case -1: left = middle + 1;
            break;
        case 0: return middle;
        case 1: right = middle - 1;
        }
    }
    return -1;
}

void sort(int list[], int n)
{
    int i, j, min, temp;
    for(i = 0; i < n-1; i++)
    {
        min = i;
        for(j = i+1; j < n; j++)
            if(list[j] < list[min])
                min = j;
        SWAP(list[i], list[min], temp);
    }
}

void swap(int *x, int *y)
{
    int temp = *x;
    *x = *y;        // *x指向存储y所指向的地址
    *y = temp;
}

/* compare x and y, return -1 for less than, 0 for equal, 1 for greater */
int compare(int x, int y)
{
    if(x < y) return -1;
    else if(x == y) return 0;
    else return 1;
}

👀输出如下:

在这里插入图片描述

💻折半查找的递归代码实现以及复杂度分析:

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#define MAX_SIZE 101
#define SWAP(x, y, t) ((t) = (x), (x) = (y), (y) = (t))     /*  宏定义可适用于任何数据类型,函数定义法见swap */
#define COMPARE(x, y) (((x) < (y)) ? -1 :((x) == (y)) ? 0 : 1)      /* the other way is func: compare() */

int binarysearch(int list[], int num, int left, int right);        /* 折半查找法基本思路 */
int binsearch(int list[], int num, int left, int right);          /* 递归的折半查找法 */
void sort(int [], int);             /* selection sort */
void swap(int *x, int *y);          /* change the location of two values */
int binarysearch(int list[], int num, int left, int right);         /* 折半查找法 */
int compare(int x, int y );         /* 判断两数关系 */

void main(void)
{
    int i, n, a, b, num;
    int list[MAX_SIZE];
    clock_t start, stop1, stop2;
    double duration; 

    printf("Enter the number of numbers to generate: ");
    scanf("%d", &n);
    if(n < 1 || n > MAX_SIZE)
    {
        fprintf(stderr, "Improper value of n\n");           // write the data into the file
        exit(1);
    }
    /* randomly generate numbers */
    printf("The target list: \n");
    for(i = 0; i < n; i++)
    {
        list[i] = rand() % 1000;
        printf("%d ", list[i]);
    }

    // 计时开始
    start = clock();
    // 排序
    sort(list, n);
    printf("\n Sorted array: \n");
    for(i = 0; i < n; i++)
        printf("%d  ", list[i]);
    printf("\n");
    // 查找
    printf("Type the expected value: ");
    scanf("%d", &num);

    printf("=============未使用递归==============\n");
    a = binarysearch(list, num, 0, n-1);
    // 非递归的二分查找计时结束
    stop1 = clock();
    printf("Is 【%d】 in this random array?(【>0】-> YES, 【-1】-> NO, 0 -> right in the middle)\n", num);
    if (num <= 0) {
        printf("The answer is 【%d】\n", a);
    }
    else {
        printf("YES. It's at the position【%d】\n", a);
    }

    printf("=============使用递归===============\n");
    b = binsearch(list, num, 0, n-1);
    // 递归的二分查找计时结束
    stop2 = clock();
    printf("Is 【%d】 in this random array?(【>0】-> YES, 【-1】-> NO, 0 -> right in the middle)\n", num);
    if (num <= 0) {
        printf("The answer is 【%d】\n", b);
    }
    else {
        printf("YES. It's at the position【%d】\n", b);
    }

    duration = ((double) (stop1-start)) / CLOCKS_PER_SEC;
    printf("不使用递归的折半查找消耗时间:%f\n" ,duration);
    duration = ((double) (stop2-stop1+start)) / CLOCKS_PER_SEC;
    printf("使用递归的折半查找消耗时间:%f\n" ,duration);
}

void sort(int list[], int n)
{
    int i, j, min, temp;
    for(i = 0; i < n-1; i++)
    {
        min = i;
        for(j = i+1; j < n; j++)
            if(list[j] < list[min])
                min = j;
        SWAP(list[i], list[min], temp);
    }
}

void swap(int *x, int *y)
{
    int temp = *x;
    *x = *y;        // *x指向存储y所指向的地址
    *y = temp;
}

/* compare x and y, return -1 for less than, 0 for equal, 1 for greater */
int compare(int x, int y)
{
    if(x < y) return -1;
    else if(x == y) return 0;
    else return 1;
}

/* 取已排序好的数组内0~n-1的数查找,先取该范围内中间的数进行判断,若该数小于则右边界减一,若大于则左边界加一 */
int binarysearch(int list[], int num, int left, int right)
{
    // 渐进复杂度为O(lgn)
    int middle;
    while(left <= right)
    {
        middle = (right + left) / 2;
        switch (COMPARE(list[middle], num))
        {
        case -1: left = middle + 1;
            break;
        case 0: return middle;
        case 1: right = middle - 1;
        }
    }
    return -1;
}

/* 递归的折半查找,返回调用直至逼近值然后返回,若找到则返回1,未找到则返回-1 */
int binsearch(int list[], int num, int left, int right)
{
    // 渐进复杂度为O(n^2)
    int middle;
    if(left <= right)
    {
        middle = (left + right) / 2;
        switch (COMPARE(list[middle], num))
        {
        case -1: return
            binsearch(list, num, middle+1, right);
        case 0: return middle;
        case 1: return
            binsearch(list, num, left, middle-1);
        }
    }
    return -1;
}

👀输出如下:

在这里插入图片描述


二、冒泡排序法

冒泡排序(bubble sort):从列表索引为0处开始,并比较每一对数据项,直到移动到列表的末尾。每当成堆的两项之间的顺序不正确时(左大右小),就会交换位置,整体上表现为将最大的项移动到列表末尾。

💻代码实现:

/* 冒泡排序法 */

#include<stdio.h>
 
int main()
{
   int data[5];
   printf("请输入五个数组元素:\n");
   int i,j;
   for(i = 0;i < 5;i ++)
   {
   	scanf("%d",&data[i]);	
   }
   
   for(i = 0;i < 5;i ++)  
   {
   	for(j = 0;j < 5 - 1 - i;j++)
   	{
   	   if(data[j] > data[j+1])     // 这里默认采用升序来排列 
		   {
		 	   int temp;       
            temp = data[j];
			   data[j] = data[j+1];
			   data[j+1] = temp;
		   }	
	   }
   }
   
   printf("排序好的数组为:\n");
   for(i = 0;i < 5;i ++)    
   {
   	 printf("%d ",data[i]);
   }
   return 0;
} 

// 冒泡排序法的渐进复杂度为O(n^2)

👀输出为:

在这里插入图片描述


三、插入排序法

插入排序(Insertion sort):在第i轮通过列表时,第i个项应该插入到列表的前i个项之中的正确排序位置。

💻代码实现:

/* 插入排序法 */


#include<stdio.h>
 
// 打印结果的函数 
void print(int data[],int n)
{
	int i;
	for(i=0;i<n;i++)
	{
		printf("%d ",data[i]);
	}
	printf("\n"); 
}

// 选择排序
void insertSort( int data[] ,int n )   
{
    int i,j;
    int t;
    for(i=1;i<n;i++)
    {
        t = data[i];
        j = i -1;
        while(j>=0 && data[j]>t)
        {
            data[j+1]=data[j];
            j--;
        }
        data[j+1] = t;
        print(data,n);         //显示排序的过程 
    }
}
 
int main()
{
	// 原数组
	int data[8]={5, 0, 2, 1, 3, 6, 7, 8};
	// 应用插入排序法后的数组
	insertSort(data ,8);
	return 0;
} 

// 插入排序法的复杂度为O(n^2)

👀输出为:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Larissa857

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值