c++经典排序算法

c++各种经典排序算法

从今天开始,写一下找工作所学的内容。

一、各种排序算法的时间空间复杂度、稳定性⭐⭐⭐⭐⭐

img

二、 (各种排序算法什么时候有最好情况、最坏情况(尤其是快排))

三、冒泡排序⭐⭐⭐⭐

// 冒泡排序 相邻2个元素 相互比较,直到最后 然后重新开始。
void BubbleSort(int a[], int len) {
    int tmp;
    int exchange = 1;
    for (int i = 0; (i < len - 1) && (exchange > 0); i++) {
        exchange = 0;
        for (int j = 0; j < len - 1 - i; j++) {
            if (a[j] > a[j + 1]) {
                tmp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = tmp;
                exchange = 1;
            }
        }
    }
}

最佳的时候:时间复杂度O(n) 。 元素本来有序排列

最坏的时候:时间复杂度O( n 2 n^2 n2) 。 数据元素是逆序的

一般情况:时间复杂度O( n 2 n^2 n2)。

稳定性:每次比较的时候 如果相邻的两个元素想等,不交换顺序。

空间复杂度:O(1)

四、插入排序⭐⭐⭐⭐

//插入排序
//拿出一个数和前面的数进行比较,遇到不比它大的数字,插入其中
void InsertSort(int a[],int len) {
    int tmp;
    for (int i = 0; i < len; i++) {
        tmp = a[i];
        int  k = i; // 记录插入的位置
        for (int j = i-1; (j >= 0) && (a[j] > tmp); j--) {
            a[j + 1] = a[j];
            k = j;
        }
        a[k] = tmp;
    }
}

最佳情况:时间复杂度O(n) 整个序列已经排序 第一个元素比较0次,第二个元素比较1次,第n个元素比较1次。

最坏情况:时间复杂度O( n 2 n^2 n2) 整个序列逆序

平均时间复杂度:O( n 2 n^2 n2)

稳定性:稳定

空间复杂度:O(1)

五、希尔排序⭐⭐⭐⭐

  • 首先 将大数据集分为几个小数据集,然后向每个小数据集进行插入排序。

img

​ 初始增量gap=length/2, 此例是按下标相隔距离为4分的组,也就是说把下标相差4的分到一组,比如这个例子中a[0]与a[4]是一组、a[1]与a[5]是一组…

插入排序完成后

img

  • 缩小增量为上个增量的一半: gap =4/2,继续划分分组,此时,每个分组元素个数多了,但是,数组变的部分有序了,插入排序效率同样比高。

  • 设置增量为上一个增量的一半:gap=2/2`,则整个数组被分为一组组,此时,整个数组已经接近有序了,插入排序效率高。

    //希尔排序
    //解决 最大值在第一位 需要移动n-1个位置
    void  ShellSort(int a[], int n) {
        int gap = n;
        int tmp;
        while (gap > 1) {
            gap = gap / 3 + 1;
            for (int i = gap; i < n; i += gap) {
                int k = i;
                tmp = a[i];
                for (int j = i -gap; (j >= 0) && (a[j] > tmp); j -= gap) {
                    a[j + 1] = a[j];
                    k = j;
                }
                a[k] = tmp;
            }
        }
    }
    
    • 最佳情况: T(n) = O(nlog2 n) 已排好序的情况
    • 最坏情况: T(n) = O(nlog_2 n)
    • 平均情况: T(n) =O(nlog2n)
    • 稳定性: 不稳定。虽然插入排序是稳定的,但是希尔排序在插入的时候可能是跳跃性的,所以不是稳定的,可能会破坏稳定性

六、归并排序⭐⭐⭐⭐

即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表。
把长度为n的输入序列分成两个长度为n/2的子序列;对这两个子序列分别采用归并排序;将两个排序好的子序列合并成一个最终的排序序列。

//归并排序
//即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表。
//把长度为n的输入序列分成两个长度为n/2的子序列;对这两个子序列分别采用归并排序;将两个排序好的子序列合并成一个最终的排序序列。

//首先假设2个数组是有序的,按照有序序列进行合并,组成有序序列
void merge(int a[],int low ,int mid,int high, int tmp[]) {
    int i = low;       //左子数组开始的位置
    int j = mid + 1;   //右子数组开始的位置
    int t = 0;         //临时空间指针
    //首先 判断要合并的数组的起始位置的大小,然后将数组复制到tmp数组存储。
    // 比较2个数组的每个元素 然后按照大小顺序进行排序。
    while (i <= mid && j <= high) {
	    if (a[i] < a[j]) {
		    tmp[t++] = a[i++];
	    }
	    else
		    tmp[t++] = a[j++];
    }
    //参考https://www.bilibili.com/video/BV1Pt4y197VZ?from=search&seid=6438701192248743313
    //如果右半区就一个元素,上述放好位置后,左半区的元素直接放就好
    //将左边剩余元素填充进temp中
    while (i <= mid) {
        tmp[t++] = a[i++];
    }
    //将右边子数组剩余部分填充到temp中
    while (j <= high) {
        tmp[t++] = a[j++];
    }  
    //将融合后的数据拷贝到原来的数据对应的子空间中
    t = 0;
    while (low <= high) {
        a[low++] = tmp[t++];
    }
}
void Msort(int a[], int low, int high, int tmp[]) {
    if (low < high) {
        int mid = (low + high) / 2;
        //递归划分左半区
        Msort(a,low,mid,tmp);
        //递归划分右半区
        Msort(a,mid + 1,high,tmp);
        //合并左右半区
        merge(a,low,mid,high,tmp);
    }
}

**时间复杂度:**O(NlogN)

**最好时间复杂度:**O(NlogN)

空间复杂度: O(N)

**特点:**时间复杂度于数据是否有序的状况无关。是稳定排序算法。它是高级排序算法中,唯一一个稳定的排序算法。

**应用:**要求排序稳定,空间不重要,则使用归并算法

七、选择排序⭐⭐⭐⭐

//选择排序 
//稳定性最好的排序之一,时间复杂度为O(n2) 规模越小越好,不占用额外空间  
//在未排序中找最小的,放到起始位置,然后再找最小放到第二位置
void SelectSort(int a[], int len) {
    for (int i = 0; i < len; i++) {
        int minindex = i;
        for (int j = i + 1; j < len; j++) {
            if (a[minindex] > a[j]) {    
                minindex = j;
            }
        }
        swap(a[i],a[minindex]);
    }
}

最佳的时候:时间复杂度O( n 2 n^2 n2)

最差的时候:时间复杂度O( n 2 n^2 n2)

一般情况:时间复杂度O( n 2 n^2 n2)

稳定性:不稳定

空间复杂度:O(n)

八、快速排序⭐⭐⭐⭐⭐

//快速排序
//选出一个数作为基准,使得数组左边的小于基准,右边的大于基准
//递归划分

//划分函数
int partion(int a[], int low, int high) {
    //选择第一个元素作为标准
    int index = a[low];
    //推动左右指针向中间移动,
    while (low < high) {
        //如果右边的数比标准大,不用移动,否则交换到左边
        while ((low < high) && a[high] >= index) {
            high--;
        }
        while ((low < high) && a[low] <= index) {
            low++;
        }
        swap(a[low],a[high]);
    }

}

void Qsort(int a[], int low,int high) {
    if (low < high) {
        int index = partion(a,low,high);
        //递归划分
        Qsort(a,low,index - 1);
        Qsort(a,index,high);
    }
}

**时间复杂度:**O( n l o g n nlogn nlogn)

**最好时间复杂度:O( n l o g n nlogn nlogn) ——对应——(额外)空间复杂度:**O( o g n ogn ogn)

**最坏时间复杂度:O( n 2 n^2 n2) ——对应——(额外)空间复杂度:**O(n) ——最坏情况快排退化为冒泡

**平均时间复杂度:**O( n l o g n nlogn nlogn)

**特点:**是不稳定的算法。

#九、要求掌握快排的partition函数与归并的Merge函数⭐⭐⭐

#参考:

​ https://blog.youkuaiyun.com/zhangsy_csdn/article/details/91483600

​ https://www.bilibili.com/video/BV1bz411e7vY

) ——最坏情况快排退化为冒泡

**平均时间复杂度:**O( n l o g n nlogn nlogn)

**特点:**是不稳定的算法。

九、要求掌握快排的partition函数与归并的Merge函数⭐⭐⭐

参考:

​ https://blog.youkuaiyun.com/zhangsy_csdn/article/details/91483600

​ https://www.bilibili.com/video/BV1bz411e7vY

<think>好的,我现在需要帮助用户解决关于Dify循环实现的问题。首先,我需要明确用户的具体需求。他们提到“dify 循环实现”或“dify 如何处理循环”,但Dify本身可能没有直接称为“循环”的功能,所以需要结合现有文档中的信息来推断可能的解决方案。 根据用户提供的引用内容,Dify工作流中有迭代节点[^1]。这可能类似于编程中的循环结构,用于重复执行某个任务。例如,在处理列表数据或需要多次执行同一操作时,迭代节点可以派上用场。我需要详细解释迭代节点的配置和使用步骤,确保用户能够理解如何设置循环次数或遍历数据集。 另外,用户可能对如何处理循环中的错误或性能问题感兴趣。引用[2]提到在Dify中处理PEM文件的问题,这可能涉及在循环中正确处理数据格式,避免错误积累。需要提醒用户在循环中注意错误处理和资源管理,确保每次迭代的稳定性。 引用[3]中的例子展示了如何结合FastAPI和Selenium进行实时监控并生成GIF,这可能涉及循环截取浏览器内容。虽然Dify本身可能不直接控制这类循环,但可以通过外部脚本或定时任务触发工作流,模拟循环执行。这部分需要说明如何将外部循环机制与Dify结合使用。 接下来,我需要组织回答结构。首先介绍迭代节点的基本概念和配置步骤,然后讨论循环中的数据处理和错误处理,最后补充外部触发循环的方法。同时,生成相关问题以帮助用户进一步探索,比如优化循环性能或处理复杂数据结构。 需要确保回答符合格式要求,使用正确的中文表达,行内公式用$...$,独立公式用$$...$$,但当前问题不涉及数学公式,所以可能不需要使用。同时,引用标识要自然地添加到相关段落末尾,如、[^2]、[^3]。 最后,检查是否有遗漏点,比如Dify的其他循环相关功能或用户可能遇到的常见问题,确保回答全面且易于理解。</think>在Dify中处理循环逻辑主要通过**迭代节点**实现,以下是具体实现方式和应用场景的解析: ### 一、Dify循环实现机制 Dify通过**工作流设计器**中的迭代节点处理循环需求,其核心原理类似编程中的`for循环`。迭代节点可遍历以下数据类型: - 数组列表:`["A","B","C"]` - 字典集合:`{"key1":"value1", "key2":"value2"}` - 数值范围:通过`range()`函数生成序列 配置示例: ```python # 模拟迭代节点的数据输入 input_data = { "dataset": [1,2,3,4,5], "process_logic": "item * 2" # 对每个元素执行乘以2的操作 } ``` ### 二、迭代节点的关键配置步骤 1. **数据源绑定**:将数组/字典类型变量连接到迭代节点的输入端口 2. **循环变量命名**:设定当前元素的变量名(默认为`item`) 3. **子流程设计**:在迭代节点内部构建需要重复执行的逻辑模块 4. **结果聚合**:通过`outputs`收集所有迭代结果,支持数组或对象格式 $$ \text{总耗时} = \sum_{i=1}^{n}(单次迭代时间_i) + 系统开销 $$ ### 三、循环中的特殊处理 1. **错误中断控制**: - 启用`continueOnError`参数可跳过失败迭代 - 通过`try-catch`模块包裹敏感操作 2. **并行优化**: ```python # 伪代码示例 Parallel.forEach(dataset, lambda item: process(item)) ``` 3. **结果过滤**: ```python filtered = filter(lambda x: x%2==0, processed_results) ``` ### 四、应用场景案例 1. **批量文件处理**:遍历存储桶中的文件列表进行格式转换 2. **数据清洗**:对数据库查询结果集进行逐条校验 3. **API轮询**:定时循环调用第三方接口直到满足特定条件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值