
algorithm
文章平均质量分 76
香味荧光笔
这个作者很懒,什么都没留下…
展开
-
线性表的顺序实现
用数组来实现线性表,在处理元素移动和边界位置的时候要注意一点。直接贴代码了。//线性表的顺序表示//lovesunmoonlight//2017.3.29 #include#include#include#includeusing namespace std;#define LIST_INIT_SIZE 100#define MAX 10#define LISTINCR原创 2017-03-29 12:19:05 · 263 阅读 · 0 评论 -
高精度乘法(正整数)
高精度正整数乘法,包含了高精度正整数的加法。就是最简单的字符串处理,注意一些细节就行。代码如下:// 1036.cpp : 定义控制台应用程序的入口点。// 大整数乘法#include "stdafx.h"#include #include #include #include using namespace std;//大整数加法string add(string s1原创 2017-08-28 22:54:53 · 757 阅读 · 0 评论 -
求序列的最大最小值
单求最大或最小值需要遍历整个序列,复杂度O(n)。当同时求最大和最小值时,可以将序列的每一对相邻元素先做比较,然后与当前的最大值最小值进行比较,来决定是否更新。这样每两个元素之间需要3次比较。代码如下:// maxmin.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include #include #include #include原创 2017-10-06 22:14:18 · 3371 阅读 · 0 评论 -
一个数组实现两个栈
思路:两个栈栈底分别为数组两端,栈顶分别向数组中间发展。长度为N的数组在两个栈的元素总数不超过N时不溢出。代码如下:// twostacks.cpp : 定义控制台应用程序的入口点。// 一个数组实现两个栈,从两边开始分别增长// 最多可容纳n个元素#include "stdafx.h"#include #include #define N 10int a[N];int原创 2018-01-02 21:55:56 · 648 阅读 · 0 评论 -
链表实现队列
思路:队列涉及到两端的操作,所以使用头结点和尾结点两个指针,避免在入队操作时遍历整个链表。代码:// linkedlistqueue.cpp : 定义控制台应用程序的入口点。// 链表实现队列#include "stdafx.h"#include using std::cin;using std::cout;using std::endl;using std::cerr;原创 2018-01-02 22:23:37 · 211 阅读 · 0 评论 -
迷宫问题
思路:裸的BFS。每次在四个方向上进行搜索,如果走得通(没有碰到边界或障碍),就将该结点加入队列。该结点的最短路径长度更新为其前驱结点的最短路径长度+1,如果需要重构路径的话,数组中保存该结点的前驱位置,输出的时候倒序输出(利用一个栈)即可。代码:// 1252.cpp : 定义控制台应用程序的入口点。// AC// BFS求迷宫问题,从左上角走到右下角#include "stda原创 2018-01-04 21:20:03 · 745 阅读 · 0 评论 -
BFS求四连通块数目
裸BFS的题目。输入是一个n*m的矩阵,矩阵由0-9的数字构成,0表示海水,数字表示陆地,求四连通的陆地块的数目。今天发现,BFS在遍历到某个结点时,先访问该结点再将邻接点入队和先将邻结点入队再访问该结点没有本质区别。而DFS则需要在某个结点可以深入的结点全部访问完再回溯到该结点时,再对其进行访问。代码:// 1329.cpp : 定义控制台应用程序的入口点。// AC// B原创 2018-01-04 16:48:39 · 1983 阅读 · 2 评论 -
并查集
思路:并查集用于解决两个问题。1:判断两个元素是否属于同一集合。2.将已有的两个集合进行合并。常用并查集实现的问题有最近公共祖先(LCA)问题和kruskal求最小生成树。在进行两个集合合并的时候,可以采用一种启发式的按秩合并策略。代码:// 1346.cpp : 定义控制台应用程序的入口点。// 并查集// 带路径压缩#include "stdafx.h"#include原创 2018-01-06 17:28:56 · 162 阅读 · 0 评论 -
并查集求集合个数和每个集合中的元素个数
思路:维护一个数组,代表以某个结点为根的树的结点数目,初始化为全1。在合并两个集合时,将秩较小的集合的元素数目加到秩较大的集合上。这里需要注意一下,就是Union过程处理两个祖先相同的结点,此时实际上没有真正的合并这两个结点,所以不需要更新集合的元素数目。至于统计集合个数就比较简单了,直接扫描一遍所有的结点,如果某个结点的祖先结点不是它自己,说明该结点是某个集合的祖先元素,统计这种结点个数即可。原创 2018-01-06 22:24:50 · 10454 阅读 · 1 评论 -
判断有向图是否有环
思路:leetcode的一道题。无环的有向图可以排出一个拓扑顺序。首先将每个结点的入度求出(扫描一遍边表),如果没有入度为0的结点,则说明有环。在循环开始前,入度为0的结点表示其没有先修课程,可以看作是已排好拓扑序。循环中,每次选择一个结点,扫描其邻居结点并检查入度,如果某个邻居结点的入度为1(说明只和当前结点相邻),则将其加入拓扑序中,依次循环。对结点的搜索可以是BFS。代码://原创 2018-01-09 10:03:24 · 2309 阅读 · 0 评论 -
求二叉树最高叶子节点的深度
思路:leetcode的一道题。递归求解,依次求每个结点的最高叶子结点的高度。也可以改成非递归形降低时间复杂度。代码// leetcode111.cpp : 定义控制台应用程序的入口点。// AC// 求二叉树最高叶子节点的深度// 递归求解#include "stdafx.h"#include #include using std::cin;using std::co原创 2018-01-09 11:35:09 · 785 阅读 · 0 评论 -
归并排序的简单实现
学习递归最开始就是斐波那契和归并排序。核心思想就是递归地把序列分成两部分,直到只剩一个元素。然后将每次划分的两部分再递归地合并起来,合并时候的顺序觉决定了排序的顺序还是逆序。划分的过程可以看做是生成一颗叶子结点数为n的二叉树,这个过程的复杂度为lgn(树的高度)。而合并的过程是相当于将每层的节点数相加,复杂度为n*lgn。所以整体的复杂度为O(nlgn)。CLRS里给的复杂度分析方法是递归树(原创 2017-08-23 15:51:09 · 391 阅读 · 0 评论 -
桶排序的简单实现
桶排序的思想有点像计数排序,又有点像快速排序,还用到一点hash的东西,值得仔细琢磨。具体做法如下,按照某种hash函数,将数据映射到不同的桶中,使用hash是因为我们要保证每个数据的映射过程应该在常数时间内完成。映射完成后,每个桶中的数据相比于其他桶都是有序的(也就是相邻的桶有严格的顺序),这个就有点像快速排序了(可以把那里看成是两个桶)。之后可以对每个桶内的数据用其他的排序方法排序。当然也原创 2017-08-24 21:18:10 · 550 阅读 · 0 评论 -
线性表的链式表示(单链表)
链表的好处在于插入和删除元素时只需改变指针的指向,减少操作次数。链表的存储结构可以是顺序的(静态链表)也可以是无序的。缺点是随机访问时需要遍历整个表。本文用无序的存储结构实现了单链表。//线性表的链式表示(单向链表) //lovesunmoonlight//2017.3.29 #include#include#include#includeusing namespace std原创 2017-03-29 14:59:51 · 331 阅读 · 0 评论 -
DFS遍历图
//DFS遍历有向图//采用十字链表存储结构 //2017.3.30//lovesunmoonlight #include#include#include#include#include#includeusing namespace std;#define MAX_VERTEX_NUM 20struct ArcBox;queue order; //表头结点原创 2017-03-30 17:44:08 · 505 阅读 · 0 评论 -
希尔排序的简单实现
希尔排序是插入排序的一种比较高级的变形。基本思路还是分治。显然,对于一个给定的顺序表,如果顺序表已经处于一个“相对有序”的状态时,插入排序进行的比较和移动次数都会有所减少。而对于较短的序列,常规的插入排序效率可以接受。因此可以考虑将序列分为几个不同的子序列,分别进行插入排序后再合并。当顺序表达到了一种比较令人满意的“相对有序”状态时,在进行一次常规的插入排序,就能比较高效地得到排序结果。(当然这个原创 2017-03-24 17:56:09 · 375 阅读 · 0 评论 -
插入排序的简单实现
之前一直知道插入排序的大概思路,也是一种比较直观的O(N^2)复杂度的排序算法。主要针对顺序表,想法很直观,但是一直没有实现过。主要思路就是维护一个有序的表,可以从第二个元素开始生长,插入元素i时依次和前面的i-1个元素进行比较,找到正确的位置。这里的一个技巧是提前把一个位置空缺出来,这样在进行比较的同时就可以进行元素的移动,找到正确的位置后直接插入即可。当然如果第i个元素原本已经在正确的位置时,原创 2017-03-24 15:43:16 · 373 阅读 · 0 评论 -
折半插入排序
这个是在上一篇插入排序的基础上的改进。在查找第i个元素的正确位置的过程中,使用折半查找加速。数据量大的情况下效率应该有比较显著的提示。//折半插入排序//lovesunmoonlight//2017.3.24 #include#include#includeusing namespace std;#define MAX 10typedef struct{ int key原创 2017-03-24 16:14:51 · 347 阅读 · 0 评论 -
快速排序的简单实现
快速排序是一种比较高级的排序方法。拥有O(NlogN)的平均复杂度。快速排序的基本思路是交换。具体做法如下,首先选定序列中的一个元素作为枢轴量(通常选择第一个元素)。然后让序列中的各元素依次和枢轴量进行比较,通过交换使得:比它小的排在它左边,比它大的排在它右边。通过这一趟排序,我们将序列分成了两部分,其中一部分全部比另一部分小(当然枢轴量放在哪一部分无所谓)。之后的想法就比较自然了,我们可以对原创 2017-03-24 21:23:53 · 371 阅读 · 0 评论 -
顺序表操作
顺序表的简单实现。包括表的初始化,插入,删除,归并。内存分配使用C语言的malloc和realloc来实现。假设在每个合法位置进行插入和删除操作的概率相等,则这两种操作每次的平均移动次数为n/2,时间复杂度为O(n)。代码如下:#include #include #include using namespace std;#define LISTINCREMENT 10原创 2017-06-11 10:58:35 · 494 阅读 · 0 评论 -
单链表操作
单链表操作的实现,包括初始化,插入,删除,遍历,排序,归并等。为了方便,使用了带头结点的单链表。注意,单链表的局限之处在于只能向后继方向进行遍历,所以在进行插入和删除操作时要找到目标结点的前驱结点。这个比较关键。其他的细节就比较简单了。代码如下:// LinkList.cpp : 定义控制台应用程序的入口点。//带头结点的单链表#include "stdafx.h" #inclu原创 2017-06-12 10:31:12 · 253 阅读 · 0 评论 -
二路插入排序
插入排序时需要移动大量元素。为此可用一个辅助的循环数组来减少元素的移动次数。具体做法如下,对于一个待排序的数组a,我们首先找到一个与a相同大小的循环数组。然后按照以下操作进行。1.令b[0]=a[0]。因为一个元素总是有序的。2.令两个指针first和final指向b中已存在元素的最大和最小值。3.对于从a[1]开始的元素,我们从b中寻找其正确的插入位置。这时会出现三种情况。如果a[i原创 2017-06-12 17:14:19 · 489 阅读 · 0 评论 -
IP地址判断
输入一个字符串,判断是否是合法的IP地址。具体的做法是用'.'将字符串进行分割,分割后如果满足:1.有4部分 2.每部分是0-255的整数 则为合法的字符串。但是由于c++里没有python中的split(貌似boost里有),所以要自己写一个split函数。这里借鉴了别人的写法(一开始我想暴力判断,后来发现行不通,还是要用分割来做)。代码如下// 5.cpp : 定义控制台应用程原创 2017-07-18 11:22:15 · 456 阅读 · 0 评论 -
计数排序的简单实现
计数排序的原理比较简单,但是很巧妙。有点类似于桶排序,但是有一些区别。具体思想是,给定一个数组,先统计各个元素出现的次数,用元素的值做下标,得到一个新的数组。然后扫描这个数组,对于数组的每个下标,如果它对应的值不为零,说明原来数组中就有几个这样的值。由于下标的天然递增,依次将这些值展开就得到了排序后的数组。但是计数排序有它的局限性,首先如果想用数组统计各个元素出现的次数,它的值必须是正整数原创 2017-08-24 17:23:02 · 1517 阅读 · 1 评论 -
Dijkstra求单源最短路径
思路:Dijkstra求解带权有向图的单源最短路径问题。与Bellman-Ford算法的区别是要求图中没有负的权值边。在这种情况下Dijkstra算法通常有比较好的复杂度。特别是使用堆以后。算法维护一个点集S,该集合中的结点的最短路径已经求出,算法重复从结点集V-S中选择最短路径估计最小的结点,将其加入S中,并该结点出发的所有边进行松弛。代码:// dijkstra.cpp : 定义控制台原创 2018-01-09 22:16:59 · 456 阅读 · 0 评论