- 博客(81)
- 收藏
- 关注
原创 用户线程、内核线程对应关系的三种模型
一对一模型 一个用户线程唯一的对应一个内核线程(反过来不成立,一个内核线程不一定有对应的用户线程,有可能是闲置的状态) 优点: 一个线程由于某种原因阻塞时,其他线程的执行不受影响 可以让多线程程序在多处理器的系统上有更好的表现 缺点: 许多操作系统限制了内核线程的数量,所以用户线程的数量也会收到限制 许多操作系统内核线程调度的时候,上下文切换的开销比较大,导致用户线程的执行效率下降 多对一模型 将多个用户线程映射到一个内核线程上,线程之间的切换由用户态的代码来实现,系统内核感受不到线
2021-03-22 11:25:38
3122
转载 有符号数和无符号数
刚开始学习的时候感觉这一部分有点奇妙,和我们平常认知的是不一样的,不多说,上代码: int main() { int a = -1; unsigned int b = 1; if(a > b) { std::cout << "a > b" << std::endl; } else { std::cout << "a <= b" << std::endl; } return 0; } 问题:-1为什么会大于1呢?
2021-01-12 20:33:11
930
2
原创 隐式类型转换
类型转换 1.首先是最简单的类型转换 int a = 3; double b = 3.14; int c = a + b; 不同类型的变量不能想加,所以在计算c的时候,需要将最后的结果6.14转换成6,在这里就发生了隐式转换 2.隐式转换的时机 在混合类型的表达式中,操作数转换成相同的类型 int a; double b; a >= b; 用作条件的表达式被转化为bool类型 int val; if(val) while(val) 用一表达式初始化某个变量,或者是
2021-01-12 19:47:46
327
原创 为什么C++中空类的大小是1?
#include <iostream> class A { }; int main() { std::cout << sizeof(A) << std::endl; return 0; } 运行结果: 原因: 这是实例化的原因;当然空类也是可以被实例化的,但是为了保证每个实例化在内存中都有独一无二的地址,编译器会给一个空类或者空的结构体中加入一个字节,这样空类或空结构体在实例化后在内存中就得到了独一无二的地址。 ...
2020-12-15 16:08:56
724
原创 单链表排序
使用归并排序实现:(核心就是链表合并的函数实现) class Solution { public: ListNode* sortList(ListNode* head) { if (head == nullptr) { return head; } int length = 0; ListNode* node = head; while (node != nullptr) {
2020-12-06 17:00:30
128
原创 内存池--队列
传统的内存分配: 1.外碎片 当我们只有红色部分申请4字节的内存时,其他的都使用8字节的内存,包括后序的申请都是8字节的空间,那么这个4字节的内存就分配不出去了,这个时候4字节的内存就是外碎片。 2.内碎片 大多都是内存对齐引起的,比如: struct A { int a; char b; }; 我们知道,在32位机器下,A的大小是8。所以在生成对象的时候是分配了8个字节的空间,但是里面只使用了5字节的内存空间,这就叫做内碎片。 为了实现自主的申请内存,自主的释放内存,不借助系统的操作,提出来池的
2020-12-05 18:10:30
395
原创 智能指针
当我们在C++申请内存的时候,使用下面的语句: int *p = new int; 这行代码的意思就是在堆上申请了一块内存,并用指针p去指向他: 由此,引出来堆和栈的区别: 栈:系统开辟、系统释放 堆:人为开辟、人为释放 在这里,就存在了人为的问题,如果因为忘记或者是代码跳跃的原因跳过了delete,这个时候就会发生内存泄漏。 如果设计出一种人为开辟,系统释放的机制,就可以解决内存泄漏的问题,即自主的内存回收机制–智能指针 在JAVA中,只有new关键字,没有delete关键字,因为在JAVA中,实现
2020-11-30 19:30:48
181
原创 斐波那契数列(递归、循环)
一、递归 一般来说递归实现的代码都是比较整洁的,但效率不高。 递归的逻辑也很简单,代码实现如下: long long Fibonacci_Solution1(unsigned int n) { if(n <= 0) return 0; if(n == 1) return 1; return Fibonacci_Solution1(n-1) + Fibonacci_Solution1(n-2); } 缺点如下: 虽然思路清晰,代码简洁,但是在计算的过程中发生了很多次无用的计算,下面的树形结构可
2020-11-23 15:52:58
288
原创 BF算法、KMP算法
在串和子串匹配的问题中,一般会存在两种算法:BF算法和KMP算法 比如在串:"QBFHILMEACHILK"中查看是否存在模式串"HILK"问题 首先,先说基础的BF算法,又叫做朴素匹配算法,用的是穷举的方法。 基于上面的问题,BF算法的思路是这样的: (1)首先会将主串按顺序和模式串的第一个字母进行比较 (2)接下来继续匹配,仍然没有匹配上 (3)到这一步,终于可以有匹配的元素了 但是我们可以看到,在最后一个元素K的匹配上出现了问题,那么这个时候就是没有完全的匹配上,我们还需要继续往下走。那么这个
2020-11-22 22:37:10
351
转载 C++中的void*
void的返回值是大家常见的,但是void*呢? void* say_hello(void* args) { std::cout << "Hello World!" << std::endl; return 0; } 正常来说返回void就可以了,那么我们返回void*到底是什么样的存在呢? (1)void可以指向任意类型的地址,但是带类型的指针不能指向void的地址 正常来说,如果两个指针类型不一样的话,两个指针变量是不可以直接相等的。例如int* a;float
2020-11-21 00:26:32
1862
原创 工厂模式
工厂模式:(最终目的是生成对象) 1.简单工厂模式 2.工厂方法模式 3.抽象工厂模式 举个例子来说明(吃苹果): (1)对于普通的情况来说,我们要走路,买苹果,洗苹果,最后可以吃到苹果。 (2)但是对于工厂模式来说,我们可以雇人(第三方)去做走路、买苹果、洗苹果这一系列的才操作,那么就不需要自己去做,自己只要做吃苹果这个目的就可以了,不必去关心苹果的来源。 所以说只要告诉工厂,我们需要做什么就可以了,不用关心对象的生成,这就是工厂模式的优势之处。 1.简单工厂模式 #include <iostrea
2020-11-20 11:15:13
173
原创 数据库--触发器、存储过程
触发器:当一个事件(操作)触发器触发,去执行另外一系列操作。 创建触发器: 触发器时间:before、after 触发事件:insert、delete、update 此时的@count = 1;那么我们在插入一组元素后: 我们可以看到,此时触发器触发,@count = 2; 还有一个关键字和insert类似,就是replace: 不同之处:insert插入的时候,如果主键重复,那么会提示插入失败;如果此时使用replace,那么它会先将表中的删除,然后再执行插入。当然,如果是主键不重复,那么insert
2020-11-08 12:46:19
410
原创 数据库--锁机制
1.共享读锁 共享读锁是基于存储引擎MyISAM中读锁的,MyISAM是表锁。 首先是事务A加读锁,此时自己是可以进行读操作的。 在事务B中再进行查询操作,发现仍然是可以的。 可以得出读锁read是共享读锁,即一个事务添加读锁的时候,其他的事务也可以读。 2.独占写锁 它也是基于存储引擎MyISAM中写锁。 (1)事务A自己加读锁,然后自己进行写操作,发现提示错误,是不允许的。 (2)事务A加读锁,在事务B中写操作呢? 那么会出现等待的情况,等待事务的读锁解锁之后,它才会修改成功。 (3)事务A加
2020-11-07 17:10:40
316
原创 数据库--事务
事务:一组特定的SQL语句的集合(ACID) A 原子性:要么全部执行成功,要么全部执行失败–事务回滚 C 一致性:事务执行前后完整性约束 I 隔离性:消除多个事务之间的影响 D 持久性:事务执行的结果要在磁盘上永久的保存 如果没有隔离性,会出现什么问题?(如下图123,按顺序) 1.脏读–执行中 A事务中将张三的工资由5000更新到8000,此时A时间片轮转完,交给B事务。 B事务获取到张三的工资是8000了,接下来进行一系列的操作,B时间片轮转完,交给A事务。 此时由于某种原因张三的工资暂时不能涨了,那
2020-11-05 10:36:21
361
原创 数据库--索引
索引: 索引就是一种数据结构,创建一种数据结构来提高查询的效率。 其中,两种常用的存储引擎MyISAM和INnoDB都是依靠B+树来实现的。但是底层的细节却不相同: MyISAM: B+树:数据和索引分离(数据在表中存储,在树中存储的是索引值,通过索引值找到相应的位置,然后通过叶子节点上的地址找到数据在表中的位置就可以了,叶子节点上并不直接存储其他的信息,这就是分离) INnoDB: B+树:数据当成索引的一部分存储(通过索引值找到相应的叶子节点,在叶子节点下面存储的直接就是相关信息,而不是地址值,这就是当
2020-11-04 19:03:05
149
原创 数组和指针的区别
一、概念 **数组:**用于存储多个相同类型数据的集合。 **指针:**相当于一个变量,但是和变量不一样,它存放的是其他变量在内存中的地址。 二、存储方式、赋值、求sizeof、初始化等 1.赋值 同类型的指针变量可以相互赋值,但是数组不可以,只能一个一个元素的赋值或拷贝。 2.存储方式 ·数组:数组在内存中是连续存放的,开辟一块连续的内存空间。数组是根据数组的下标进行访问的,多维数组在内存中是按照一维数组存储的,只是在逻辑上是多维的。 数组的存储空间:不是在静态区就是在栈上 ·指针:指针很灵活,它可以指
2020-10-27 21:29:53
305
原创 树的三种遍历方式
1.中序遍历思路:每到一个节点 A,因为根的访问在中间,将 A 入栈。然后遍历左子树,接着访问 A,最后遍历右子树。 #include <iostream> #include <vector> #include <stack> struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode() : val(0), left(nullptr), right(nullp
2020-10-25 17:00:38
277
原创 explicit、volatile、mutable关键字
explicit关键字:禁止隐式生成临时对象 class Test { public: explicit Test(int a):ma(a) {} private: int ma; }; 这个时候再生成Test = 30;这种对象就会报错。 volatile关键字的作用:禁止代码优化 int a = 10; int b = a; mov a ==> eax eax ==> b int c = a; mov a ==> eax eax ==> c 这个是没有代码优化的,代码优化
2020-10-05 18:56:06
199
原创 单例模式
单例模式:SingleTon,顾名思义是单个对象的模式,即一个类中只能实例化一个对象。 我们可以这样做: 1.屏蔽起来对象生成接口,即: private: 构造函数 这样就实现了只能本类类中访问,不能类外访问并生成对象 2.类中生成唯一的对象 提供一个接口返回出去供外部使用 下面来具体说说这个接口:暂且将这个接口叫做函数getInstance() 1.先说函数getInstance的范围,它的范围应该是全局共享的,最主要的是不依赖对象调用,所以我们才将函数设置成static 2.再来看看它的返回值类型,我们
2020-10-03 21:08:00
151
原创 static关键字
static修饰成员 1.修饰成员变量 成员变量就不属于对象了,属于类了:即所有对象共享的。(构造函数不能初始化静态的成员变量) 应该在类外进行初始化,间接的符合了所有对象共享的机制,类似于全局变量的定义 class Test { public: Test(int b):mb(b){} static void show() { std::cout << "ma:" << ma << std::endl; //std::cout << "mb:"
2020-09-30 18:20:52
139
原创 const关键字
1.修饰变量 在C中修饰的叫做“常变量”,可以不初始化。 在C++中修饰的叫做“常量”,必须要初始化,不可修改。 2.const的位置决定了不可修改的内容,例如: const int a = 10; const int *p = &a; const修饰是*p,即a中的内容不可修改。 3.const修饰成员变量/成员方法 在C++的类中,如果修饰成员变量,则变量会变成常量,必须要初始化 要用如下方法初始化: Test(int a):ma(a){} 修饰的成员方法变成了常方法,下面是调用规则: (1
2020-09-30 12:57:26
136
原创 深拷贝中&的作用
首先 ,我们写这样一段代码: class Good{}; A good1; A good2 = good1; 编译器不会报错,但是在运行阶段会出错。我们就可以猜测,是系统给我们提供了一种函数,让语法不出错,但是在运行的时候条件不满足无法运行。 那么这种函数的核心就是:用一个已经存在的对象来生成一个相同类型的新对象,这也正是&的作用 &的作用 1.不加&,那么程序就会陷入递归调用,当对象传递进去后,会发生: const Good rhs = good1; 这行代码是传递形参的过程,
2020-09-29 14:41:13
345
原创 Linux--kill项目
1.我们首先要知道kill命令有几种格式: kill pid ==> 默认 15 kill -9 pid ==> 强制关闭 9 kill -stop pid ==>挂起进程 19 后面的数字其实就是一些信号的宏定义,可以在/usr/include/bits/signum.h下面查询。 没有截全,可以自行查询。 根据命令格式,主函数中要保留两个参数的位置 ,所以定义成: int main(int argc,char *argv[]); 思路: 1.判断参数是否够用,不够的话提示再次输
2020-08-10 18:54:30
306
原创 僵死进程
僵死进程:一个进程执行结束,但是进程的PCB没有被系统释放。进程结束后,还要在PCB中保存ji进程退出码,以备其父进程获取。 实例:父进程未结束,子进程结束,并且父进程没有获取子进程的退出码。 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <assert.h> #include <string.h> int main() { pid_t pid = for
2020-08-10 11:55:54
119
原创 Linux--cp项目
在Linux下,cp拷贝的命令有如下格式: cp main.c main1.c cp main.c dir 文件的名字:my_cp.c 1.主函数中我们需要参数,所以应该设计成 int main(int argc,char *argv[]) { exit(0); } 其中: argv[0] : “./my_cp.c” argv[1] : “源文件的路径+文件名” argv[2] : “目的文件的路径/文件名” argc : 参念列表中的参数个数 思路: 1.判断参数列表中的个数是否够,不够的话是没有办
2020-08-09 20:04:33
446
转载 Linux中硬链接和软连接的区别和联系
首先要弄清楚,在Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号。文件属性保存在索引结点里,在访问文件时,索引结点被复制到内存在,从而实现文件的快速访问。 链接是一种在共享文件和访问它的用户的若干目录项之间建立联系的一种方法。Linux中包括两种链接:硬链接(Hard Link)和软链接(Soft Link),软链接又称为符号链接(Symbolic link)。 一、硬链接 硬链接说白了是一个指针,指向文件索引节点,系统并不为它重新分配ino
2020-08-02 23:22:02
231
原创 股票问题
给定一个数组,他的第i个元素是给定股票第i天的价格 设计一个算法来计算你能获得的最大的利润,可以尽可能的完成多次交易,但是 不可以同时参与多笔交易。必须在再次购买之前卖掉手里的股票。 int Get_Max_Money(const vector<int> &vec) { int n = vec.size(); int max = 0; for(int i = 1;i < n;++i) { if(vec[i] > vec[i-1]) { max += (v
2020-08-01 14:38:43
158
原创 进程、线程、以及区别
进程、线程: 进程是系统中正在运行的一个程序,程序一旦运行就是进程。 进程可以看作是程序执行的一个实例。进程是系统资源分配的独立个体,每个进程都拥有独立的地址空间。一个进程无法访问另一个进程的变量和数据结构。如果想让一个进程访问两外一个进程的系统资源,需要使用进程间通讯,比如管道、文件、套接字等。 一个进程可以拥有d多个线程,每个线程使用其所属进程的栈空间。 一个主要的区别就是:同一进程内的多个线程会共享部分状态,多个线程可以读写同一块内存,但是一个进程就无法访问另一进程的内存。同时,每个线程还拥有 自己的
2020-07-30 20:18:42
148
原创 发苹果的问题
问题:老师发苹果或者饼干的问题,每人至少分一个,相邻的同学分数高的一定比分数低的同学数量多,问至少老师要准备多少数量的苹果或饼干? 如果两个相同分数的人相邻,那么不要求分发数量相等。 我们从两个方向同时进行扫描,如果比前者或者后者大,我们就在之前的基础上+1 int get_apple(vector<int> &vec) { int count = 0; int n = vec.size(); if(n <= 0) return 0; vector<int> l
2020-07-27 14:17:55
284
原创 组合问题--排列数
题目:[1,2,3] [4,5] 进行组合 (1,4)(1,5)(2,4)(2,5)(3,4)(3,5) 思想就是排列树的思想 void Perm(vector<vector<int>> &arr,int k,vector<int> &tmp) { if(k == arr.size()) { int n = tmp.size(); for(int i = 0;i < n;++i) { cout << tmp[i]
2020-07-27 12:17:56
150
原创 找到对应值的位置
我们需要考虑在测试的时候需要考虑很多种的情况: 12 23 34 56 78 90 12 23 23 23 34 45 56 67 78 12 12 12 12 12 12 12 12 12 没找到 要求有重复值的时候需要返回最左边位置的下标。 int FindValue(const vector<int> &vec,int val) { int left = 0,right =vec.size()-1; while(left <= right) { int mid
2020-07-26 17:11:50
198
原创 LRU最久未用算法的设计
要求: 获取数据get(key):如果关键字存在缓存中,则获取关键字的值(总是正数),否则返回-1. 写入数据put(key,value):如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组。当缓存容量达到上限的时候,他应该在写入新的数据之前,删除最久未使用的数据,从而为新来的数据腾出空间。 进阶: 在O(1)的时间复杂度内完成这两种操作。 LRUCache cache = new LRUCache(2) /2:缓存容量/ 测试用例: 设计思想:因为时间复杂度为O(1),所以我想到了STL组
2020-07-26 15:20:30
139
原创 关联容器
无序关联容器 链式哈希表 增删查O(1) 集合中只存key unordered_set 无序的单重集合 unordered_multiset 无序的多重集合 映射表中存key、value unordered_map 无序的单重映射表 unordered_multimap 无序的多重映射表 单重中的元素是不允许重复的。 **并且后续的再插入也不能覆盖掉当前的数据。**就像下面的例子一样,王六的3000是不能将王五的数据覆盖掉的。 unordered_set<int> set1; for(int
2020-07-21 17:14:52
131
原创 标准容器中的容器适配器
设计模式,就叫做适配器模式。 怎么理解这个适配器呢? 1.适配器底层是没有自己的数据结构的,它是另一个容器的封装,他的方法全部是底层依赖的容器进行实现的。 2.没有实现自己的迭代器。 容器适配器分别有:stack、queue、priority_queue 他们的方法都是根据底层的容器决定的。 其中,queue和stack底层依赖的是deque,而priority_queue依赖的是vector。 queue和stack底层依赖的是deque理由: 1.vector的内存使用效率太低了,没有的deque好 2
2020-07-20 23:20:37
156
原创 4G虚拟内存
ALU算数逻辑单元 32位处理机:32指计算机一次处理的最多比特位 进程地址空间需要隔离,防止恶意的程序修改其他程序的内存数据,因此计算机引入虚拟地址空间。 4G虚拟地址空间布局如下: 每个程序运行起来之后,都会有自己的虚拟地址空间。所有的进程有拥有自己的用户空间,但是缺共享一个内核空间。 用户空间: 1.128M的保留区,存放的是C语言的库,不可读、不可写 我们平时将申请的临时变量指针的初始化置位NULL,可以防止后续无意使用这个指针出错。 2…text段 存放的是代码中的指令。局部变量也属于指令,但是
2020-07-10 20:20:35
1065
原创 vector向量容器
底层的数据结构:动态开辟的数组,每次以原来空间的2倍进行扩容。 容器的方法都是底层已经设计好的:#include 增加: vec.push_back(); 末尾添加元素 O(1) 导致容器扩容 vec.insert(it,20); 迭代器 it 指向的位置添加一个元素20 O(n) 导致容器扩容 vector<int> vec; for(int i = 0;i<20;i++) { vec.push_back(rand()%100 + 1); } //给奇数前添加一个比
2020-07-02 15:45:46
147
原创 BST树
BST树:二叉排序树 首先是树的基础架构,我采用的是三叉链表,即leftchild,parent,data,rightchild. 构造链表: typedef struct BstNode { ElemType data; BstNode *leftchild; BstNode *rightchild; BstNode *parent; }BstNode; typedef struct { BstNode *head; int cursize; }BSTree; 然后就是对其进行初始化和购买
2020-06-28 16:38:14
192
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅