算法

c# 数据结构与算法解读篇(键值对key-value的使用)

泪湿孤枕 提交于 2020-01-24 05:39:04
key-value的特点: 读取&增删都快? 有 hash散列 字典 key-value,一段连续有限空间放value(开辟的空间比用到的多,hash是用空间换性能),基于key散列计算得到地址索引,这样读取快 增删也快,删除时也是计算位置,增加也不影响别人 肯定会出现2个key(散列冲突),散列结果一致18,可以让第二次的+1, 可能会造成效率的降低,尤其是数据量大的情况下,以前测试过dictionary在3w条左右性能就开始下降的厉害 //Hashtable key-value 体积可以动态增加 拿着key计算一个地址,然后放入key - value //object-装箱拆箱 如果不同的key得到相同的地址,第二个在前面地址上 + 1 //查找的时候,如果地址对应数据的key不对,那就 + 1查找。。 //浪费了空间,Hashtable是基于数组实现 //查找个数据 一次定位; 增删 一次定位; 增删查改 都很快 //浪费空间,数据太多,重复定位定位,效率就下去了 Console . WriteLine ( "***************Hashtable******************" ) ; Hashtable table = new Hashtable ( ) ; table . Add ( "123" , "456" ) ; table [ 234 ] =

java算法-二分查找算法

时光怂恿深爱的人放手 提交于 2020-01-24 04:22:33
一、二分查找算法思想 又叫折半查找,要求待查找的序列有序。每次取中间位置的值与待查关键字比较,如果中间位置的值比待查关键字大,则在前半部分循环这个查找的过程,如果中间位置的值比待查关键字小,则在后半部分循环这个查找的过程。直到查找到了为止,否则序列中没有待查的关键字。 二、图示说明 三、二分查找优缺点 优点是比较次数少,查找速度快,平均性能好; 其缺点是要求待查表为有序表,且插入删除困难。 因此,折半查找方法适用于不经常变动而查找频繁的有序列表。 使用条件:查找序列是顺序结构,有序。 四、代码实现 1.非递归方法 private static int binarySearch(int[] arr, int key) { int left = 0; int right = arr.length-1; int mid ; if (key < arr[left] || key > arr[right] || left > right){ return -1; } while(left < right){ mid = (left + right)/2; if (arr[mid] < key){ left = mid +1; }else if(arr[mid] > key){ right = mid - 1; }else { return mid ; } } return -1; } 2

k-means算法

五迷三道 提交于 2020-01-24 02:07:35
k-means算法为常见的聚类算法。 算法的大致思路为: 首先指定要分多少类(k),然后指定k个类中心点的初始坐标。 线性扫描所有的点,计算其至各中心点的距离,选择最小距离使自己归于此类。然后更新各个类中心点的坐标。 迭代上述步骤直至达到收敛条件。 伪码如下: 但是,k初始以及中心点坐标初始值的随机选定可能会对结果造成影响。 k初始值我们可以采用 手肘法 : (图片取自知乎@是泽哥啊) 取每个点至其所在类中心点的总距离,然后取其 拐点 (3)。 还可以采用 蒙特卡洛模拟 ,自动取得k值。 解决随机选取中心点的坐标的问题可以采用**k-means++**算法。 但是,每次都要线性扫描所有的比较耗时。 为了提高效率,我们可以采用 kd树 。 kd树即在n维空间(坐标为n维时),以垂直于坐标轴的方法进行空间切分。且切分位置为其坐标的中位数,如下图所示: kd树为二叉树,初始时,二叉树的根节点为整个坐标空间,然后左右子树为被其切分的两个区域,重复,直到切分到区域中没有坐标点为止。 来源: CSDN 作者: JLUspring 链接: https://blog.csdn.net/qq_37724465/article/details/103834700

200117(最短路径的Floyd算法)

你离开我真会死。 提交于 2020-01-24 01:50:39
Floyd算法是一个经典的动态规划算法。简单地说,首先我们的目标是寻找从顶点 i 到顶点 j 的最短路径。 从任意顶点i到任意顶点j的最短路径不外乎2种可能,一是直接从 i 到 j ,二是从 i 经过若干个中间顶点到 j 。所以,我们假设D(i,j)为顶点 i 到顶点 j 的最短路径的距离,对于每一个顶点 k,我们检查D(i,k) + D(k,j) < D(i,j)是否成立,如果成立,证明从 i 到 k 再到 j 的路径比 i 直接到 j 的路径短,我们便设置D(i,j) = D(i,k) + D(k,j),这样一来,当我们遍历完所有顶点 k,D(i,j)中记录的便是 i 到 j 的最短路径的距离。 算法过程: 1)首先把初始化距离数组D为图的邻接矩阵arc,路径数组P初始化为P[i][j]=j(初始化时由于 i 是直接到 j 的,所以 i 的后继结点就是 j ); 2)对于每一对顶点 i 和 j,遍历所有顶点,看看是否存在一个顶点 k 使得从 i 到 k 再加上 k 到 j 比直接从 i 到 j 的路径更短。如果是就更新D[i][j]。 递推关系式为: 如果 D[i][k]+D[k][j] < D[i][j] 则D[i][j] = D[i][k]+D[k][j] 注意!!!:仔细思考递推关系式会发现由于D[i][i]始终为0, 所以 i 、j 、k

RMQ问题(ST算法)

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-24 00:28:26
RMQ是询问某个区间内的最大值或最小值的问题,ST算法可以求解RMQ问题.ST算法通常用在要 多次询问某一些区间的问题中,相比于线段树,它的程序实现更加简单,运行速度更快,它可以做到O(nlogn)的预处理,O(1)回答每个问题.使用ST算法的条件是没有修改操作,因此它适用于没有修改操作并且访问次数较多(10^6级别甚至更大)的情况. 1.预处理 ST算法的原理实际上是动态规划,首先要知道f数组的含义,f[i][j]中i表示左边端点,j表示2^j个长度, 因此f[i,j]表示的是区间为[i,i+2^j-1]这个范围内的最大值,也就是以a[i]为起点连续的2^j个数的最大值.由于元素个数为2^j个,所以从中间平均分成两部分,每一部分的个数都为2^(j-1);假设f[6][3]分为f[6][2]和f[10][2],如下图所示, 整个区间的最大值一定是左右两部分最大值的较大者,满足动态规划的最优化原理,分析得f数组的状态转移方程为f[i][j]=max(f[i][j-1],f[i+2^(j-1)][j-1]). for(int j = 1;(1<<j) <= n;++j) //j枚举每一个可能出现的长度 for(int i = 1;i + (1<<j)-1 <= n;i++) //i枚举每一个区间的左端点 f[i][j] = max(f[i][j-1],f[i+(1<<(j-1))][j

经典算法应用之七----10亿数据中取最大的100个数据

我只是一个虾纸丫 提交于 2020-01-24 00:25:38
给出三种思路,仅供参考。。 1.思路一:根据快速排序划分的思想,每次分割之后只考虑比轴大的一部分,知道比轴大的一部分在比100多的时候,采用传统排序算法排序,取前100个。 step1:递归对所有数据分成[a,b),(b,d]两个区间,(b,d]区间内的数都是大于[a,b)区间内的数 step2:对(b,d]重复 step1操作,直到最右边的区间个数小于100个。注意[a,b)区间不用划分 step3:返回上一个区间,并返回此区间的数字数目。接着方法仍然是对上一区间的左边进行划分,分为[a2,b2),(b2,d2]两个区间,取(b2,d2]区间。如果个数不够,继续 step3操作,如果个数超过100的就重复 step1操作,直到最后右边只有100个数为止。 复杂度为O(10亿*100) 2.思路二:先取出前100个数,维护一个100个数的最小堆,遍历一遍剩余的元素,在此过程中维护小顶堆就可以了。 具体步骤如下: step1:取前m个元素(例如m=100),建立一个小顶堆。保持一个小顶堆得性质的步骤,运行时间为O(lgm);建立一个小顶堆运行时间为m O(lgm)=O(m lgm); step2:顺序读取后续元素,直到结束。每次读取一个元素,如果该元素比堆顶元素小,直接丢弃;如果大于堆顶元素,则用该元素替换堆顶元素,然后保持最小堆性质。最坏情况是每次都需要替换掉堆顶的最小元素

C语言SM2算法实现(基于GMSSL)

落爺英雄遲暮 提交于 2020-01-23 23:09:00
最近项目中需要通过C语言实现SM2、SM4国密算法,这里我基于GMSSL来进行实现,本人已在这5种环境下全部实现,并已使用在生产环境中。 1、GMSSL编译 GMSSL编译在不同环境下都不一样,这里我提供Window64、Arm64、Linux64、Android、himix200海思芯片 环境编译方法,传送门如下: Gmssl官网地址 Gmssl 各平台编译方法【绝对可用】 如果各位都是比较懒得人,我这里也给各位提供上述五种环境已经编好的库,传送门如下: Gmssl链接库(himix200、android、arm64、linux64、windows64) 2、SM2实现 我们基于第一步编译出来的库来实现我们的SM2算法,头文件相关代码(authref.h)如下: #ifndef __AUTHREF_H__ #define __AUTHREF_H__ #include <assert.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #define SM2_PUB_KEY_SIZE 178 // SM2 公钥的位数 typedef struct SM2_KEY { uint8_t *pub_key; uint8_t *pri_key; } T_sm2_key; typedef struct ENCRYPT

02:算法应用

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-23 22:42:25
算法其他篇 目录: 1.1 设计一个O(n)复杂度的算法 1.2 在大量数中找到前10个最大的数 1.3 其他 1.1 设计一个O(n)复杂度的算法 返回顶部   1、问题:计数排序       现在有一个列表,列表中的数范围都在0到100之间,列表长度大约为100万,设计算法在O(n)时间复杂度内将列表进行排序   2、原理       1、 必须知道这些数中最大的数是多少       2、 然后生成一个长度等于最大数的列表       3、 循环li列表中所有的数,li中每出现一次这个数就在生成的count列表中加一       4、 这样就可以在count列表中的对应位置记录出列表li中所有数出现的次数       5、 然后在循环count,这个数出现几次就依次写几个到li列表中,就出现下面效果 def count_sort(li, max_num): count = [0 for i in range(max_num + 1)] for num in li: count[num] += 1 i = 0 print('count',count) for num,m in enumerate(count): #循环列表count,按顺序得到li中数出现次数 for j in range(m): #这个数出现多少次就在li中依次追加多少个 li[i] = num i += 1

算法 归并排序

情到浓时终转凉″ 提交于 2020-01-23 22:30:10
归并排序 思想:图解 代码: public static void sort(int[] a,int low,int high){ if(low <high){ int mid = (low+high)/2; sort(a,low,mid); sort(a,mid+1,high); mergeSort(a,low,mid,high); } } private static void mergeSort(int[] a, int low, int mid, int high) { int lowStart = low; int highStart = mid + 1; int tmp = low; int m = low; int[] merge = new int[a.length]; while(lowStart <= mid && highStart <= high){ if(a[lowStart] <= a[highStart]){ merge[tmp++] = a[lowStart++]; } else{ merge[tmp++] = a[highStart++]; } } while(highStart <= high){ merge[tmp++] = a[highStart++]; } while(lowStart <= mid){ merge[tmp++] = a

操作系统核心原理-5.内存管理(中):分页内存管理

北城余情 提交于 2020-01-23 21:24:23
   在上一篇介绍的几种多道编程的内存管理模式中,以交换内存管理最为灵活和先进。但是这种策略也存在很多重大问题,而其中最重要的两个问题就是空间浪费和程序大小受限。那么有什么办法可以解决交换内存存在的这些问题呢?答案是分页,它是我们解决交换缺陷的“不二法门”。 一、分页内存管理 1.1 解决问题之道   为了解决交换系统存在的缺陷,分页系统横空出世。分页系统的核心在于: 将虚拟内存空间和物理内存空间皆划分为大小相同的页面,如4KB、8KB或16KB等,并以页面作为内存空间的最小分配单位,一个程序的一个页面可以存放在任意一个物理页面里 。   (1)解决空间浪费碎片化问题   由于将虚拟内存空间和物理内存空间按照某种规定的大小进行分配,这里我们称之为页(Page),然后按照页进行内存分配,也就克服了外部碎片的问题。   (2)解决程序大小受限问题   程序增长有限是因为一个程序需要全部加载到内存才能运行,因此解决的办法就是使得一个程序无须全部加载就可以运行。使用分页也可以解决这个问题,只需将当前需要的页面放在内存里,其他暂时不用的页面放在磁盘上,这样一个程序同时占用内存和磁盘,其增长空间就大大增加了。而且,分页之后,如果一个程序需要更多的空间,给其分配一个新页即可(而无需将程序倒出倒进从而提高空间增长效率)。 1.2 虚拟地址的构成与地址翻译   (1)虚拟地址的构成   在分页系统下