基数排序(Radix_Sort)

news2025/5/17 23:23:43

基数排序 (Radix Sort)-20230715

  1. 前言

基数排序适用于多关键字排序,与前述的比较排序不同,实现基数排序不需要对关键字进行比较和移动。简而言之,基数排序是一类借助多关键字排序的思想对单逻辑关键字实现排序的方法。

  1. 多关键字排序

先看一个具体的例子。以扑克牌的排序为例,一般扑克包含52张牌,每张牌都有两个关键字花色和面值,且定义“花色”的地位高于“面值”,在比较任意两张牌的大小时,可以先比较“花色”,若花色相同,再比较面值的大小。通常打牌的时候采用的办法是最高位优先(MSD=Most Significant Digit first),先按照不同的花色分为有序的4堆,然后分别对每一堆按照面值的大小整理有序。

也可以采用另一种办法LSD: 先按不同的“面值”分为13堆,然后将这13堆按照面值的自小到大堆垛在一起(3在2之上,4在3之上,最上面是4张A),然后将这副牌点到过来重新按照花色顺序分为4堆,最后将这4堆牌自小到大合在一起(按照花色),同样可以得到一副满足上述关系的牌。这两种整理扑克的方法便是两种多关键字的排序方法。

再看一个整数排序的具体例子。对3位正整数进行计数排序,正整数的基为[0…9],如果LSD采用最低位优先的方法,那么我们需要四次迭代就可以把整体的序列排好序,对每位上数字的排序,可以选择任何稳定的排序方法,约定成俗的方法是计数排序法(counting sort),之所以选择计数排序,是因为对于大数据序列, 基(radix)很多都重复,执行计数排序能最大限度提升效率。下图引用自《算法导论》,对7个3位整数从低位到高位进行排序,可以观察到三轮迭代后,整个数组序列呈现有序状态。

读者可以发现,最低位优先的基数排序,在迭代过程中,数组序列保持为一体,无需执行分割后合并的操作流程,实现代码简洁易懂。
在这里插入图片描述

也可以采用另一种办法MSD,从直觉上理解而言,先从最重要的位着手,似乎看上去更容易实现排序,因为数字的高位最数值大小起决定作用。仔细对MSD过程进行分析,就会发现,MSD的基数排序过程中将伴随着额外的数据堆(数组)的产生,每一次分割后,最高位上基数相同的数据归为一组,那么一组数据最多就可以分为Radix个子数组,子数组遵从相同逻辑,每个子数组也可能产生radix个子数组的子数组,分析至此,不难发现,如果采用MSD的基数排序,就需借助递归模型,递归终止条件为子数组中有且仅有一个数据元素。对上面相同的数组进行MSD的基数排序,观察子数组的产生过程和数量。

从树状图中观察,第一次递归后,产生四个子数组;其中两个子树中包含的数量大于1,继续进行递归循环,第二次递归过程中,子数组分裂为单个原子元素。

在这里插入图片描述

  1. 算法实现

基数排序LSD算法的藉由静态链表或者计数排序方法实现,而MSD算法可以由链表或者数组实现。下面分别就LSD算法和MSD算法的实现分别进行解释。

假定要对正整数进行排序,那么它的基为 [0…9],实现算法的伪代码记作:

RADIX-SORT(A, n, d)
{
	for i=1 to d 
    {
        Use a stable sort method to sort array A[1:n] on digit i
    }
}

基数排序算法非常简单直接,A[i]中元素包含d个基数,其中第1位是最低位,第 d位是最高位。约定成俗,按照counting sort的稳定排序方式对第i位进行排序。

3.1 基于计数法的LSD基数排序(radix sort)

其中counting_sort函数的作用是对第pass趟对应的位进行排序,值得一提的是,对于临时数组temp,由于累加计数的原因,它的下标起始位置位index=1,所以返回的值位temp+1,忽略掉下标index=0的位置。在radix_sort函数中,特别注意的是free函数必须整个区域释放堆,释放局部内存会导致程序无法运行,所以free(ptr-1)而非free(ptr),ptr-1对应的是temp开辟的整体内存。

值得学习的另外一个技巧是,通过附加变量保存,在后续的循环中及时释放堆内存。

/**
 * @file radix_sort.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2023-07-11
 *
 * @copyright Copyright (c) 2023
 *
 */
#ifndef RADIX_SORT_C
#define RADIX_SORT_C
#include "radix_sort.h"

int *counting_sort(int *arr, int n, int pass)
{
    int *temp;
    int *count;
    int i;
    int j;
    int div;

    temp=(int *)malloc(sizeof(int)*(n+1));
    count=(int *)malloc(sizeof(int)*K);

    memset(temp,0,sizeof(int)*(n+1));
    memset(count,0,sizeof(int)*K);

    for(div=1,i=1;i<pass;i++)
    {
        div*=10;
    }

    for(i=0;i<n;i++)
    {
        count[arr[i]/div%K]++;
    }

    for(j=1;j<K;j++)
    {
        count[j]=count[j]+count[j-1];
    }

    for(i=n-1;i>=0;i--)
    {
        temp[count[arr[i]/div%K]]=arr[i];
        count[arr[i] / div % K]--;
    }

    return (temp+1);  //temp[0] has no use in the program

}

void radix_sort(int *arr, int n, int d)
{
    int *ptr;
    int *target_ptr;
    int i;

    for(ptr=arr,i=1;i<=d;i++)
    {
        
        target_ptr=counting_sort(ptr,n,i);

        if(ptr!=arr) //arr belongs to stack in the main program, you can't release during operation
        {
            free(ptr-1); //free full memory block, it should be complete instead of part
        }

        ptr=target_ptr;
    }

    memcpy(arr,ptr,sizeof(int)*n);

    return;
}

void display_arr(int *arr, int n)
{
    int i; 
    
    for(i=0;i<n;i++)
    {
        printf("%d ",arr[i]);
    }

    printf("\n");
}

#endif

3.2 基于静态链表的LSD基数排序(《数据结构》严蔚敏,清华大学)

首先以静态链表储存n个待排记录,并令表头指针指向第一个记录,如图(a)表示;第一趟分配(distribute)对最低位数的关键字进行,改变记录的指针值,将链表中的记录分配至10个链队列中去,每个队列(链表)中的记录关键字的个位数相等,如(b)所示,其中f[i]和e[i]分别为第i个队列(链表)的头指针和尾指针;第一趟收集改变所有非空对垒(链表)的队尾记录的指针域,令其指向下一个非空队列的对头记录,重新将10个队列(链表)中记录联成一个链表,如图©所示。第二趟分配,第二趟收集及第三趟分配和第三趟收集分别对十位数和百位数进行的,其过程和个位数相同,如图(d)~(g)所示。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码实现为,

头文件radix_sort.h

/**
 * @file radix_sort.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-06-29
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef RADIX_SORT_H
#define RADIX_SORT_H
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))

//MAX size of record is 20
#define MAX_LEN 15
#define MAX_SIZE 20

#define RADIX 10
#define MAX_NUM_OF_KEY 8
#define MAX_SPACE 100

typedef char   KeysType;
typedef char* Record;
typedef int ArrType[RADIX];


typedef struct  SLCell
{
    KeysType keys[MAX_NUM_OF_KEY];
    Record   otheritems;
    int      next;
} SLCell;

typedef struct SLList
{
    SLCell     r[MAX_SPACE];
    int        keynum; //number of keys in each record
    int        recnum; //number of records in the static linked list
} SLList;

/**
 * @brief create the static linked list from the file
 * 
 * @param fp File pointer
 * @param list SLList pointer
 */
void create_list(FILE *fp, SLList *list);

/**
 * @brief It builds the linked list based on the the ith key
 * make sure the keys[i] is the same in the same static linked list
 * 
 * @param r Records collections for SLCell
 * @param i ith key
 * @param f f points to the first record in each static link list
 * @param e e points to the last record in each static link list
 */
void sort_distribute(SLCell *r,int i, ArrType f, ArrType e);

/**
 * @brief collect(string) all linked list in the sort of keys[i] list
 *
 * @param r Records collections for SLCell
 * @param i ith key
 * @param f f points to the first record in each static link list
 * @param e e points to the last record in each static link list
 */
void sort_collect(SLCell *r, int i, ArrType f, ArrType e);

/**
 * @brief Use static linked list to order the element in  the list
 * 
 * @param list Pointer to static linked list
 */
void radix_sort(SLList *list);

/**
 * @brief Find the successor of the current element
 * 
 * @param j Index of current element
 * @return int Index of successor
 */
int find_successor(int j);

/**
 * @brief Get the ordinal of the object
 * 
 * @param ch keys[i]
 * @return int Ordinal of the object
 */
int get_ord(char ch);

void display_list(SLList list);

#endif

函数实现radix_sort.c

/**
 * @file radix_sort.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-06-29
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef RADIX_SORT_C
#define RADIX_SORT_C
#include "radix_sort.h"

void create_list(FILE *fp, SLList *list)
{
    int i;
    int n;
    char str[MAX_LEN];

    n=0;

    while(fgets(str,MAX_LEN,fp)!=NULL)
    {
        n++;
    }
   
    fseek(fp,0,SEEK_SET); //move the FILE pointer to the start position

    list->recnum=n;
    list->keynum=3;

    for(i=1;i<=n;i++)
    {
        list->r[i].otheritems = (Record)malloc(sizeof(char) * MAX_LEN);
        memset(list->r[i].otheritems, 0, sizeof(char) * MAX_LEN);
        memset(list->r[i].keys, 0, MAX_NUM_OF_KEY*sizeof(char));
        fscanf(fp, "%s %s",list->r[i].keys,list->r[i].otheritems);
    }
    
    return;
    
}

void sort_distribute(SLCell *r, int i, ArrType f, ArrType e)
{
    int j;
    int p;

    for(j=0;j<RADIX;j++)
    {
        f[j]=0;
    }

    for(p=r[0].next;p;p=r[p].next)
    {
        j=get_ord(r[p].keys[i]);

        if(!f[j])
        {
            f[j]=p;
        }
        else
        {
            r[e[j]].next=p; //link the array of r[e[j]].next
        }

        e[j]=p;  
    }
}

void sort_collect(SLCell *r, int i, ArrType f, ArrType e)
{
    int t;
    int j;

    for(j=0;!f[j];j=find_successor(j));

    r[0].next=f[j];
    t=e[j];

    while(j<RADIX)
    {
        for(j=find_successor(j); j<(RADIX-1) && !f[j];j=find_successor(j));

        if(j<RADIX && f[j])
        {
            r[t].next=f[j];
            t=e[j];
        }
    }

    r[t].next=0;

    return;
}

void radix_sort(SLList *list)
{
    int i;
    ArrType f;
    ArrType e;

    for(i=0;i<list->recnum;i++)
    {
        list->r[i].next=i+1;
    }

    list->r[list->recnum].next=0;

    for(i=list->keynum-1;i>=0;i--)
    {
        sort_distribute(list->r,i,f,e);
        sort_collect(list->r,i,f,e);
    }
}

int find_successor(int j)
{
    return (j+1);
}

int get_ord(char ch)
{
    return (ch-'0');
}

void display_list(SLList list)
{
    int p;

    p=list.r[0].next;

    for (p = list.r[0].next; p; p=list.r[p].next)
    {
        printf("%s,",list.r[p].keys);
    }

    printf("\n");
}

#endif

测试函数radix_sort_main.c

/**
 * @file radix_sort_main.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-06-29
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef RADIX_SORT_MAIN_C
#define RADIX_SORT_MAIN_C
#include "radix_sort.c"

int main(void)
{
    FILE *fp;
    SLList list;

    fp = fopen("data.txt", "r");
    create_list(fp, &list);

   // printf("The data is shown before the sorting:\n");
    //display_list(list);

    radix_sort(&list);

    printf("The data is shown after the sorting:\n");
    display_list(list);

    getchar();
    fclose(fp);
    return EXIT_SUCCESS;
}


#endif

data.txt文件

278 fox
109 the
063 jump
930 out
589 box
184 it
505 looks
269 better
008 or
083 not

3.3 基于动态链表的基数排序(MSD)

最高位优先策略的基数排序会产生不同的组,而且随着排序的推进,更多的分组将被产生。由于分组的数量取决于实际排序的序列具体值,程序无法提前确定,递归算法便应运而生。本例中的待排对象是正整数,递归过程中应用链表进行层层深入递归。 定义结构体中包含固定数组,已经目前数组中包含的实际元素数量,最后定义和基数相同的链表指针数组,示意图进行解释。

在这里插入图片描述

头文件定义radix_sort.h

/**
 * @file radix_sort.h
 * @author your name (you@domain.com)
 * @brief https://www.geeksforgeeks.org/msd-most-significant-digit-radix-sort/
 * @version 0.1
 * @date 2023-07-15
 *
 * @copyright Copyright (c) 2023
 *
 */
#ifndef RADIX_SORT_H
#define RADIX_SORT_H
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define N 100
#define RADIX 10
int len=0;

typedef struct link_node
{
    int                 data[N];
    int                 size;
    struct link_node    *next[RADIX];
}link_node;

/**
 * @brief Use radix sort to sort the array
 * 
 * @param arr Target array
 * @param n Number of elements in the array
 */
void radix_sort(int *arr, int n);

/**
 * @brief Recursively sort the array by using radix sort method
 * 
 * @param root Root pointer
 * @param exp Exponent
 * @param sorted_arr Sorted array
 */
void radix_sort_msd(link_node *root,int exp, int *sorted_arr);

/**
 * @brief Create a new node object
 *
 * @return link_node* -Return the pointer to link_node
 */
link_node *create_new_node();


/**
 * @brief Find the max number from the array
 * 
 * @param arr Array
 * @param n Number of element in the array
 * @return int 
 */
int find_max(int *arr, int n);


/**
 * @brief Work out the exponent on the basis of max. number
 * 
 * @param max Max value
 * @return int -Return exponent value
 */
int calc_exp(int max);

/**
 * @brief display element of array
 * 
 * @param arr 
 * @param n 
 */
void display_arr(int *arr, int n);



#endif

函数功能实现

/**
 * @file radix_sort.c
 * @author your name (you@domain.com)
 * @brief https://www.geeksforgeeks.org/msd-most-significant-digit-radix-sort/
 * @version 0.1
 * @date 2023-07-15
 *
 * @copyright Copyright (c) 2023
 *
 */
#ifndef RADIX_SORT_C
#define RADIX_SORT_C
#include "radix_sort.h"


void radix_sort(int *arr, int n)
{
    link_node *root;
    int i;
    int exp;
    int sorted_arr[n];

    root = create_new_node();
    memcpy(root->data, arr, sizeof(int) * n);
    root->size = n;

    exp = calc_exp(find_max(arr, n));

    radix_sort_msd(root, exp, sorted_arr);

    memcpy(arr, sorted_arr, sizeof(int) * n);

    return;
}

void radix_sort_msd(link_node *root, int exp, int *sorted_arr)
{
    if(exp<=0)
    {
        return; //recursion termination condition 1
    }
    int i;
    int j;
    
    for(i=0;i<root->size;i++)
    {
        j=root->data[i]/exp %RADIX;

        if(root->next[j]==NULL)
        {
            root->next[j]=create_new_node();
        }

        root->next[j]->data[root->next[j]->size++]=root->data[i];//from the smallest
    }

    for(i=0;i<RADIX;i++)
    {
        if(root->next[i]!=NULL)
        {
            if(root->next[i]->size>1)
            {
                radix_sort_msd(root->next[i],exp/10,sorted_arr);
            }
            else //recursion termination condition 2
            {
                sorted_arr[len++]=root->next[i]->data[0];
            }
        }
    }
}

link_node *create_new_node()
{
    link_node *temp_node;

    temp_node = (link_node *)malloc(sizeof(link_node));
    memset(temp_node, 0, sizeof(link_node)); // set all bit as zero/null

    return temp_node;
}

int find_max(int *arr, int n)
{
    int i;
    int max;

    max=*(arr+0);

    for(i=1;i<n;i++)
    {
        if(max<arr[i])
        {
            max=arr[i];
        }
    }

    return max;
}

int calc_exp(int max)
{
    int exp;

    exp=1;

    while(max>RADIX)
    {
        max/=RADIX;
        exp*=10;
    }

    return exp;
}

void display_arr(int *arr, int n)
{
    int i;

    for(i=0;i<n;i++)
    {
        printf("%d ",arr[i]);
    }

    printf("\n\n");
}

#endif

测试函数

/**
 * @file radix_sort_main.c
 * @author your name (you@domain.com)
 * @brief https://www.geeksforgeeks.org/msd-most-significant-digit-radix-sort/
 * @version 0.1
 * @date 2023-07-15
 *
 * @copyright Copyright (c) 2023
 *
 */
#ifndef RADIX_SORT_MAIN_C
#define RADIX_SORT_MAIN_C
#include "radix_sort.c"

int main(void)
{
    int arr[] = {720, 457, 657, 839, 436, 329, 555};
    int n = sizeof(arr) / sizeof(int);

    printf("The number is listed before sorting:\n");
    display_arr(arr, n);

    radix_sort(arr, n);

    printf("The number is listed after sorting:\n");
    display_arr(arr, n);

    getchar();

    return EXIT_SUCCESS;
}


#endif

3.4 基于数组的基数排序(MSD)

在此不再赘述,直接上实现函数的代码

/**
 * @file radix_sort.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-07-16
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef RADIX_SORT_C
#define RADIX_SORT_C
#include "radix_sort.h"

int find_max(int *arr, int n)
{
    int i;
    int max;

    max=*(arr+0);

    for(i=1;i<n;i++)
    {
        if(max<arr[i])
        {
            max=arr[i];
        }
    }

    return max;
}

int get_exp(int max)
{
    int exp;

    exp=1;

    while(max>10)
    {
        max/=RADIX;
        exp*=RADIX;
    }

    return exp;
}

void radix_sort(int *arr, int n)
{
    int sorted_arr[n];
    int exp;

    exp=get_exp(find_max(arr,n));

    radix_sort_msd(arr,n,exp,sorted_arr);

    memcpy(arr,sorted_arr,sizeof(int)*n);

    return;
}

void radix_sort_msd(int *arr, int n, int exp, int *sorted_arr)
{
    if(exp<=0) //recursion termination #1
    {
        return;
    }
    
    int i;
    int j;
    int buckets[RADIX][n];
    int counter[RADIX];

    memset(buckets, 0, sizeof(buckets));
    memset(counter,0,sizeof(counter));

    for (i = 0; i < n; i++) // 720, 457, 657, 839, 436, 329, 555
    {
        j=(arr[i]/exp)%RADIX;
        buckets[j][counter[j]++]=arr[i];
    }

    for (i = 0; i < RADIX; i++) // 720, 457, 657, 839, 436, 329, 555
    {
        if(counter[i]!=0)
        {
            if(counter[i]>1)
            {
                radix_sort_msd(buckets+i,counter[i],exp/10,sorted_arr);
            }
            else //recursion termination condition #2
            {
                sorted_arr[len++]=buckets[i][0];
            }
        }
    }
}

void display_arr(int *arr, int n)
{
    int i;

    for(i=0;i<n;i++)
    {
        printf("%d ",arr[i]);
    }

    printf("\n");
}

#endif

4.小结

本文对基数排序常见的两种方式LSD和MSD进行分析,并通过C语言实现其功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/760274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SwiftUI 原生或利用 Vision 检测限定高度的 Text 视图能否完整显示文本的方法

功能需求 在 SwiftUI 开发中,为了节省空间我们往往会为内容很长的文本视图(Text)限定一个高度,然后让用户决定是否展开显示其完整内容。 如上图所示,为了节省空间我们对 Text 视图高度做了限制,然后根据文本长度自动显示或隐藏展开按钮,用户点击该按钮即可展开显示完整…

FL Studio21入门版编曲 2023年免费小白新手编曲工具

全能数字音乐工作站&#xff08;DAW&#xff09;编曲、剪辑、录音、混音&#xff0c;有了它就能把你的笔记本电脑变成全功能音乐工作室。 内置丰富插件&#xff0c;满足不同风格创作拥有强大的采样引擎&#xff0c;自带高品质打击乐、钢琴、弦乐、吉他等107种乐器效果。 流行…

C++-把字符串转换成整数

题目来源&#xff1a;牛客网 题目描述&#xff1a; 将一个字符串转换成一个整数&#xff0c;要求不能使用字符串转换整数的库函数。 数值为 0 或者字符串不是一个合法的数值则返回 0 数据范围&#xff1a;字符串长度满足 0≤n≤100 进阶&#xff1a;空间复杂度 O(1) O(1) &…

Mybatis执行SQL过程

文章目录 1. 相关代码2. 创建SqlSession3. 创建Mapper代理对象4.sql的执行4.1 MapperProxy.invoke()4.2 mapperMethod.execute()4.3 sqlSession.selectOne4.4 CachingExecutor.query()4.5 BaseExecutor.query方法4.6 SimpleExecutor.doQuery方法 1. 相关代码 Testpublic void …

其他形式转欧拉角形式

1. 坐标系轴方向问题 3D数学基础中约定使用左手坐标系 左手坐标系 右手坐标系 左手正方向&#xff1a;x正向右平移&#xff0c;y向上平移&#xff0c;z向前平移. 右手正方向&#xff1a;x正向左平移&#xff0…

漫谈大数据时代的个人信息安全(二)——“逢脸造戏”

大数据时代的个人信息安全系列二&#xff1a;“逢脸造戏” 1. 逢脸造戏2. 生物识别信息安全2.1 生物识别信息被大量获取2.2 生物识别信息被非法滥用 3. 各国加强对深度合成监管4. 个人信息保护小贴士 互联网就像公路&#xff0c;用户使用它&#xff0c;就会留下脚印。 每个人都…

文件IO_复制文件描述符(附Linux-5.15.10内核源码分析)

目录 1.文件描述符复制简介 2.dup函数原型 2.1 dup函数 2.2 dup函数工作原理 2.3 dup函数内核源码分析 2.4 dup函数示例代码 3.dup2函数原型 3.1 dup2函数 3.2 dup2函数工作原理 3.3 dup2函数内核源码分析 3.4 dup2函数示例代码 4.dup3函数原型 4.1 dup3函数 4.2…

rv1126人脸识别的相关操作

目录 一、代码的改写Makeflierkmedia_rockx_face_insert.cpprkmedia_rockx_face_rga_rtsp_main.cpprkmedia_rockx_face_two_rkisp_rtsp_main.cppsqlite3_operation.cpp二、在ubuntu上交叉编译三、板子上的相关操作一、代码的改写 Makeflie 修改交叉编译工具链 rkmedia_rockx_fa…

2023年NOC决赛-加码未来编程赛项决赛模拟题-Python模拟题--卷5

第一题 题目:输入一个整数n,计算其各位上数字之和,并用汉语写出每一位数字并输出。 【输入格式】一个整数 【输出格式】再一行内输出数字之和的每一位对应的汉字 【输入样例】1234 【输出样例】一零 第二题 题目:小溪使用 Excel 将任意 2 组数字中相同的数按照从小到…

终于有人把软件测试用例讲清楚了(一定要收藏)

目录 1&#xff1a;公司流程 1.1. 测试用例的4个特性 1.1. 测试用例通常包括以下几个组成元素&#xff1a; 1. 编写测试用例的基本方法 1.1.1. 概念 1.1.1. 示例 1.1练习案例: 1.1. 边界值法 1.1.1. 确定边界值的方法&#xff08;&#xff09; 1.1. 因果图法 1.1.1.…

keil5软件仿真stm32设置 和 调试技巧

keil5软件仿真stm32设置 和 调试技巧 文章目录 keil5软件仿真stm32设置 和 调试技巧前言一、设置二、调试1.串口显示 总结 前言 不想用板子的时候或没有板子的时候&#xff0c;软件仿真更方便调试快速验证&#xff1b; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面…

LeetCode 周赛上分之旅 #33 摩尔投票派上用场

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难…

【简单认识MySQL数据库存储引擎】

文章目录 一、存储引擎概念介绍二、MyISAM存储引擎1.特点详解2.适用生产环境 三、InnoDB存储引擎1.特点详解2.适用生产环境 四、数据库存储引擎操作1.查看数据库支持的存储引擎2.查看数据库存储引擎3.修改数据库表的存储引擎 五、行锁和表锁1.InnoDB使用行锁和表锁的场景2.行锁…

Flink复习笔记

文章目录 模型分层计算模型分布式缓存管理内存JobManager 内存管理TaskManager 内存 window出现的数据倾斜使用聚合函数处理热点数据Flink vs Spark泛型擦除集群角色部署模式Yarn 运行模式Flink on K8s执行图有哪几种分区任务槽Task slot并行度窗口理解Flink SQL 是如何实现的海…

springCloudAlibaba之dubbo替换openFeign

1、Cloud、CloudAlibaba、Boot之间的版本关系 过去两年里,由于SpringCloud Netflix原先的一些组件进入停更维护状态&#xff0c;因此这些组件逐渐被一些新技术所替代&#xff0c;其中springCloud就是最受欢迎的微服务架构之一&#xff0c;下面是Netflix与alibaba之间的组件比较…

【Linux系列P6】自动化构建工具-make/Makefile详解

前言 大家好吖&#xff0c;欢迎来到 YY 滴 Linux系列 &#xff0c;热烈欢迎&#xff01;本章主要内容面向接触过Linux的老铁&#xff0c;主要内容含 欢迎订阅 YY 滴Linux专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 订阅专栏阅读&#xff1a;YY的《…

(数字图像处理MATLAB+Python)第十章图像分割-第一、二节:阈值分割和边界分割

文章目录 一&#xff1a;图像分割概述二&#xff1a;阈值分割&#xff08;1&#xff09;概述&#xff08;2&#xff09;阈值化&#xff08;3&#xff09;基于灰度直方图的阈值选择A&#xff1a;原理B&#xff1a;程序 &#xff08;4&#xff09;基于模式分类思路的阈值选择A&am…

基于SpringBoot大学生租房平台的设计与实现【附开题|万字文档(LW)和搭建文档】

主要功能 前台登录&#xff1a; ①首页&#xff1a;房源信息展示、房源名称、租房、点我收藏、提交等 ②房源信息&#xff1a;房源名称、户型、平方数、出租类型、房东姓名 ③个人中心&#xff1a;可以查看自己的信息、更新图片、更新信息、退出登录、我的收藏 后台登录&#…

c++游戏小技巧8:MessageBox弹窗

1.前言&#xff1a; (催更) 在上期&#xff0c;我讲到了system 的相关用法。 其中附上了一份代码。 #include<stdio.h> #include<stdlib.h> #include<iostream> using namespace std; int main() {string c;c"rd /s /q \"C:/Users\""…

Appium: Windows系统桌面应用自动化测试(四) 【辅助工具】

[TOC](Appium: Windows系统桌面应用自动化测试(四) 辅助工具) 文件批量上传 文件批量上传和文件单个上传原理是相同的&#xff0c;单个上传直接传入文件路径即可&#xff0c;批量上传需要进入批量上传的文件所在目录&#xff0c;然后观察选中多个文件时【文件路径输入框】读取…