嵌入式学习第三周(排序 和 递归函数)

一、排序

(1)冒泡排序

基本思想:

冒泡排序(Bubble Sort)是最基础的排序算法之一,它的核心思想是:多次遍历要排序的序列,在遍历的过程中,当发现两个相邻的元素逆序,就交换这两个元素的位置,直到某次遍历不需要交换元素为止。此时整个序列都不存在两个元素逆序的情况,即满足了顺序要求

   从上图我们不难看出冒泡排序应该有两个循环:

  • 第一个循环是小循环,该循环的作用是——在某个数组内依次进行两个数的大小比较;
  • 第二个循环是大循环,该循环的作用是——决定小循环的次数

那么概括来说就是,在一定次数内,数组按照一定的大小顺序进行两两比较,满足顺序的移动 

 基本代码:

#include<stdio.h>

void My_Select(int *arr,int len)
{
	int i,j,temp,flag=0;
	for(i=0;i<len-1;i++)//大循环
	{
		for(j=0;j<len-i-1;j++)  //小循环
		{
			if(arr[j]>arr[j+1]) //判断条件 
			{
				flag=1;
				temp=arr[j];  //交换数值
				arr[j]=arr[j+1];
				arr[j+1]=temp;
			}
		}
		if(flag==0)  //标志位判断
		{
			break;
		}
		else
			flag=0;
	}
	
}


int main()
{
	int i,size;
	int arr[]={52, 52, 32, 71, 92, 32, 46, 72, 12, 34, 77, 22, 56, 22};
	size=sizeof(arr)/sizeof(int); //求数组的长度
	My_Select(arr,size);  //调用冒泡函数 
	for(i=0;i<size;i++)
		printf("%d ",arr[i]);
	return 0;
 } 
 
 

优化过的冒泡排序,相对原本的冒泡排序,减少了重复比较的次数,如果已经比较过的相同的元素,就会跳出循环。用标志位flage判定    时间复杂度在O(n^2)

 (2)选择排序

  选择排序是一种简单直观的排序算法,它的工作原理是每一次从待排序的数据元素中选出最小(最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法。

1.简单的选择排序

基本思想:每一趟从待排序的数据元素中选择最小(或最大)的一个元素作为首元素,直到所有元素排完为止。

算法实现:每一趟通过不断地比较交换来使得首元素为当前最小,交换是一个比较耗时间的操作,我们可以通过设置一个值来记录较小元素的下标,循环结束后存储的就是当前最小元素的下标,这时再进行交换就可以了。

#include<stdio.h>

void Sum_a(int *a,int *b)  //交换数值
{
	int temp;
	temp=*a;
	*a=*b;
	*b=temp; 
}

void My_SelectSort(int *arr,int len)
{
	int i,j,min,temp;
	for(i=0;i<len-1;i++) //查找最小值 
	{
		min=i;
		for(j=i+1;j<len;j++) 
		{
			if(arr[j]<arr[min])
			{
				min=j;
			}
		}
			Sum_a(&arr[i],&arr[min]);
	}
}

//优化后的选择排序 
//交换两个数据
void Swap(int* a, int* b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

//优化  可从两边同时将最大值和最小值取出来
void SelectSort(int* arr, int size)
{
	int begin = 0;
    int end = size - 1;
    while (begin < end)
    {
        int max = begin;
        int min = begin;
        int i = 0;
        for (i = begin+1; i <= end; i++)
        {
            if (arr[i] < arr[min])
            {
                min = i;
            }
            
            if (arr[i] > arr[max])
            {
                max = i;
            }
        }
        
        Swap(&arr[begin], &arr[min]);
        if (begin == max)				//修正max
        {
            max = min;
        }
        Swap(&arr[end], &arr[max]);
        
        begin++;
        end--;
    }
}



int main()
{
	int i,size;
	int arr[]={52, 52, 32, 71, 92, 32, 46, 72, 12, 34, 77, 22, 56, 22};
	size=sizeof(arr)/sizeof(int);
	SelectSort(arr,size);
	for(i=0;i<size;i++)
		printf("%d ",arr[i]);
	return 0;
 } 
 
 

【排序算法】选择排序(C语言)_手眼通天王水水的博客-CSDN博客 可以看下这个博主的优化算法

(3) 插入排序

插入排序的原理:

一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增 1 的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动 。

选择排序的基本思想是:

将未排序的元素一个一个地插入到有序的集合中,插入时把所有有序集合从后向前扫一遍,找到合适的位置插入。

 代码:


void insertion_sort(int *arr, int len)
{
    int i, j, temp;
    for (i = 1; i < len; i++)
    {
        temp = arr[i];
        for (j = i; j > 0 && arr[j - 1] > temp; j--) // j=1 j=0
            arr[j] = arr[j - 1];
        arr[j] = temp; // j=0 arr[0]
        int k = 0;
    }
    
}

总结:

  1. 还有很多算法的结构,目前掌握这三种就基本够用了
  2. 希尔算法,快速排序等
  3. 二分查找法  可以看下这个博主的
  4. 二分查找【详解】_二分查找法_圣喵的博客-CSDN博客

二、递归函数

什么是递归?

递归(recursion):程序调用自身的一种编程技巧。

😀如何理解函数递归

1.从调用自身层面:函数递归就是函数自己调用自己。

2.从编程技巧层面:一种方法(把一个大型复杂的程序转换为一个类似的小型简单的程序),这种方法的主要思想就是把大事化小。

递归的两个必要条件

1.存在限制条件,当满足这个限制条件时,递归便不再继续。

2.每次递归调用之后越来越接近这个限制条件。

 递归实例-------

实例1(按照顺序打印一个数的整形值)

#include <stdio.h>

void print(int n)
{
    if(n>9)
    {
        print(n/10);
    }
    printf("%d ",n%10);
}
int main()
{
    int num = 1234;
    print(num);
    return 0;
}

不停地调用,,进入底层,再将值带出来  打印结果为 1 2 3 4

 图解:

实例2: 使用函数在不创建变量的情况下求字符串长度

#include <stdio.h>
int Strlen(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + Strlen(str + 1);
}
int main()
{
	char* p = "abcd";
	int len = Strlen(p);
	printf("%d\n", len);
	return 0;
}

-----递归与迭代

迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。 每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。 目前对于c语言来说,迭代可以简单认为是循环结构。

 实例1 (求n的阶乘)

方法一(使用递归)

#include <stdio.h>
int fac(int n)
{
	if (n == 1)
		return 1;
	else
		return n * fac(n - 1);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fac(n);
	printf("%d\n", ret);
	return 0;
}

方法二(使用迭代)

#include <stdio.h>
int main()
{
	int n = 0;
	scanf("%d", &n);
	int i = 0;
	int ret = 1;
	for (i = 1; i <= n; i++)
	{
		ret *= i;
	}
	printf("%d\n", ret);
	return 0;
}

实例2 (求解斐波那契数列

斐波那契数列:指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)

#include <stdio.h>
int fib(int n)
{
	if (n <= 2)
		return 1;
	else
		return fib(n - 1) + fib(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fib(n);
	printf("%d\n", ret);
	return 0;
}

 运行结果:

 注意:当求得的数字较大时,使用递归的方法计算机所要计算的量是相当大的,因为每次计算一个第n项时都需要计算第n-1项和第n-2项 ,这里我们通过求解第40项来观察fib(3)的计算次数来观察。

计算第40项时已经计算第3项已经有三千多万次,那么如果计算第一百项,一千项...时程序就会崩溃...这是我们就要考虑使用迭代的方法进行求解。 

方法二(迭代求解)

#include <stdio.h>
int fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (n > 2)
	{
		c = a + b;
		a = b;
		b = c;
		n--;
	}
	return c;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fib(n);
	printf("%d\n", ret);
	return 0;
}

 运行结果:

 这里我们可以看出递归和迭代的运行结果是一样的,但是迭代的运行速度要更快。 

🔴 注意:

1.许多问题是以递归的形式进行求解的,这只是因为它比非递归的形式更加清晰。

2.但是这些问题的迭代实现往往比递归实现效率更高,虽然可读性差些。

3.当一个问题相当复杂时,此时递归实现的简洁性便可以弥补它所带来的运行开销。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值