自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(61)
  • 收藏
  • 关注

原创 设计模式-模板模式

1. 模板模式对于流程一致的一个事物,但是某些步骤的细节不一样。在基类中构造出该事物的所有流程,细节的不同在子类中实现;模板方法模式:定义一个操作中算法的骨架,但是将一些步骤延迟到子类中。模板方法使得可以不改变一个算法的机构就可以重新定义该算法的某些特定步骤;class Template {public: void question1() { cout << "question1:ABC?" << endl; } void question2() { cou

2021-02-08 21:02:35 182

原创 设计模式-原型模式

1. 原型模式如果你想从A的实例中得到一份与A内容相同的实例,并且这两个实例互不干扰,并且实例A是运行时的状态,就需要使用原型模式;原型模式与拷贝构造函数是不相同的。拷贝构造函数涉及的类是已知的, 原型模式通过指针调用clone()函数, 其涉及的类型是未知的;原型模式与直接new 出实例是不同的。用new新建对象不能获取对象当前运行时的状态。并且某些情况下,直接new新对象效率低;如果是需要一个干净的空对象时候,建议选用工厂模式或是抽象工厂模式;代码如下,让一个类继承带有clone()的接口函

2021-02-08 20:26:08 167

原创 设计模式-装饰者模式

1. 装饰者模式装饰者模式是为已有的实体动态地添加更多功能的一种设计模式。装饰者模式将每一个单独的功能都封装在单独的派生类当中,并且让这个类包装所需要装饰的对象;装饰者模式可以区分核心职责与装饰功能,简化原有的类;1)装饰类中存储着一个指针,指向要装饰的对象;2)装饰类同时又继承自要装饰的对象;这样在加糖的派生类看来,加了冰的茶依旧是茶;class Tea {public: Tea(const string& str) :name(str) {} Tea(const Tea&amp

2021-02-08 16:37:12 148

原创 设计模式-简单工厂模式与策略模式

1. 简单工 厂模式与策略模式简单工厂模式就是将生产函数变成static函数并放置在类中,这个生产函数接收外部来的信息,根据信息加工生产得到具体的派生类,并将这个派生类的指针作为函数返回;简单工厂模式结合策略模式不需要生产函数和生产类,而是设计一个context类,在这个类中封装整个产品的继承体系结构,所有对整个产品继承体系结构的操作都通过context类实现;class CashSuper {public: virtual double getResult(double money)

2021-02-08 13:45:28 88

原创 设计模式-享元模式

1. 享元模式比如围棋,10个棋子就需要实例化10个对象。这样导致内存空间浪费。 享元模式对于相同性质的棋子,会共享一个相同的对象,因此,围棋不管多少个棋子,只需要实例化黑白两个对象即可;class Website {public: virtual void use() {}};class ConcreteWebsite :public Website {private: string name;public: ConcreteWebsite(const string& str

2021-02-07 17:17:48 75

原创 设计模式-解释器模式

1. 解释器模式一个表达式中有多个语法,每一个语法就是一个派生类,有一个特定的解释;解释器模式是讲一个表达式根据语法分为多个派生类,并且对每一个派生类执行解释。下面的代码是使用解释器模式求解"a+b-c", 思路是求得的值放在栈顶;class Expression {public: virtual int interpreter(map<string, int>& var) = 0; virtual ~Expression() {}};class VarExpre

2021-02-07 15:12:27 88

原创 设计模式-访问者模式

1. 访问者模式将人分为男人和女人两种;将人的状态分为成功、失败、高兴等多种状态;代码如下:class Person {public: virtual void show(const Visitor& visitor)const {}};class Man :public Person {public: virtual void show(const Visitor& visitor) const { cout << "This is man" <&

2021-02-07 13:14:26 76

原创 C++中对multiset重载比较函数遇到的坑

一、multiset介绍multiset是关键字的集合的一个容器,允许重复关键字,multiset默认使用less 对关键字进行排序,如果需要重载自己定义的关键字比较函数,增加模板类型参数,并且传递自己定义的比教函数:class Foo {public: Foo() :data(0) {} int data;};bool compare(const Foo& lhs, const Foo& rhs) { return lhs.data < rhs.data;}mul

2021-01-28 10:37:01 1079 5

原创 for循环与while循环的区别示例

实现输出从10 到0的数字,变量要求是无符号。1. 使用for循环实现:输出会出错,因为i从0减去1时候变成最大值,代码死循环;#include <iostream>using namespace std;int main(){ for (unsigned i = 10; i >= 0; i--) cout << i << endl; return 0;}2. 使用for循环实现:代码成功输出;#include <iostr

2020-12-30 16:41:15 969

原创 signal 和 sigaction 函数

一、signal函数signal()函数只处理一次信号;signal函数每次设置具体的信号处理函数只能生效一次, 每次在进程响应处理信号的时候,随即将信号处理函数恢复到默认方式;如果想多次以相同的方式处理某个信号,通常的做法是,在响应函数开始,再次设置signal;int sigint_handler(int sig){ signal(SIGINT, sigint_handler); ...}看一个例子,此函数只能处理一次信号void sigint_handler(int signo)

2020-09-17 18:37:37 1059 3

原创 图数据结构的两种实现方式

一、 使用矩阵实现图结构使用一个数组放置搜有顶点;使用一个二维数组放置所有的边, 二维数组的两个下标指示边的两个顶点:#include <stdio.h>#include <stdlib.h>#define MAXVEX 100#define INFINITY 65535typedef char VertexType;typedef int EdgeType;typedef struct MGraph { VertexType vexes[MAXVEX];

2020-07-04 22:58:24 656

原创 不相交集(并查集)

不相交集是解决等价问题的一种有效的数据结构。一、等价关系等价关系定义如下:1) 自反性:对于所有的a属于集合S, a与a有关系;2) 对称性:如果a与b 有关系, 则b与a 有关系;3) 传递性:如果a有b 有关系, b与c有关系, 则a 与 c 有关系;在不想交集类中, 所有具有等价关系的类都在一个集合中,称为等价类; 不同的集合之间不存在等价关系;为确定a 和 b是否具有关系, 我们只需要确定a 和 b 是否属于同一个等价类中;一开始, 输入数据是N个数据, 每一个数据就是一个等价类(每

2020-07-04 18:37:16 1577

原创 随机函数生成器(rand5()与rand7()的转化)

一、C语言中随机函数rand() 和 srand()1) rand函数和srand函数介绍随机函数rand() 会随机生成一个位于0-RAND_MAX之间的整数;#include <stdio.h>#include <stdlib.h>int main(){ for (int i = 0; i < 10; i++) printf("%d ", rand()); printf("\n"); return 0;}使用rand()函数的缺点是, 对于同

2020-07-03 15:30:35 879

原创 使用malloc在堆上动态申请二维数组的三种方法

一、利用二级指针申请一个二维数组每一行的地址都是连续的,但是行与行之间的地址不连续,所有行的首地址都存放在一级指针上;int main(){ int m = 4, n = 3; int** arr = (int**)malloc(sizeof(int*) * m); for (int i = 0; i < m; i++) arr[i] = (int*)malloc(sizeof(int) * n); for (int i = 0; i < m; i++) free(arr

2020-07-03 09:31:24 517

原创 回溯算法(收费公路重建问题)

一、问题描述给出一个距离的集合D, 求出在x轴,存在哪些点能够组合成这样的距离集合;假设第一个点在0处:path[1] = 0;最后一个点是距离集合中最大的距离:path[N] = max(D);使用堆或是红黑树存放距离集合D;二、具体的代码如下#include <iostream>#include <vector>#include <set>using namespace std;bool place(vector<int>&

2020-07-02 15:13:31 666

原创 回溯算法(井字游戏)

一、问题描述三连棋双方都是智力卓越的话,很容易完成平局;在人机对战情况下, 计算机的策略是保证自己不输,并等待玩家失误的机会,当玩家失误时候, 计算机抓住这个失误并取得胜利;** 极大极小策略**使用一个求值函数来对一个位置的好坏量化;能使得计算机获胜的位置,其值+1; 平局为0; 计算机输的-1;通过考察盘面能够确定这局棋输赢的位置叫做终端位置(终端位置:有时候只下到一半,计算机发现玩家失误了,计算机一定能赢了,不用等到完全落完棋子);终端位置是使用immediateHumanWin函数或是imm

2020-07-01 17:26:36 866

原创 回溯算法(八皇后问题)

一、回溯法介绍回溯算法相当于穷举搜索的巧妙实现,穷举算法是每一种可能都去尝试, 回溯法会在尝试的过程中做出判断,当发现一些不符合标准的组合方案,直接跳过不去尝试。因此, 回溯算法能节省时间代价;回溯算法实质上还是暴力算法,但是回溯算法并不直接尝试所有的可能,会删除不可能的方案;在一步内删除一大组可能性的做法叫做裁剪;在尝试解决问题时候, 每进行一步, 都是抱着试试看的态度;如果发现当前选择并不是最好的,或者这样继续下去可定达不到目标时候, 就放弃本次操作,返回上一层操作,重新做选择;(走不通就回退

2020-07-01 00:46:04 353

原创 分治算法的运行时间

分治算法的递推公式与时间复杂度的关系根据分治算法的递推公式,可以得出分治算法的时间复杂度;并且, 对分治算法递推公式的优化, 可以使得时间复杂度得以优化;

2020-06-30 19:03:11 336

原创 连续子数组的最大和

一、问题描述给定一个数组, 找出数组的一个连续子数组, 这个子数组的和最大;遍历数组,将数组的值加入到sum中, 如果sum大于0, 继续遍历下一个数据, 如果sum小于等于0,说明前面的子数组是无用的,丢弃前面的数组,从下一个数组开始继续遍历;二、连续子数组的最大和代码实现#include <stdio.h>#include <stdlib.h>int FindBiggestSum(int* arr, int len) { int curSum = 0; int

2020-06-30 18:02:41 122

原创 数组中出现次数超过一半的数字

一、问题描述给出一个数组, 数组中存在一个数据,其出现次数超过一半的的数组长度,求出这个数据;可以使用快速排序方法, 然后中位数就是要求的数据,其时间复杂度是O(nlogn);二、基于partition的算法1) 在数组中随机寻找一个数据pivot,然后调整数组使得pivot 左边的数据都小于pivot, pivot右边的数据都大于pivot, 返回数据pivot的下标索引index;如果index == mid,即找到了问题的解;如果index > mid, 在左边集合中继续寻找inde

2020-06-30 16:13:26 105

原创 最近点问题(分治算法)

一、问题描述对于平面上的一些点对:p1, p2, …,pn, 找出两个点,使得这两个点之间的距离最小;解题思路:首先对所有的点按照x坐标排序, 然后按x坐标在pivot处将点集二分为坐标点集S1和右边点集S2;先递归求得左边点集的最小距离min_left, 然后递归求得右边点集的最小距离min_right; 比较左右点集的最小距离min = min(min_left, min_right);此外, 靠近pivot左右min的区域(pivot-min, pivot+min)的区域,存在点对距离小于

2020-06-30 14:59:31 800

原创 快速选择问题(top k问题)

一、问题描述找到一个数组中第k大的数据;使用分治法,参考快速排序的思想, 找原数组中找到一个枢纽元pivot, 将数组分为S1, pivot, S2; S1中的数据都是小于pivot, S2中的数据都是大于pivot;如果pivot 就是第k个数组,直接返回;如果S1中数据多于k, 第k个数据存在于S1, 递归调用S1;如果k存在于S2, 第(k-pivot-S1)个数据就是解, 递归调用S2;二、代码快速选择问题的具体代码如下;该算法时间复杂度是O(n), 因为每一次分治实际上只有一次递归

2020-06-30 13:36:05 322

原创 近似装箱问题

一、问题描述设给定N项物品, 大小为s1, s2, s3, …, sn, 每个物品的都不超过1; 现有大小为1的箱子若干个, 将物品装入箱子中, 尽量使用少的箱子装满所有物品;实例:现有一列物品:0.2, 0.5, 0.4, 0.7, 0.1, 0.3, 0.8;其中一种装箱方案如下所示:装箱问题是一个NP完全问题, NP完全问题的最优解的时间复杂度不能是一个二项式的(通常NP问题的时间复杂度是指数型的);因此, 当获知这是一个NP完全问题, 就要考虑不纠结于求解其最优解,通常求解器近似解,并且近

2020-06-29 21:09:49 1822 1

原创 简单的优先队列(C语言实现)

#include <stdio.h>#include <stdlib.h>#define N 16int arr[N];int len;inline int leftChild(int i) { return 2 * i + 1;}inline int Parent(int i) { if (i < 1) return -1; //当i == 0的时候,返回-1表示出错, 否则push函数的while循环会死循环 return (i - 1) /

2020-06-28 23:07:43 599

原创 算法导论_17.1-17.3平摊分析

平摊分析:执行一系列数据结构操作所需要的时间是通过对执行的所有单个操作求平均得出的;即单个操作所需的时间 = 所有操作消耗的时间/操作次数;即便单个操作的代价很大, 但是平均代价很小;平摊分析与平均情况分析的不同之处是平摊分析不涉及概率, 即使在最坏的情况下, 每个操作都具有平均性能;举例说明平摊分析与平均情况分析的区别:例如有三个操作,耗时是1, 2, 3; 三个操作被执行的频率是0.5, 0.2, 0.3;平摊分析不考虑频率:(1+2+3)/3 = 2;平均情况分析:1×0.5 + 2×0.

2020-06-28 13:06:33 2001 1

原创 算法导论_16.5一个任务调度问题

一、任务调度问题描述单个处理器对若干个单位时间任务进行最优调度, 其中每个任务都有一个截止期限和超时惩罚。单个处理器上具有期限和惩罚的单位时间任务调度的输入如下,有三个数组:1) 包含有n个单位时间任务的集合S = {a1, a2, a3, …, an};2) n个整数值的期限d1, d2, …, dn, 即任务ai要求在di之前完成;3) n个非负的权值(惩罚代价)w1, w2, w3,…, wn;如果ai在di之前没有被调度,就会有惩罚wi;目标:找出一个S的调度,使得总的惩罚最小;考虑一

2020-06-27 22:54:43 2475

原创 排序算法实现总结

一、快速排序1) 实现一:当将arr的第一个元素作为标准key, 需要从arr的尾端先做比较,这是因为作为标准的key,在函数partition的循环过程中一直在被移动,直到i == j的时候,key的值才固定。如果从arr首端开始比较,会出现错误;此函数实现使用了swap函数;void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp;}int partition(int *arr, int i, int j) { int k

2020-06-27 19:01:30 254

原创 算法导论_16.4 贪心法的理论基础(拟阵)

一、贪心算法的理论基础贪心算法的理论,在确定何时能够产生最优解的时候非常有用,其实用到一种叫做拟阵的组合结构。1) 拟阵:一个拟阵是满足下列条件的一个序对M= (S,e);1)S 是一个有穷非空集合;2) e是S的一个非空子集族,称为S的独立子集;具有遗传性质, 如果A是B的子集, 并且B是e的一个成员,则A是e的一个成员;3) 拟阵具有交换性:如果A是e的成员, B是e的成员, |A|<|B|, 则有某个元素x 是(B-A), 使得A+{x} 是e的成员;拟阵的一个实例,图的拟阵MG

2020-06-27 17:15:31 1497

原创 算法_哈夫曼编码

一、 什么是哈夫曼编码计算机中使用二进制编码字符;哈夫曼编码是通过构造哈夫曼树得到的, 哈夫曼树是通过贪心算法得到的;贪心算法构造哈夫曼树:将字符出现的次数作为哈夫曼树的权值,按照贪心算法,选择权值最小的两个结点,成为一个数的左右结点;左右子结点的权值变为子树根的权值;然后在余下的结点中递归选用最小的两个结点;根据哈夫曼树得到哈夫曼编码:从根开始, 遇到左分支编码为0, 遇到右分支编码为1;对于同一个编码, 哈夫曼编码不唯一,但是都能正常工作;哈夫曼编码是一种变长编码,权值越大的字符,其编

2020-06-27 14:47:08 2668

原创 算法导论_15.2矩阵链乘法

一、问题描述对于矩阵A(2, 3) 和矩阵A(3, 4)相乘,总共需要做2×3×4 = 24次乘法;因此对于三个矩阵A1,A2,A3做乘法, 不同的乘法次序会得到不同次数的乘法运算;例如, 三个矩阵维数是:10×100, 100×5, 5×50((A1, A2), A3): 需要的乘法次数是:(10×100×5)+(10×5×50) = 7500次乘法运算;(A1, (A2, A3)):需要的乘法次数是:(10 ×100×50) + (100×5×50) = 75000次乘法运算;从上面可知,

2020-06-25 17:11:38 1299

原创 算法导论_15.1装配线调度

一、装配线调度问题描述总共有n个装配站;底盘进入到装配线1和装配线2的时间记录在二元数组e[2]上;底盘在装配线1和装配线2上每个站的时间记录在数组a1[n] 和a2[n]上;底盘在每个站上换装配线的时间记录在t1[n-1], t2[n-2]上;(在最后一个站时候, 不需要换装配线了,所以数组只有n-1个数据)底盘离开装配线的时间存放在二元数组x[2]上面;求得的最优解记录在数组f1[n] 和f2[n]上;每次做出的选择记录在数组l1[n-1], l2[n-1]上;(在最后一个站的时候, 不需

2020-06-25 14:00:58 1119

原创 区分共享文件的两种形式

一、引言共享文件至的是,两个不同的文件描述符,但是引用的是同一个文件,就叫做文件在文件描述符fd1和fd2之间共享;操作系统中主要是三种数据结构表示文件;1) 文件描述符表,每个进程都有自己的文件描述符表;2) 内核中的文件表, 文件表中有文件偏移位置, 指向v节点表的指针;3) 内核中的v节点表, v节点表有大部分文件的信息;二、共享文件的两种表现形式1) 通过open打开两个相同的文件两个文件描述符指向不同的文件表,这种形式虽然共享文件,但是不共享文件位置偏移;对不同的文件描述符进行操作

2020-06-23 14:52:04 1126 1

原创 文件元属性中st_mode详解

一、 文件元数据操作系统中, 有关文件的大部分属性存放在磁盘中的i节点, 其余的文件信息i节点编号和文件名称存放在其父目录的目录项中;可以使用系统调用stat或是lstat得到一个文件的所有属性,这两个函数返回的是一个struct stat的数据结构。本文主要讲解关于struct stat数据结构的第一个字段st_mode的介绍。st_mode中有关于文件类型和文件访问访问权限的信息, st_mode是16位;二、 st_mode的介绍15-12位:使用这4各位表示7种文件类型11-9位:设置用户

2020-06-23 11:21:31 1848

原创 APUE_第5章 标准IO库

5.1 引言相对于底层的unix IO, 标准IO库处理很多细节,例如缓冲区分配, 以优化长度执行IO。 这些处理使得用户不用担心如何选择正确的缓冲区块长度(还记得3.9节IO效率的讨论, 当缓冲区块长度等于磁盘块长度的时候, IO效率最好);5.2 流和FILE对象底层的unix IO函数都是针对文件描述符的,函数第一个参数文件描述符fd;对于标准IO库, 其操作是围绕流进行的。使用标准IO库打开或创建一个文件的时候,即将一个流与一个文件相关联;标准IO文件流可用于单字节和宽字节字符集。流动定

2020-06-23 09:56:52 179

原创 APUE_第4章 文件和目录

4.1 文件和目录stat数据结构中包含有文件的基本信息,4.2 stat, fstat, lstat函数//restrict关键字表明,只能通过这一个指针访问这一个对象,这样有利于编译器优化,不会产生内存别名;int stat(const char *restrict pathname, struct stat *restrict buf);int fstat(int fd, struct stat *buf);int lstat(const char *restrict pathname,

2020-06-22 15:09:01 211

原创 APUE_第3章 文件I/O

3.1 引言底层的unix IO主要有6个函数:open, close, read, write, lseek, stat. 这6个函数都是系统调用,并不带缓冲区;本章的函数都是不带缓冲区的, 不带缓冲是指每个read, write都是内核中的一个系统调用,在用户层没有缓冲区;一旦涉及在多个进程之间共享资源, 就需要考虑原子操作;3.2 文件描述符文件描述符的变化范围是:0-OPEN_MAX;所有的打开文件都是通过文件描述符引用的, 内核是向打开的进程返回文件描述符的;3.3 open函数i

2020-06-21 16:25:22 191

原创 深入理解计算机系统_第10章 系统级I/O

区分系统级unix I/O函数和高级的标准I/O函数;有时候必须使用系统级unix I/O 函数, 例如, 标准I/O库没有提供读取文件元数据的方式,所以必须使用系统unix I/O函数(stat); 访问网络文件socket的时候, 使用标准IO函数访问存在不足值得风险;10.1 Unix I/O将所有的I/O 设备抽象问文件, 将所有的输入、输出动作抽象为读、写操作;因此, linux内核只需要提供一个低层次的接口——unix I/O, 就可以对所有的设备以统一的格式进行访问;1) 打开文件应

2020-06-20 21:01:48 349

原创 深入理解计算机系统_第8章 异常控制流

异常控制流发生在计算机系统的各个层次:1) 硬件层面, 硬件检测到事件会触发控制,跳转到异常处理程序;2) 操作系统层面, 内核通过上下文切换,实现进程切换,也是异常控制流;3) 应用程序层面, 信号的信号处理程序,也是异常控制流;语言层面的try, catch, throw也是异常控制流;非本地跳转setjmp, longjmp也是异常控制流;8.1 异常异常就是控制流中的突变,用来响应处理器状态的某些变化;异常事件可能是与当前执行指令相关: 虚拟内存缺页、算术溢出、一条指令试图除以零;

2020-06-14 21:44:13 1921 1

原创 深入理解计算机系统_第7章 链接

链接动作可以出现在程序的三个时期:1) 链接可以执行于编译时,即在源代码被翻译成机器代码的时候;2) 链接可以执行于加载的时候, 即程序从硬盘被加载到内存的过程中;3) 链接可以执行于运行的时候, 即由应用程序来执行链接工作;链接器的出现使得分离编译成为可能,将一个大型程序分解成各个模块,每一个模块单独编译。再将各个模块编译后的文件链接到一起,得到最终的二进制文件。分离编译的好处是,如果大型程序中某一个模块的源代码修改了, 只需要重新编译这部分代码和重新链接。未修改部分的代码不再需要重新编译。7.

2020-06-12 23:24:10 880

原创 深入理解计算机系统_第6章 存储器层次结构

6.2 局部性程序的局部性:倾向于引用邻近于其他最近引用过的数据项的数据项,或者引用最近引用过的数据项本身。局部性的两种不同形式:时间局部性和空间局部性时间局部性:被引用过一次的内存位置很可能在不远的将来再次被引用;空间局部性: 如果一个内存位置被引用了, 那么程序可能在不久的将来引用附近的一个内存位置;有良好局部性的程序运行得更快;6.2.1 对程序数据引用的局部性int sumvec(int v[N]){ int i, sum = 0; for(i = 0; i < N; i+

2020-06-11 18:03:36 401

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除