冒泡和递归的理解

博客介绍了JavaScript中冒泡和递归的相关知识。事件冒泡指事件在对象上触发后,若对象无处理程序或返回true,会向父级传播。还总结了冒泡排序,同时阐述递归是计算过程中每步用到前一步或几步结果,递归函数可计算,古典递归函数定义在自然数集上。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

冒泡和递归

事件冒泡
在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。
总结一个冒泡排序:

 <script>
      let arr = [11, 21, 98, 22, 87, 19, 67, 120];
      for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr.length; j++) {
          if (arr[j] < arr[j + 1]) {
            let num = 0;
            num = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = num;
          }
        }
      }
      console.log(arr);
    </script>

递归:
一种计算过程,如果其中每一步都要用到前一步或前几步的结果,称为递归的。用递归过程定义的函数,称为递归函数,例如连加、连乘及阶乘等。凡是递归的函数,都是可计算的,即能行的 [1] 。
古典递归函数,是一种定义在自然数集合上的函数,它的未知值往往要通过有限次运算回归到已知值来求出,故称为“递归”。它是古典递归函数论的研究对象 [1] 。

用递归来求一下100内的整数相加
  <script>
        function fn(num){
            if(num == 1){
                num =1
                return num
            }
            return num+fn(num-1);
        }
        fn(100)
        console.log(fn(100))
    </script>
<think>嗯,用户让我介绍C++中的冒泡排序递归实现。首先,我得回忆一下冒泡排序的基本原理。冒泡排序是一种简单的排序算法,通过不断比较相邻元素并交换它们的位置,把较大的元素逐渐“浮”到数组的末尾。通常,我们是用循环来实现的,外层循环控制轮数,内层循环处理每一轮的比较交换。 现在用户想用递归来实现,这需要把循环结构转换成递归形式。首先,我得想清楚递归的终止条件。常规的冒泡排序每一轮都会确定一个最大元素的位置,所以递归的终止条件应该是当需要排序的数组长度为1时,或者当某一轮中没有发生任何交换时,说明数组已经有序,可以结束递归。 然后是递归的处理步骤。每一轮递归需要执行一次遍历数组,比较相邻元素并交换,这样每一轮结束后,最大的元素就会被放到正确的位置。接下来,递归调用自身来处理剩下的未排序部分,也就是数组长度减一的部分。 不过,这里有个问题。常规的冒泡排序在每一轮之后,最后的元素已经是最大的,不需要再处理。所以在递归中,每次处理完一轮后,应该缩小数组的边界,只处理前面的元素。例如,初始数组长度为n,处理一轮后,对前n-1个元素进行递归调用。 然后,我需要考虑如何将这个过程用递归函数表示。可能需要传递数组的指针或引用,以及当前需要处理的数组长度。每次递归调用时,将长度减一,直到长度为1或者没有交换发生。 另外,递归实现的效率可能不如循环,因为每次递归调用都会增加函数调用的开销。不过作为教学示例,递归版本有助于理解递归的思想。 接下来,我需要考虑代码的结构。例如,递归函数可能需要一个参数来记录当前处理的数组长度,并且在每次遍历时检查是否有交换发生。如果没有交换,提前结束递归,因为数组已经有序。 可能的实现步骤: 1. 编写一个递归函数,参数包括数组的引用当前长度。 2. 在函数内部,遍历数组的前n-1个元素,比较相邻元素并进行交换。 3. 如果有交换发生,设置一个标志位。 4. 遍历结束后,如果发生了交换,则递归调用函数处理前n-1个元素。 5. 如果没有交换,提前终止递归,因为数组已经有序。 然后,我需要验证这个思路是否正确。例如,考虑一个简单的数组,如5, 3, 8, 4, 2。第一轮处理后,最大的8会被放到最后,数组变成3,5,4,2,8。然后递归处理前4个元素,依次类推。如果某次处理中没有交换,说明剩下的部分已经有序,无需继续递归。 可能需要注意的边界情况,例如数组为空或只有一个元素时直接返回。此外,递归深度的问题,如果数组很大,可能会导致栈溢出,但作为示例代码,可以忽略这个问题。 现在,将这些思路转化为C++代码。例如: void bubbleSortRecursive(int arr[], int n) { if (n <= 1) return; // 终止条件 bool swapped = false; for (int i=0; i<n-1; i++) { if (arr[i] > arr[i+1]) { swap(arr[i], arr[i+1]); swapped = true; } } if (swapped) { bubbleSortRecursive(arr, n-1); } } 这个函数是否正确?测试一下。假设数组是5,3,8,4,2,第一次调用n=5,遍历前4个元素,进行交换。结束后最大的8在最后。然后递归调用n=4,处理前3个元素,将5交换到正确位置,依此类推。如果某次遍历没有交换,说明已经有序,结束递归。 是的,这样应该可以工作。不过,是否需要将n作为参数传递?用户在使用时可能需要调用辅助函数,比如初始调用时传入数组长度。例如,用户调用时: int arr[] = {5,3,8,4,2}; bubbleSortRecursive(arr, 5); 这样就能正确排序。 总结来说,递归实现的冒泡排序将外层循环转换为递归调用,每次处理一轮比较,并缩小处理的范围,直到无需再处理或只剩一个元素。虽然效率不如循环,但有助于理解递归的应用。</think>### C++ 冒泡排序的递归实现 #### 1. 冒泡排序原理 冒泡排序通过**相邻元素比较交换**实现排序,每一轮将最大元素“冒泡”到末尾。常规实现使用双重循环,而递归版本需将外层循环改为递归调用。 #### 2. 递归实现思路 - **终止条件**:当数组长度为 1 或某一轮无交换时结束。 - **递归步骤**: 1. 遍历数组,比较相邻元素并交换。 2. 若有交换,递归处理前 $n-1$ 个元素。 #### 3. 代码实现 ```cpp #include <iostream> using namespace std; // 递归冒泡排序函数 void bubbleSortRecursive(int arr[], int n) { if (n <= 1) return; // 终止条件:只剩一个元素时无需排序 bool swapped = false; // 标记本轮是否发生交换 for (int i = 0; i < n - 1; i++) { if (arr[i] > arr[i + 1]) { swap(arr[i], arr[i + 1]); swapped = true; } } // 若发生交换,递归处理前 n-1 个元素 if (swapped) { bubbleSortRecursive(arr, n - 1); } } // 示例调用 int main() { int arr[] = {5, 3, 8, 4, 2}; int n = sizeof(arr) / sizeof(arr[0]); bubbleSortRecursive(arr, n); cout << "排序结果:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } return 0; } ``` #### 4. 关键点分析 - **递归终止条件**:当 $n \leq 1$ 时直接返回。 - **交换标记**:`swapped` 用于优化,若某轮无交换说明数组已有序,提前终止递归。 - **时间复杂度**: - 最优情况(已有序):$O(n)$,仅一轮遍历。 - 最差情况(逆序):$O(n^2)$,递归深度为 $n$。 #### 5. 循环实现的对比 | 实现方式 | 代码结构 | 空间复杂度 | 优化难度 | |----------|----------------|------------|----------| | 循环 | 双重循环 | $O(1)$ | 简单 | | 递归 | 函数自调用 | $O(n)$ | 中等 | #### 6. 总结 递归版本的冒泡排序通过**缩小问题规模**逐步完成排序,虽然不如循环高效,但能帮助理解递归思想。实际应用中建议优先选择循环实现,递归版本更适合教学目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值