简单选择排序:交换很少,为什么还是O(n²)?

数据结构—排序(Part Ⅱ)—交换排序&选择排序 数据结构-排序(第十章)的整理笔记,若有错误,欢迎指正。 交换排序 所谓交换,是指根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置。基于交换的排序算法很多,这里主要介绍冒泡排序和快速排序。 冒泡排序(bubble sort) 冒泡排序的基本思想是:从后往前(或从前往后)两两比较相邻元素的值,若为逆序(即A[i-1]>A[i]),则交换它们,直到序列比较完。我们称它为第一趟冒泡,结果是将最小的元素交换到待排序列的第一个位置(或将最大的元素交换到待排序列的最后一个位置),关键字最小的 阅读详情

简单选择排序:交换很少,为什么还是O(n²)?

直接插入排序拿到一个数,会问:它应该插在哪里?简单选择排序换了一个问题:这个位置应该放哪个数?

这个区别不只是名字。5个元素已经有序时,本文的选择排序仍比较10次,插入只比较4次;完全逆序时,选择只交换2次,插入却要右移10次。

为什么搬得少,时间复杂度还是平方级?我们从原始数组推导,再用程序核对。本文讨论的是每轮选择最小值、最后至多交换一次的经典实现,不把它的结论套到所有选择排序变体。

1. 先确定位置,再去挑数

从乱序数组开始:

[5, 2, 4, 1, 3]

第一个位置应该放整个数组的最小值。先扫描,记住最小值在哪里,扫描过程中不搬元素:

暂定最小:5,下标0
遇到2:改为2,下标1
遇到4:不变
遇到1:改为1,下标3
遇到3:不变

最后才把下标0与3的元素交换:

[1 | 2, 4, 5, 3]

为什么可以不再管1?因为没有剩余元素比它小,它已经处在一个正确的最终位置。后面的轮次只扫描竖线右边。

从[2,4,5,3]选2:已在当前位置,不交换
[1, 2 | 4, 5, 3]

从[4,5,3]选3:与4交换
[1, 2, 3 | 5, 4]

从[5,4]选4:与5交换
[1, 2, 3, 4 | 5]

只剩一个元素时,不用继续挑。这就是“选择”:每轮确定一个位置,选出应该放在那里的元素。

2. 左边都有序,为什么不是同一种思想?

直接插入也维护有序的左边,但有序的含义不同:

插入:[2, 5 | 4, 1, 3]
      2和5只是已处理部分有序,后来遇到1,还得搬。

选择:[1, 2 | 4, 5, 3]
      1和2已经是全数组最小的两个数,后面不会再动它们。

插入是给数找位置;选择是给位置找数。 有序前缀相似,建立它的方式、知道的信息、下一轮的任务却不同。

3. 把“先选后放”翻译成C

void selection_sort(int a[], int n)
{
    for (int i = 0; i < n - 1; i++) {
        int min_index = i;
        for (int j = i + 1; j < n; j++) {
            if (a[j] < a[min_index]) min_index = j;
        }
        if (min_index != i) {
            int temp = a[i];
            a[i] = a[min_index];
            a[min_index] = temp;
        }
    }
}

外层i是这轮要填的位置;min_index暂存最小值的下标。内层只更新下标,不一发现较小值就交换。扫描结束后才交换。

如果最小值已经在i,跳过自交换;这会减少写入,却不会减少内层比较。本实现要求n非负,n大于0时a指向至少n个可写元素;长度0或1不进入循环。不要直接改成无符号n后仍照抄 n-1,空数组时减法会下溢。

比较使用 < 而不是相减,避免把INT_MIN与INT_MAX相减造成有符号溢出。求元素个数、容量与大数组计数时,也要注意类型范围;下面验证器的计数使用uint64_t。

4. 少搬了,但比较并没消失

插入排序会为一个数腾位置,可能连续右移一串元素。选择排序先挑最小值,最后交换两个位置,不需要逐个腾位置。

但“我已经找到最小值”必须有依据。扫描 [5,2,4,1,3] 时,遇到2也不能停:后面可能有1。没有额外信息,所有剩余候选都要看。

轮次未排序元素数元素比较数
第1轮nn-1
第2轮n-1n-2
最后一轮21

每轮先把当前位置作为候选,剩余每个元素比较一次,因此总比较数是:

(n-1) + (n-2) + ... + 1 = n(n-1)/2

最后至多交换一次,每轮一个,合计至多n-1次交换;并非一定交换n-1次。逆序5元素时,中间的3本来就在最终位置,实际只交换两次。

所以不能只看交换很少,就说时间O(n)。计算总时间,要把内层寻找最小值的成本也算进去。

5. 为什么已经有序也要扫描?

看到 [1,2,3,4,5],人知道它已经有序,但程序不能凭感觉知道。第一轮仍要确认没有元素比1小,第二轮确认剩余没有元素比2小。

这个经典实现的比较次数不依赖初始排列,最好、平均、最坏时间都是Θ(n²),额外空间O(1)。数据只影响交换次数,不能让固定的扫描消失。

直接插入却能利用已有的有序前缀:新元素不小于前缀最大值时,只比较一次就能停。最好Θ(n),最坏Θ(n²);在互异元素的各个排列等概率出现的模型下,平均Θ(n²)。但乱序不等于每次都最坏,实际右移数由逆序对数决定。

这不是说“任何选择类算法都不能检测有序”。额外加有序检测会改变实现与最好情况,这篇不偷偷加上它,再拿新结果冒充原来的算法。

6. 严格小于,为什么还是不稳定?

前一篇插入排序用严格大于,避免新元素越过前面相等的元素。选择用严格小于,遇到相同最小值时保留先遇到的候选,看起来也很谨慎。

但破坏稳定的地方不是挑选相等的最小值,而是最终交换:

下标: 0    1    2
原值:[2甲, 2乙, 1]
                 最小
交换下标0、2
结果:[1, 2乙, 2甲]

2甲被换到末尾,越过了2乙。第二轮两个2相等,不再交换,也无法恢复顺序。所以严格比较并不是所有排序都稳定的通用条件,要看整个移动过程。

选择最小值1后交换下标0与2,2甲越过2乙,导致相等元素顺序反转

想让这条思路稳定,可以取出最小元素,把它前面的未排序元素整体右移,再填到当前位置。其他记录的顺序就保住了;但这又增加了搬移,已经不是本文的少交换实现。

7. 验证器不只检查最终有序

整数版排序与带身份版本都参与验证。记录类型为 {key,id},只比较key,id记录原始下标。搬移或交换整个记录,才能检查是否丢失、重复、身份与数值错配。

验证器检查三件不同的事:

  • 输出数值是否与独立qsort参考一致。参考比较器用关系判断,不用整数相减。
  • 元素是否完整保留。不能只检查有序,否则 [1,1,1] 也可能蒙混过关。
  • 比较数是否恰好n(n-1)/2,实际交换是否不超过n-1。插入对照还必须保持相等记录的原顺序。

qsort只作为数值序列的参考,不拿它判断稳定性;它自己的稳定性没有作为前提。也不把id加进排序键,否则会遮住我们想观察的不稳定。

统一计数口径:comparisons只数元素大小比较;swaps只数不同下标之间的交换;shifts是插入的右移次数;array_writes数源码中对数组槽位的赋值。一交换有两次数组写入,另有一次暂存变量赋值,后者不算数组写入。

数组写入计数是算法层面的口径,不等于CPU实际存储指令、缓存行为或物理设备写入量。本轮没有计时,不能把这些次数直接换成“快了几倍”。

测试覆盖长度0至7、值域{-1,0,1}的全部3280个数组;固定种子1000组随机输入,部分包含INT_MIN、INT_MAX;以及5个定向样例。

失败对照包括:严格 < 的选择确实把 [2甲,2乙,1] 排成 [1,2乙,2甲];故意让内层从i+2开始,跳过相邻候选,必须在 [2,1] 上被拒绝。已知故障能被抓住,才有理由相信检查不是摆设;有限测试仍不等于一般正确性证明。

本轮Windows x64、MinGW GCC 13.1.0、C11、-Wall -Wextra -Werror -O2实测,断言开启,4285个输入通过。没有sanitizer或CPU耗时测量。

输入实现比较交换右移数组写入
sorted5selection10000
sorted5insertion4004
reversed5selection10204
reversed5insertion1001014
equal5selection10000
equal5insertion4004
example5selection10306
example5insertion90711
unstable3selection3102
unstable3insertion3024

sorted5为[1,2,3,4,5],reversed5为[5,4,3,2,1],equal5为五个2,example5为本文的[5,2,4,1,3],unstable3为[2甲,2乙,1]的数值部分。id在验证器内部保留。

有序和全相等输入中,选择比较始终是10次,却没有数组写入。逆序输入中选择两次交换、四次数组写入;插入十次右移,加四次最终填入,共十四次数组写入。比较计数固定,与交换数随输入变化,可以同时成立。

负例也得到预期结果:

strict <: still unstable; result=1,2B,2A
mutation j=i+2: rejected on [2,1]
PASS cases=4285; selection, insertion, plain_selection checked

8. 从这里继续优化,该问什么?

现在的主要成本已经清楚:反复找最小值。每轮删掉一个最小元素,却把之前的比较关系全忘了,下一轮从头再挑。

下一步可以问:能不能保存一些比较结果,拿走最小值后只修复受到影响的部分? 这会引向堆或胜者树等结构,属于新的算法设计,不是把循环下标改一下就消除了平方级扫描。

如果数据已经大致有序,直接插入可能更合适;如果比较相对便宜、移动记录相对昂贵,选择的少交换特点值得考虑,但要结合记录大小、比较成本和真实计时,而不是只凭复杂度表选实现。这里是在解释成本取舍,不建议用教学实现替代成熟排序库。

两篇文章的分工也由此明确:前一篇讲找位置与跨步整理;这一篇讲先选后放,并追问为什么少交换仍不能代表低时间成本。

附录:完整程序与复现方法

下面程序保存为verify.c即可编译,包含前面的整数排序、带身份的选择与插入、用例生成器、计数断言和失败对照。容量256只是本验证程序的限制。不要加 -DNDEBUG,否则assert检查会被关闭。

gcc -std=c11 -Wall -Wextra -Werror -O2 verify.c -o verify
./verify
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void selection_sort(int a[], int n)
{
    for (int i = 0; i < n - 1; i++) {
        int min_index = i;
        for (int j = i + 1; j < n; j++) {
            if (a[j] < a[min_index]) min_index = j;
        }
        if (min_index != i) {
            int temp = a[i];
            a[i] = a[min_index];
            a[min_index] = temp;
        }
    }
}

typedef struct { int key; int id; } Item;
typedef struct { uint64_t comparisons, swaps, shifts, writes; } Stats;
enum { CAP = 256 };
static unsigned cases;
static uint32_t random_state = 20261005u;

static void select_items(Item a[], int n, Stats *s)
{
    for (int i = 0; i < n - 1; i++) {
        int min_index = i;
        for (int j = i + 1; j < n; j++) {
            s->comparisons++;
            if (a[j].key < a[min_index].key) min_index = j;
        }
        if (min_index != i) {
            Item temp = a[i];
            a[i] = a[min_index];
            a[min_index] = temp;
            s->swaps++;
            s->writes += 2;
        }
    }
}

static void insert_items(Item a[], int n, Stats *s)
{
    for (int i = 1; i < n; i++) {
        Item temp = a[i];
        int j = i - 1;
        while (j >= 0) {
            s->comparisons++;
            if (!(a[j].key > temp.key)) break;
            a[j + 1] = a[j];
            s->shifts++;
            s->writes++;
            j--;
        }
        a[j + 1] = temp;
        s->writes++;
    }
}

static int compare_int(const void *p, const void *q)
{
    int a = *(const int *)p, b = *(const int *)q;
    return (a > b) - (a < b);
}

static int stable(const Item a[], int n)
{
    for (int i = 1; i < n; i++)
        if (a[i - 1].key == a[i].key && a[i - 1].id > a[i].id) return 0;
    return 1;
}

static uint32_t next_random(void)
{
    random_state ^= random_state << 13;
    random_state ^= random_state >> 17;
    random_state ^= random_state << 5;
    return random_state;
}

static void check(const int input[], int n, const char *label)
{
    assert(n >= 0 && n <= CAP);
    int expected[CAP], plain[CAP];
    memcpy(expected, input, (size_t)n * sizeof(int));
    memcpy(plain, input, (size_t)n * sizeof(int));
    qsort(expected, (size_t)n, sizeof(int), compare_int);
    selection_sort(plain, n);
    assert(memcmp(plain, expected, (size_t)n * sizeof(int)) == 0);
    for (int method = 0; method < 2; method++) {
        Item a[CAP];
        int seen[CAP] = {0};
        Stats s = {0};
        for (int i = 0; i < n; i++) a[i] = (Item){input[i], i};
        if (method == 0) select_items(a, n, &s);
        else insert_items(a, n, &s);
        for (int i = 0; i < n; i++) {
            assert(a[i].key == expected[i]);
            assert(a[i].id >= 0 && a[i].id < n);
            assert(!seen[a[i].id]++);
            assert(a[i].key == input[a[i].id]);
        }
        if (method == 0) {
            uint64_t count = n < 2 ? 0 : (uint64_t)n * (uint64_t)(n - 1) / 2;
            assert(s.comparisons == count);
            assert(s.swaps <= (uint64_t)(n > 0 ? n - 1 : 0));
            assert(s.writes == 2 * s.swaps);
        } else {
            assert(stable(a, n));
            assert(s.writes == s.shifts + (uint64_t)(n > 0 ? n - 1 : 0));
        }
        if (label) printf("%s,%s,%d,%llu,%llu,%llu,%llu\n", label,
            method == 0 ? "selection" : "insertion", n,
            (unsigned long long)s.comparisons, (unsigned long long)s.swaps,
            (unsigned long long)s.shifts, (unsigned long long)s.writes);
    }
    cases++;
}

static void negative_controls(void)
{
    Item a[] = {{2, 0}, {2, 1}, {1, 2}};
    Stats s = {0};
    select_items(a, 3, &s);
    assert(a[0].key == 1 && a[1].id == 1 && a[2].id == 0);
    assert(!stable(a, 3));
    puts("strict <: still unstable; result=1,2B,2A");
    // Deliberately skip the adjacent candidate: the two-item test must reject it.
    int bad[] = {2, 1};
    for (int i = 0; i < 1; i++) {
        int min_index = i;
        for (int j = i + 2; j < 2; j++)
            if (bad[j] < bad[min_index]) min_index = j;
        int temp = bad[i];
        bad[i] = bad[min_index];
        bad[min_index] = temp;
    }
    assert(bad[0] > bad[1]);
    puts("mutation j=i+2: rejected on [2,1]");
}

int main(void)
{
    int a[CAP] = {0};
    puts("case,method,n,comparisons,swaps,shifts,array_writes");
    for (int n = 0; n <= 7; n++) {
        int combinations = 1;
        for (int i = 0; i < n; i++) combinations *= 3;
        for (int code = 0; code < combinations; code++) {
            int rest = code;
            for (int i = 0; i < n; i++) { a[i] = rest % 3 - 1; rest /= 3; }
            check(a, n, NULL);
        }
    }
    for (int trial = 0; trial < 1000; trial++) {
        int n = (int)(next_random() % (CAP + 1));
        for (int i = 0; i < n; i++) a[i] = (int)(next_random() % 101) - 50;
        if (n > 0 && trial % 10 == 0) a[0] = INT_MIN;
        if (n > 1 && trial % 10 == 0) a[1] = INT_MAX;
        check(a, n, NULL);
    }
    const int sorted[] = {1, 2, 3, 4, 5};
    const int reversed[] = {5, 4, 3, 2, 1};
    const int equal[] = {2, 2, 2, 2, 2};
    const int example[] = {5, 2, 4, 1, 3};
    const int unstable[] = {2, 2, 1};
    check(sorted, 5, "sorted5");
    check(reversed, 5, "reversed5");
    check(equal, 5, "equal5");
    check(example, 5, "example5");
    check(unstable, 3, "unstable3");
    negative_controls();
    printf("PASS cases=%u; selection, insertion, plain_selection checked\n", cases);
    return 0;
}
排序算法(一)选择排序(简单选择排序、堆排序)思想图解及代码 今天来总结一下著名的八大排序算法中的选择排序中的两种排序,为什么从这里开始讲,不知道,随便吧,从哪里开始都行。 其实初学我也总是忘记,函数名和参数写好之后就开始发呆了,我自己的一些经验来看:对于每种排序算法我们首先得了解核心思想,然后根据这个核心思想可以进行几轮的手动排序,从中得到核心代码,再由核心代码再完整的写出来整个排序算法。当然了,大佬完全可以在脑子里面进行动态的转换的…我就不行了。 所以我会主要记录一下前两步,也方便自己后面的复习。 1.简单选择排序: 再写代码之前再说几句:无论是我还是正在读文 阅读详情

相关推荐

简单选择排序、树形选择排序和堆排序算法及其C语言实现

本节介绍三种选择排序算法,分别为:简单选择排序、树形选择排序和堆排序。 简单选择排序 该算法的实现思想为:对于具有 n 个记录的无序表遍历 n-1 次,第 i 次从无序表中第 i 个记录开始,找出后序关键字中最小的记录,然后放置在第 i 的位置上。 例如对无序表{56,12,80,91,20}采用简单选择排序算法进行排序,具体过程为: 第一次遍历时,从下标为 1 的位置即 56 开始,找出关...

数据结构和算法教程(C语言版) 2807

数据结构-选择排序(简单选择排序,堆排序)

目录 1,简单选择排序 1.1,简单选择排序思想 1.2,选择排序的时间复杂度分析 1.3,简单选择排序代码实现 2,堆排序 2.1,什么是堆排序 2.2,堆排序的思想 2.3,堆排序时间复杂度分析 2.4,代码实现 1,简单选择排序 1.1,简单选择排序思想 选择排序(Selection sort)是一种简单直观的排序算法。 简单选择排序算法的比较次数和初始的序列排列顺序无关。 它的基本思想是:首先在未排序的数列中找到最小(or最大)元素,然后将其存放到数列的起始位置;接着,.

理科男同学 2420

深入解读ES8388寄存器:从录音到播放,如何用代码控制这颗音频Codec

本文深入解析ES8388音频编解码器的寄存器设置,从录音到播放的完整控制流程。详细介绍了寄存器架构、录音通道配置、播放通道优化以及直通(Bypass)模式的高级应用,帮助开发者通过代码精准控制这颗高性能音频Codec,解决实际开发中的音质问题。

weixin_30275415的博客 547

时间复杂度O(n²)之冒泡排序、选择排序法

前言 O(n²):代表数据量增大n倍时,耗时增大n的平方倍,这是比线性更高的时间复杂度。对n个数排序,需要扫描n×n次 典型算法有:冒泡排序、选择排序法 冒泡排序 冒泡排序:时间复杂度O(n²),从第一个值开始,依次轮询,相邻的两个数依次比较,如果大于(正序排序)或者小于(倒序排序)则交换位置,即每一次轮询都会把最大的一个数冒泡到最后,轮询次数为length-1,每次轮询的长度都会减1 代码实现: public class BubbleSort { public static void main(

qq_31086797的博客 2349

YOLOv5+Astra Pro Plus深度相机:手把手教你实现实时目标检测(附ROS配置技巧)

本文详细介绍了如何将YOLOv5目标检测算法与Astra Pro Plus深度相机结合,构建实时目标检测系统。内容涵盖从硬件选型、环境搭建、ROS配置到YOLOv5部署与深度信息融合的完整流程,并分享了性能优化、避障算法等实战技巧,帮助开发者在机器人视觉等场景中快速实现智能感知应用。

weixin_28292761的博客 386

CarPlay wired(USB)连接方案

CarPlay的wired(USB)的连接方案要求车载设备至少要支持USB2.0 Hi-Speed,支持USB Host Mode,该模式要求车载设备能够工作在USB device模式下,因为Apple设备在CarPlay中是作为USB Host的。而通常情况下,车载设备USB是工作在USB Host模式的,而外接的USB设备是工作在USB Device模式的,因而在这种情况下的CarPlay wired(USB)连接方案中就需要进行USB的模式切换。模式切换完成后便是Apple设备(USB HOST)的枚

Ke8323的博客 1万+

简单选择排序 C语言

简单选择排序 (Simple Selection Sort)也称作直接选择排序。 算法步骤: 1) 设待排序的记录存放在数组Data[1…n]中。第一趟从Data[1]开始,通过n-1次比较,从n个记录中选出关键字最小的记录,记为Data[k],交换Data[1]和Data[k]。 2) 第二趟从Data[2]开始,通过n- 2次比较,从n-1个记录中选出关键字最小的记录,记为Data[k],交换Data[2]和Data[k]。 3) 依次类推,第i趟从Data[i]开始,通过 n - i 次比较,从n-i

qq_43402544的博客 2252

Windows打印体系结构之Windows内置打印驱动程序

时间是一种很残酷的东西,它只会冲淡能够冲淡的,但也会洗尽铅华帮你留下该留下的。1.3.4、Windows内置打印驱动程序现在的Windows下的打印机驱动程序通常分为V4打印机驱动程序(V4 Printer Driver)、XPS打印机驱动程序(XPSDrv)、微软通用打印机驱动程序(Microsoft UniversalPrinter Driver)、微软PostScri...

weixin_34309435的博客 2253

【排序算法】——— 简单选择排序总结

文章目录

Lebron 1249

【PINN物理信息网络】基于PINN物理信息网络求解泊松方程(python)

【PINN物理信息网络】基于PINN物理信息网络求解泊松方程(python)

k8291121的博客 2811

使用 MATLAB/Simulink 构建一个电机-液压联合控制系统的仿真模型

本文详细介绍了基于Simulink的电机与液压执行机构联合控制系统建模方法。通过7个步骤,系统讲解了从创建项目、搭建PMSM电机模型、建立逆变器与矢量控制模块,到构建液压泵和执行机构模型的完整过程。重点展示了如何设置关键参数、添加测量反馈模块,并提供了实用的代码片段。教程还包含仿真运行流程、结果分析指标及进阶建议,帮助读者掌握多物理场耦合系统建模的核心技术。该方法适用于机电液一体化系统设计,为工程实践提供有效参考。

amy_mhd的博客 613

排序算法:直接插入排序,折半插入排序,冒泡排序,快速排序,简单选择排序

一、直接插入排序 基本操作是将一条记录插入到已排好序的有序表中,从而得到一个新的、记录数量增1的有序表。 算法步骤: ①设待排序的记录存放在数组r[1...n]中,r[1]是一个有序序列; ②循环n-1次,每次使用顺序查找法,查找r[i](i=2...n)在已排好序的序列r[1...i-1]中的插入位置,然后将r[i]插入表长为i-1的有序序列r[1...i-1],直到r[n]插入表长为n-1的有序序列r[1...n-1],最后得到一个表长为n的有序序列。 void insertsort(nod

xiaoyeren_ITRoad的博客 3026

10.嵌入式控制器EC实战 GPIO开发流程

文章目录1.General Control Register (GCR),通用控制寄存器,地址0x1602.GPDRA—GPDRJ端口数据寄存器组(共10组)3.Port Control n Registers (GPCRn, n = A0-I7),端口控制寄存器4.GPIO端口编程指导编程步骤端口初始化使用InitGPIOReg数据结构初始化所有端口默认工作模式读取输入引脚的值(STATE_ACin()): IT8502中各个引脚的描述见下表所示: 在嵌入式控制器EC的IT8502主控芯片中,通过芯片的

qq_30135687的博客 2282

2.2.选择排序——每轮找最小,为什么交换更少却反而不稳定?

选择排序核心思想与特点 选择排序通过逐轮扫描未排序区间找到最小值并交换到前面,每轮确定一个元素的最终位置。其特点是: 时间复杂度固定为O(n²),比较次数不受数据初始顺序影响 交换次数少(O(n)),但比较次数多 不稳定排序,交换可能破坏相等元素的相对顺序 难以优化,必须完整扫描才能确认最小值 空间复杂度O(1),属于原地排序 典型应用场景是对交换成本高、比较成本低的数据进行排序。虽然效率不高,但思路简单直观,适合教学和小规模数据排序。

blacktion 421

VS Code下载安装与使用教程

VSCode下载安装与使用教程

weixin_46713695的博客 4万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

详解简单选择排序

简单选择排序的核心在于每一次找到剩余元素中的最小值,并将其交换到当前排序区域的末尾。虽然该算法时间复杂度较高(O(n²)),但其逻辑简单、实现容易,对于数据量较小或者对性能要求不高的场景是个不错的选择。

Weiki的博客 1368

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

查找与排序-选择排序(简单选择排序、堆排序)

选择排序也是基于“比较”和“交换”两种操作来实现的排序方法。每一趟排序在待排序序列中选择关键字最小(或最大)的数据元素加入到排好序的序列前(或后),直至所有元素排完为止。

2301_79744714的博客 1677

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

归并交换基数简单选择排序

排序

世界仙境与冷酷尽头's Blog 701

选择排序到堆排序:从O(n²)到O(n log n)的进阶之路

排序算法是数据结构与算法学习中最基础也最核心的内容之一。从最简单的选择排序出发,每一轮通过线性扫描选出最小值,复杂度为O(n²),虽然实现直观,但性能受限于反复的全量比较。堆排序则借助堆这种完全二叉树结构,将查找极值的操作从O(n)优化到O(log n),整体复杂度跃升至O(n log n)。理解这一演进,不仅能深入掌握两种排序算法的原理、C语言实现与循环不变量证明,还能体会数据结构如何从根本上改变算法效率。在实际工程中,选择排序因交换次数少适合交换成本高的场景,堆排序则凭借O(1)空间与稳定最坏时间复杂度

weixin_30516429的博客 267

排序算法总结(一)——O(n)时间复杂度排序

冒泡排序 初级版冒泡排序 冒泡排序(Bubble Sort) 一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。冒泡的实现在细节上可以有很多种变化,我们将分别就3种不同的冒泡实现代码,来讲解冒泡排序的思想。这里,我们就先来看看比较容易理解的一段。 void bubble_sort0(int a[],int n) { for (int i = ...

qq_40692109的博客 891

排序(一) 简单交换排序

排序(一) 简单交换排序   by斜风细雨QQ:253786989    2012-02-01 样例代码: // 简单交换排序 int data[9] = {8, 2, 1, 4, 9, 5, 7, 3, 6}; for (int i = 0; i < 9; ++i) { for (int j = i+1; j < 9; ++j) { if

斜风细雨 2597

循环排序复杂度:O(n²)还是O(n log n)?

排序算法是计算机科学的基础,其效率直接影响工程实践。在众多排序方法中,原地排序算法凭借空间复杂度优势备受青睐。循环排序(Cycle Sort)是一种基于循环链的原地排序算法,它通过元素间的环转移将每个元素直接放入最终位置,实现了最小化写入操作的目标。与常见的O(n log n)排序不同,标准循环排序的时间复杂度为O(n²),但这并不妨碍它在特定场景下的价值——当内存写入成本极高时(如EEPROM或Flash存储优化),其O(n)的写入次数成为决定性优势。深入理解循环排序的原理与复杂度,有助于在工程实践中根据

weixin_33971977的博客 423

简单选择排序实现(Java)

简单选择排序实现 简单选择排序就是通过n-i次关键字之间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i (1 ≤ i ≤ n)个记录交换。 代码实现: public class SelectSort { //置换 public void swap(int[] elem, int i, int j) { int temp = elem[i]; elem[i] = elem...

如是说的博客 681

简单选择排序

目录一 基本思想二 例子三 时间复杂度 一 基本思想 简单选择排序就是通过 n-i-1 次关键字间的比较, 从 n-i 个记录中选出关键字最小的记录, 并和第 i 个记录交换。 二 例子 private int[] array = new int[10] {4,5,6,3,2,1,7,8,9,0}; private void SelectSort() { int min = 0; for (int i = 0; i <

醉风的博客 307

【数据结构与算法】第34篇:选择排序:简单选择排序与堆排序

选择排序的核心思想是每次选出最小(或最大)的元素放到正确位置。简单选择排序直观但效率低,而堆排序借助完全二叉树的结构,将选择过程优化到O(log n),使整体复杂度达到O(n log n)。这一篇我们学习简单选择排序,然后重点讲解堆排序——如何建堆、如何用向下调整算法维护堆,以及为什么升序要建大根堆。

2301_80672009的博客 968

【一图看懂选择排序】——选择排序和堆排序

直接选择排序:在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换 在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

如果需要沟通,可添加微信公众号找我免费答疑 529
上一篇: 跨网段把包交给网关,为什么目标IP不是网关?用隔离实验看清IP与MAC
下一篇: 1000组随机测试全过,程序却是错的:我怎样验证自己的判题器
咔_
博客等级 码龄4年 948粉丝 258原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值