C语言详解数据结构与算法中枚举和模拟及排序

目录
  • 枚举
    • 连号区间数
    • 递增三元组
      • 二分
      • 双指针
      • 前缀和
  • 模拟
    • 特别数的和
    • 错误票据
  • 排序
    • 快速排序
    • 归并排序

枚举

连号区间数

来源:第四届蓝桥杯省赛C++B组,第四届蓝桥杯省赛JAVAB组

小明这些天一直在思考这样一个奇怪而有趣的问题:

在 1∼N 的某个排列中有多少个连号区间呢?

这里所说的连号区间的定义是:

如果区间 [L,R] 里的所有元素(即此排列的第 L 个到第 R 个元素)递增排序后能得到一个长度为 R−L+1 的“连续”数列,则称这个区间连号区间。

当 N 很小的时候,小明可以很快地算出答案,但是当 N 变大的时候,问题就不是那么简单了,现在小明需要你的帮助。

输入格式
第一行是一个正整数 N,表示排列的规模。

第二行是 N 个不同的数字 Pi,表示这 N 个数字的某一排列。

输出格式
输出一个整数,表示不同连号区间的数目。

数据范围
1≤N≤10000,
1≤Pi≤N

输入样例1:

4
3 2 4 1

输出样例1:

7

输入样例2:

5
3 4 2 5 1

输出样例2:

9

样例解释
第一个用例中,有 7 个连号区间分别是:[1,1],[1,2],[1,3],[1,4],[2,2],[3,3],[4,4]
第二个用例中,有 9 个连号区间分别是:[1,1],[1,2],[1,3],[1,4],[1,5],[2,2],[3,3],[4,4],[5,5]

先来看暴力做法

先两次for()循环,对给出的数排序,然后再对区间内的数做判断,如果连续的就res++。

#include <bits/stdc++.h>

using namespace std;

const int N=10010;

int a[N],bac[N];

int main()
{
    int n,res=0;
    cin >> n;
    for(int i=1;i<=n;i++) cin >> a[i];

    for(int i=1;i<=n;i++)
       for(int j=i;j<=n;j++){
            memcpy(bac,a,sizeof a); // 这里要把数组的初始状态存在bac数组中,因为每次sort排序后,数组的顺序会发生改变。
            sort(a+i,a+j+1);

            bool flag=true;
            for(int k=i;k<j;k++){
                if(a[k+1] - a[k] != 1){
                    flag=false;
                    break;
                }
            }

            if(flag) res++;
            memcpy(a,bac,sizeof a); // 还原数组a的初始状态
        }
    cout << res << endl;
    return 0;
}

但是这道题暴力做法在蓝桥杯中只能得60分,然后我们再来想一下怎么优化?

这里设两层循环,一层i表示左端点,第二层j表示右端点。如果要保持连续性的话那么有一个思路:因为是连续的所以在所取的[l,r]范围中寻找最大值,最小值。然后相减,最后和r-l(区间长度)作比较即可。除此之外当l=r时也算作连续
即MAX-MIN==R-L

#include <bits/stdc++.h>

using namespace std;

const int N = 10010, INF = 100000000;

int n;
int a[N];

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> a[i];

    int res = 0;
    for (int i = 0; i < n; i ++ )   // 枚举区间左端点
    {
        int minv = INF, maxv = -INF;
        for (int j = i; j < n; j ++ )   // 枚举区间右端点
        {
            minv = min(minv, a[j]);
            maxv = max(maxv, a[j]);
            if (maxv - minv == j - i) res ++ ;
        }
    }

    cout << res << endl;

    return 0;
}

递增三元组

来源:第九届蓝桥杯省赛C++B组,第九届蓝桥杯省赛JAVAB组

给定三个整数数组

A=[A1,A2,…AN],
B=[B1,B2,…BN],
C=[C1,C2,…CN],

请你统计有多少个三元组 (i,j,k) 满足:

1≤i,j,k≤N
Ai<Bj<Ck
输入格式
第一行包含一个整数 N。

第二行包含 N 个整数 A1,A2,…AN。

第三行包含 N 个整数 B1,B2,…BN。

第四行包含 N 个整数 C1,C2,…CN。

输出格式
一个整数表示答案。

数据范围
1≤N≤105,
0≤Ai,Bi,Ci≤105

输入样例:

3
1 1 1
2 2 2
3 3 3

输出样例:

27

首先考虑暴力做法,三个数组嵌套枚举,O(n3)的时间复杂度,n≤105一定会超时,这里提供代码,想试一下的可以试试

//暴力做法枚举(会超时)
#include <bits/stdc++.h>

using namespace std;

const int N=10000;

int n,a[N],b[N],c[N];
int cnt=0;
int main(){
    //输入
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++) cin>>b[i];
    for(int i=0;i<n;i++) cin>>c[i];
    //运算
    for(int i=0;i<n;i++)
    	for(int j=0;j<n;j++)
    		for(int k=0;k<n;k++)
        		if(a[i]<b[j]&&b[j]<c[k])
	            cnt++;
    cout<<cnt<<endl;
    return 0;
}

尝试通过枚举的次序进行优化本题,先枚举B数组,在A中寻找小于B[i]的数的个数cnt1,在C中寻找大于B[i]的数的个数cnt2,带有B[i]的合法选择数就是cnt1*cnt2。

用暴力查找时间总的时间复杂度为O(n2),还是会超时。

二分

既然是查找,那么可以考虑进行二分查找,查找前先通过排序预处理三个数组,排序时间复杂度O(nlog2n)O(nlog2n),枚举B的所有元素+查找A,C中的元素时间复杂度也是O(nlog2n)O(nlog2n),总的时间复杂度降为O(nlog2n)

//二分查找
#include <bits/stdc++.h>

using namespace std;

const int N=100000+6;

int n,a[N],b[N],c[N];
long long res=0;
int main(){
    cin>>n;//输入
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++) cin>>b[i];
    for(int i=0;i<n;i++) cin>>c[i];
    //排序
    sort(a,a+n);sort(b,b+n);sort(c,c+n);
    //查找
    for(int i=0;i<n;i++)
    {
        int low_a=0,right_a=n-1;
        while(low_a<right_a)    //找比b[i]小的最后一个数
        {
            int mid=(low_a+right_a+1)>>1;//加1之后改为向上取整
            if(a[mid]<b[i])  low_a=mid;
            else  right_a=mid-1;
        }
        if(a[low_a]>=b[i]) low_a=-1;//所有数都大于等于b[i]的时候,low_a=-1,这样最后(low_a+1)*(n-low_b)的时候为0

        int low_b=0,right_b=n-1;
        while(low_b<right_b)   //找比b[i]大的第一个数
        {
            int mid =(low_b+right_b)>>1;
            if(c[mid]>b[i]) right_b=mid;
            else low_b=mid+1;
        }
        if(c[low_b]<=b[i]) low_b=n;//所有数都小于等于b[i]的时候,low_b=n,这样最后(low_a+1)*(n-low_b)的时候为0
        //if(low_a!=0&&low_b!=n-1)//最开始的时候用这种方法判断,后来发现不行
         //如果只有一个数字可以的时候,这种情况无法判断,
         // 例如:
         //  1 4 5
         //  5 5 9
         //  4 6 7(10)  当b[i]=9的时候,c[i]=7和10的时候无法判断
        res+=(long long)(low_a+1)*(n-low_b);

    }
    cout<<res<<endl;

    return 0;
}

双指针

进一步对查找进行优化,对于排过序的数组A和B,寻找A中小于B[i]的元素的个数可以考虑双指针算法,因为每个指针最多移动n次,故查找的时间复杂度降到O(n),查找C与查找A同理,只是找第一个大于B的位置。

只需要将上述二分程序中的

//二分
for(int i = 1; i <= n; ++i) {
    int key = num[1][i];
    //A中二分查找第一个小于key的数的下标
    int pos1 = lower_bound(num[0]+1, num[0]+n+1, key)-num[0]-1;
    //C中二分查找第一个大于key的数的下标
    int pos2 = upper_bound(num[2]+1, num[2]+n+1, key)-num[2];
    if(pos1 >= 1 && pos2 <= n) {
        ans += (LL)pos1*(n-pos2+1);
    }
}

更改为

//双指针
int a = 1, c = 1;
for(int i = 1; i <= n; ++i) {
    int key = num[1][i];
    while(a<=n && num[0][a] < key) a++;
    while(c<=n && num[2][c] <= key) c++;

    ans += (LL)(a-1)*(n-c+1);
}

完整的双指针程序为:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 1e5+10;

int num[3][N];

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < 3; ++i)
        for(int j = 1; j <= n; ++j)
            scanf("%d", &num[i][j]);
    for(int i = 0; i < 3; ++i)
        sort(num[i]+1, num[i]+n+1);

    LL ans = 0;
    //枚举B,寻找A满足的个数以及C满足的个数相乘
    int a = 1, c = 1;
    for(int i = 1; i <= n; ++i) {
        int key = num[1][i];
        while(a<=n && num[0][a] < key) a++;
        while(c<=n && num[2][c] <= key) c++;

        ans += (LL)(a-1)*(n-c+1);

    }
    cout<<ans<<endl;
    return 0;
}

前缀和

之前的双指针算法时间复杂度的瓶颈为:排序O(nlog2n)O(nlog2n)

考虑是否可以不排序在O(n)的时间内解决此问题呢?

既然要排序实现快速的查找A中小于B[i]的数的个数,可以将数组A中所有元素出现的次数存入一个哈希表中,因为数组中元素的范围只有n5n5, 可以开一个大的数组cnta 作为哈希表。

在枚举B中元素时,我们需要快速查找找小于B[i]的所有元素的总数,只需要在枚举之前先将求出表中各数的前缀和即可。

查找C与查找A同理可得。

//前缀和
#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N = 1e5+10;
int A[N], B[N], C[N];
int cnta[N], cntc[N], sa[N], sc[N];

int main() {
    int n;
    scanf("%d", &n);
    //获取数i在A中有cntc[i]个,并对cnt求前缀和sa
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        cnta[++A[i]]++;
    }
    sa[0] = cnta[0];
    for(int i = 1; i < N; ++i) sa[i] = sa[i-1]+cnta[i];
    //B只读取即可
    for(int i = 1; i <= n; ++i) scanf("%d", &B[i]), B[i]++;

    //获取数i在C中有cntc[i]个,并对cnt求前缀和sc
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &C[i]);
        cntc[++C[i]]++;
    }
    sc[0] = cntc[0];
    for(int i = 1; i < N; ++i) sc[i] = sc[i-1]+cntc[i]; 

    //遍历B求解
    LL ans = 0;
    for(int i = 1; i <= n; ++i) {
        int b = B[i];
        ans += (LL)sa[b-1] * (sc[N-1] - sc[b]);
    }
    cout<<ans<<endl;
    return 0;
}

分别是暴力,前缀和,双指针,二分。

模拟

特别数的和

来源:第十届蓝桥杯省赛C++B组,第十届蓝桥杯省赛JAVAB组

小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。

请问,在 1 到 n 中,所有这样的数的和是多少?

输入格式
共一行,包含一个整数 n。

输出格式
共一行,包含一个整数,表示满足条件的数的和。

数据范围
1≤n≤10000

输入样例:

40

输出样例:

574

常用小技巧:关于取出x的每位数字 和 将字符数字转为数字

1.取出x的每位数字
int t = x % 10;
x /= 10;
2.将字符数字转为数字
int x = 0;
for (int i = 0; i < str.size(); i ++ )
    x = x * 10 + str[i] - '0';

下面请看你代码:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n;
    cin >> n;

    int res = 0;
    for (int i = 1; i <= n; i ++ )
    {
        int x = i;
        while (x)
        {
            int t = x % 10; // 取出x的个位
            x /= 10;    // 删掉x的个位
            if (t == 2 || t == 0 || t == 1 || t == 9)
            {
                res += i;
                break;
            }
        }
    }

    cout << res << endl;

    return 0;
}

错误票据

来源:第四届蓝桥杯省赛C++A/B组,第四届蓝桥杯省赛JAVAA/B组

某涉密单位下发了某种票据,并要在年终全部收回。

每张票据有唯一的ID号。

全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。

因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。

你的任务是通过编程,找出断号的ID和重号的ID。

假设断号不可能发生在最大和最小号。

输入格式
第一行包含整数 N,表示后面共有 N 行数据。

接下来 N 行,每行包含空格分开的若干个(不大于100个)正整数(不大于100000),每个整数代表一个ID号。

输出格式
要求程序输出1行,含两个整数 m,n,用空格分隔。

其中,m表示断号ID,n表示重号ID。

数据范围
1≤N≤100

输入样例:

2
5 6 8 11 9 
10 12 9

输出样例:

7 9

思路

找出最大和最小的数,同时再用一个数组记录每个数字的个数,最后遍历一遍即可

#include <bits/stdc++.h>

using namespace std;

const int N = 10010;

int n;
int a[N];

int main()
{
    int cnt;
    cin >> cnt;
    string line;

    getline(cin, line); // 忽略掉第一行的回车
    while (cnt -- )
    {
        getline(cin, line);
        stringstream ssin(line);

        while (ssin >> a[n]) n ++ ;
    }

    sort(a, a + n);

    int res1, res2;
    for (int i = 1; i < n; i ++ )
        if (a[i] == a[i - 1]) res2 = a[i];  // 重号
        else if (a[i] >= a[i - 1] + 2) res1 = a[i] - 1; // 断号

    cout << res1 << ' ' << res2 << endl;

    return 0;
}

排序

快速排序

给定你一个长度为 n 的整数数列。

请你使用快速排序对这个数列按照从小到大进行排序。

并将排好序的数列按顺序输出。

输入格式
输入共两行,第一行包含整数 n。

第二行包含 n 个整数(所有整数均在 1∼109 范围内),表示整个数列。

输出格式
输出共一行,包含 n 个整数,表示排好序的数列。

数据范围
1≤n≤100000

输入样例:

5
3 1 2 4 5

输出样例:

1 2 3 4 5

快排思路

1.有数组 q, 左端点 l, 右端点r

2.确定划分边界 x

3.将 q 分为 <=x 和 >=x 的两个小数组
        
        i 的含义: i 之前的元素都 ≤x, 即 q[l..i−1]q[l..i−1] ≤x
        j 的含义: j 之后的元素都 ≥x, 即 q[j+1..r]q[j+1..r] ≥x
        结论: while循环结束后, q[l..j] ≤x,q[j+1..r] ≥x
        简单不严谨证明:
        
        while 循环结束时, i≥j
        若 i>j , 显然成立
        
        若 i=ji=j
        ∵∵ 最后一轮循环中两个 do−whiledo−while 循环条件都不成立
        
        ∴ q[i]≥x,q[j]≤x
        ∴ q[i]=q[j]=x
        ∴ 结论成立

4.递归处理两个小数组

#include <iostream>

using namespace std;

const int N = 100010;

int q[N];

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }

    quick_sort(q, l, j);
    quick_sort(q, j + 1, r);
}

int main()
{
    int n;
    scanf("%d", &n);

    for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);

    quick_sort(q, 0, n - 1);

    for (int i = 0; i < n; i ++ ) printf("%d ", q[i]);

    return 0;
}

归并排序

归并的题和快排的题是一样的,这里就不写题目了。

归并思路

1.有数组 q, 左端点 l, 右端点 r

2.确定划分边界 mid

3.递归处理子问题 q[l..mid], q[mid+1..r]

4.合并子问题

主体合并    
        至少有一个小数组添加到 tmp 数组中    
    收尾    
        可能存在的剩下的一个小数组的尾部直接添加到 tmp 数组中    
    复制回来    
        tmp 数组覆盖原数组

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int a[N], tmp[N];

void merge_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int mid = l + r >> 1;

    merge_sort(q, l, mid), merge_sort(q, mid + 1, r);

    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
        if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
        else tmp[k ++ ] = q[j ++ ];
    while (i <= mid) tmp[k ++ ] = q[i ++ ];
    while (j <= r) tmp[k ++ ] = q[j ++ ];

    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);

    merge_sort(a, 0, n - 1);

    for (int i = 0; i < n; i ++ ) printf("%d ", a[i]);

    return 0;
}

到此这篇关于C语言详解数据结构与算法中枚举和模拟及排序的文章就介绍到这了,更多相关C语言 枚举 模拟 排序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言超详细讲解排序算法下篇

    上期学习完了前四个排序,这期我们来学习剩下的三个排序:

  • C语言模拟实现密码输入的示例代码

    目录 引言 思路分析 代码实现 代码分析 引言 登录账号时我们要输入密码,密码输入错误时会提示密码错误.有时密码的输入次数会被限制,例如银行卡,当我们3次密码都输入错误时卡会被冻结.下面用C语言模拟实现密码输入. 思路分析 首先要确立一个正确密码,再确定密码输入限制次数,接着用一个scanf语句读取用户输入的密码.将用户输入的密码和先前确定的密码进行比较,如果密码输入正确就显示密码正确,如果密码输入错误就提示密码错误,并告诉用户还有几次输入机会. 代码实现 #include<stdio.h>

  • C语言中枚举与指针的实例详解

     C语言中枚举与指针的实例详解 总结一下, 定义枚举,用typedef enum关键字, 比如 typedef enum{Red,Green,Blue} Color3; 枚举到数值的转换,如果没有指定代表数值就是从0开始算, 比如 Color3 c=Red; printf("%d",c);会显示0, 除非指定 如typedef enum{Red=3,Green=5,Blue=10} Color3; 关于类型指针的定义, 定义的时候在变量名左边加*代表此变量只是一个空指针而已, 若需要赋

  • C语言超详细讲解排序算法上篇

    目录 1.直接插入排序 2.希尔排序(缩小增量排序) 3.直接选择排序 4.堆排序 进入正式内容之前,我们先了解下初阶常见的排序分类 :我们今天讲前四个! 1.直接插入排序 基本思想:当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排 序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移! 直接插入排序的特性总结: 1. 元素集

  • C语言三个函数的模拟实现详解

    目录 一.strcpy 二.模拟实现strcat 三.strcmp 总结: 一.strcpy //模拟实现strcpy #include<stdio.h> #include<assert.h> char* my_strcpy(char*dest, char*str) { assert(dest && str); char* tmp = dest; while (*str != '\0') { *dest = *str; dest++; str++; } *dest

  • C语言结构体,枚举,联合体详解

    目录 1.什么是结构体.枚举.联合体 2.定义结构体 2.1 包含结构体成员变量.variable 2.2 tag.结构体成员变量 2.3 用结构体声名变量 2.4 用typedef 创建新类型 2.5 两个结构体相互包含 2.6 结构体变量初始化 2.7 结构体指针 3.枚举 3.1 定义方式 3.2 为什么用枚举 3.3 枚举变量的定义 3.4 实例 3.5 枚举实际用途 4.联合体 4.1 与结构体区别 4.2 定义 总结 1.什么是结构体.枚举.联合体 结构体(struct)是由一系列具

  • C语言枚举的使用以及作用

    目录 一.什么是枚举 二.枚举的用法 三.枚举有什么用,用在哪里? 四.枚举要注意的地方 一.什么是枚举 我对枚举的理解就是把一些固定的值—列举出来分别起个名字,比如说给1取个名字叫Ture,0取个名字叫False,Ture和False都是表示同一个类型的数据,比如说都是代表逻辑的对错,这里用51单片机的IE中断使能寄存器来举一个例子. 二.枚举的用法 1.直接定义枚举值,然后给普通变量赋值 2.定义一个带名称的枚举 3.定义枚举别名 #include <stdio.h> enum  {   

  • C语言详解数据结构与算法中枚举和模拟及排序

    目录 枚举 连号区间数 递增三元组 二分 双指针 前缀和 模拟 特别数的和 错误票据 排序 快速排序 归并排序 枚举 连号区间数 来源:第四届蓝桥杯省赛C++B组,第四届蓝桥杯省赛JAVAB组 小明这些天一直在思考这样一个奇怪而有趣的问题: 在 1∼N 的某个排列中有多少个连号区间呢? 这里所说的连号区间的定义是: 如果区间 [L,R] 里的所有元素(即此排列的第 L 个到第 R 个元素)递增排序后能得到一个长度为 R−L+1 的“连续”数列,则称这个区间连号区间. 当 N 很小的时候,小明可以

  • C语言详解分析进程控制中进程终止的实现

    目录 进程退出的形式 进程退出的几种方法 进程退出的形式 进程退出的几种情况 正常退出(自愿,代码运行完其结果正确) 错误退出(自愿,代码运行完其结果不正确) 异常退出(非自愿,代码异常直接终止) 被其他进程终止(非自愿) 自愿退出会返回一个退出码,由父进程接收. 在Linux上可以使用命令echo $?显示最近一次退出的进程返回的退出码 //现有如下代码,源文件名为mycode.c # include <stdio.h> int main(void) { printf("i am

  • 详解Python数据结构与算法中的顺序表

    目录 0. 学习目标 1. 线性表的顺序存储结构 1.1 顺序表基本概念 1.2 顺序表的优缺点 1.3 动态顺序表 2. 顺序表的实现 2.1 顺序表的初始化 2.2 获取顺序表长度 2.3 读取指定位置元素 2.4 查找指定元素 2.5 在指定位置插入新元素 2.6 删除指定位置元素 2.7 其它一些有用的操作 3. 顺序表应用 3.1 顺序表应用示例 3.2 利用顺序表基本操作实现复杂操作 0. 学习目标 线性表在计算机中的表示可以采用多种方法,采用不同存储方法的线性表也有着不同的名称和特

  • C语言 详解如何删除有序数组中的重复项

    目录 删除有序数组中的重复项Ⅰ a.思路 b.图解 c.代码 d.思考 删除有序数组中的重复项Ⅱ a.思路 b.图解 c.代码 d.思考 删除有序数组中的重复项Ⅰ a.思路 定义变量 int dest=0,cur=1,nums[cur]与nums[dest]逐一比较. nums[cur]!=nums[dest],将nums[cur]放入dest下一个位置,更新dest. nums[cur]!=nums[dest],cur移动. cur==numsSize,结束.返回dest+1. b.图解 c.

  • 详解5种Java中常见限流算法

    目录 01固定窗口 02滑动窗口 03漏桶算法 04令牌桶 05滑动日志 06分布式限流 07总结 1.瞬时流量过高,服务被压垮? 2.恶意用户高频光顾,导致服务器宕机? 3.消息消费过快,导致数据库压力过大,性能下降甚至崩溃? ...... 在高并发系统中,出于系统保护角度考虑,通常会对流量进行限流:不但在工作中要频繁使用,而且也是面试中的高频考点. 今天我们将图文并茂地对常见的限流算法分别进行介绍,通过各个算法的特点,给出限流算法选型的一些建议,并给出Java语言实现的代码示例. 01固定窗

  • 详解如何在Java中实现堆排序算法

    目录 算法描述 实现代码 测试代码 算法描述 堆排序算法的描述如下: 将待排序的数组调整为最大堆,此时未排序的长度 N 为数组的长度,调整的过程就是倒序将数组的前 N/2 个元素下沉的过程,每次下沉都会将较大的元素带到上面,最终将数组变为最大堆: 弹出最大堆的堆顶元素并将其移动到数组的最后面,将原本最后面的元素放到堆顶,然后将未排序的长度 N - 1,调整数组的前 N 个元素为最大堆: 重复步骤 2 直到未排序的长度为 0. 实现代码 package com.zhiyiyo.collection

  • C语言详解float类型在内存中的存储方式

    目录 1.例子 2.浮点数存储规则 1.例子 int main() { int n = 9; float *pFloat = (float *)&n; printf("n的值为:%d\n",n); printf("*pFloat的值为:%f\n",*pFloat); *pFloat = 9.0; printf("num的值为:%d\n",n); printf("*pFloat的值为:%f\n",*pFloat); re

  • C语言详解如何实现堆及堆的结构与接口

    目录 一.堆的结构及实现(重要) 1.1 二叉树的顺序结构 1.2 堆的概念及结构 1.3 堆的实现 1.3.1 堆的向下调整算法 1.3.2 向下调整算法的时间复杂度 1.3.3 堆的创建(向下调整) 1.3.4 堆排序 1.3.5 建堆的时间复杂度 二.堆的相关接口实现(以大堆为例) 2.1 堆的初始化 2.2 堆的销毁 2.3 堆的插入 2.4 堆的删除 2.5 获取堆顶元素 2.6 堆的判空 2.7 找出堆中前k个最大元素 2.8 堆的创建(向上调整) 一.堆的结构及实现(重要) 1.1

  • C语言详解如何实现带头双向循环链表

    目录 创建链表存储结构 创建结点 链表的初始化 双向链表的打印 双向链表尾插 双向链表尾删 双向链表头插 双向链表头删 双向链表查找 双向链表pos前插入结点 双向链表删除pos位置的结点 双向链表的销毁 顺序表和链表的区别 2022042311415360.{C}{C}png" /> 创建链表存储结构 我们需要创建一个结构体来存储一个链表结点的相关信息. typedef int ListDataType;//将ListDataType先定义为int类型,根据需要可以改为不同的类型 //创

  • C语言详解结构体的内存对齐与大小计算

    目录 结构体的内存对齐 1.计算结构体的大小 2.结构体的对齐规则 3.为什么存在内存对齐? 4.总结 结构体的内存对齐 1.计算结构体的大小 struct S1 { char c1; // 1 byte,默认对齐数为8,所以c1的对齐数是1,第一个成员变量放在与结构体变量偏移量为0的地址处 int i; // 4 byte,默认对齐数为8,所以i的对齐数是4,所以i要放到偏移量为 4的整数倍 的地址处 char c2; // 1 byte,默认对齐数为8,所以c2的对齐数是1,所以c2要放到偏

随机推荐