关于c:用C程序打印空心星形-右倒置直角三角形

解题思路用10*10网格 第0行打印0个空格10个星 第1行打印1个空格 第2行打印2个空格 以此类推 从第1行开始列如果(j==0||j==10-i-1)则打印星,否则打印空格 /*打印如下:********** * * * * * * * * * * * * * * ** * */#include <stdio.h>int main(){ int i; int j; for (i = 0; i < 10; i++) { for (j = 0; j < i; j++) { printf(" "); } for (j = 0; j < 10; j++) { if (i == 0) { printf("*"); } else if (j == 0 || j == 10 - i - 1) { printf("*"); } else { printf(" "); } } printf("\n"); } return 0;}

March 14, 2021 · 1 min · jiezi

关于stl:STL核心编程

title: STL外围编程categories: [C++]tags: [编程语言]date: 2021/03/13 作者:hackett 微信公众号:加班猿 容器序列式容器string容器类外部封装了char ,治理这个字符串,是一个char 型的容器 构造函数 string(); string(const char *s); string(const string& str); string(int n , char c); 赋值操作 string& operator=(const char* s); string& operator=(const string &s); string& operator=(char c); string& assign(const char* s); string& assign(const char *s , int n); string& assign(const string& s); string& assign(int n , char c); 字符串拼接 string& operator+=(const char* str); string& operator+=(const char c); string& operator+=(const string& str); string& append(const char *s); string& append(const char *s, int n); string& append(const string &s); string& append(const string &s, int pos, int n) ...

March 13, 2021 · 3 min · jiezi

关于c++:C核心编程

title: C++外围编程categories: [C++]tags: [编程语言]date: 2021/03/11 作者:hackett 微信公众号:加班猿 内存散布模型堆区:new/delete,由程序员调配和开释,若程序员不开释,程序完结由操作系统回收栈区:寄存函数的参数值,局部变量等;由编译器主动调配开释动态存储区:寄存全局动态变量、部分动态变量、全局变量以及虚函数表常量存储区:全局常量、函数指针、常量数组、对函数指针代码区:寄存函数体的二进制代码援用必须初始化,初始化后不可扭转常量援用润饰形参实质是一个指针常量函数默认参数(语法:返回值类型 函数名 (参数 = 默认值){})函数占位参数(语法:返回值类型 函数名 (数据类型))函数重载:同一作用域下函数名雷同函数参数类型不同/个数不同/程序不同构造函数能够有参数,因而能够产生重载 调用对象时主动调用结构,无需手动调用,而且只会调用一次 调用规定如果用户定义有参构造函数,c++不在提供默认无参结构,然而会提供默认拷贝结构 如果用户定义拷贝构造函数,c++不会再提供其余构造函数 虚析构和纯虚析构虚析构语法:virtual ~类名(){} 纯虚析构语法:virtual ~类名() = 0; 抽象类,无奈实例化对象 共性解决父类指针开释子类对象 都须要有具体的函数实现 深/浅拷贝浅拷贝:简略的复制拷贝操作 深拷贝:在堆区从新申请内存,进行拷贝操作;属性有在堆区开拓的,肯定要本人提供拷贝构造函数,避免浅拷贝带来的反复开释堆区问题 初始化列表语法:构造函数():属性1(值1),属性2(值2),属性3(值3)… 动态成员动态成员变量所有对象共享同一份数据 在编译阶段分配内存 类内申明,类外初始化 动态成员函数所有对象共享一个函数 动态成员函数只能拜访动态成员变量 this指针定义this指针指向被调用的成员函数所属的对象 this指针是隐含每一个非动态成员函数内的一种指针 用处形参和成员变量同名时,能够用this指针来辨别 在类的非动态成员函数中返回对象自身,可应用return *this const常函数const在成员函数后:void func() const{} 常函数内不能够批改成员属性 成员属性申明前加mutable关键字,在常函数中仍然可批改 常对象const在申明对象前 常对象只能调用常函数 友元friend作用:让一个类或者函数拜访另一个类中的公有成员全局函数 类 成员函数 运算符重载加号实现两个自定义数据类型相加 左移能够输入自定义数据类型(配合友元) 递增实现本人的整型数据(前置递增返回援用,后置递增返回值) 赋值类中有属性指向堆区,做赋值操作时也会呈现深浅拷贝问题 关系让两个自定义数据类型对象进行比照操作 函数调用应用形式十分像函数的调用,因而称为仿函数,没有固定写法,非常灵活 继承继承形式public 继承下来的成员属性放弃不变 protected 继承下来的成员属性变为protected private 继承下来的成员属性变为private 对象模型父类公有成员被子类继承下来,被编译器暗藏后拜访不到 结构和析构程序先调用父类的构造函数,再调用子类的构造函数,析构是先调用子类的析构函数,再调用父类的析构函数 同名成员/动态成员解决拜访子类:间接拜访 ...

March 13, 2021 · 1 min · jiezi

关于c:用C程序打印数字右直角三角形

解题思路用10*10网格 第一行9个空格(10-1行号)和一个数字(1行号) 第二行8个空格(10-2行号)和两个数字(2行号) 第三行7个空格(10-3行号)和三个数字(3行号) 第四行6个空格(10-4行号)和四个数字(4行号) 以此类推… 从法则来看,每行打印的都与行号无关 /*打印如下: 1 12 123 1234 12345 123456 1234567 12345678 12345678912345678910 */#include <stdio.h>int main(){ int i; int j; for (i = 1; i <= 10; i++) { for (j = 0; j < 10 - i; j++) { printf(" "); } for (j = 1; j <= i; j++) { printf("%d", j); } printf("\n"); } return 0;}

March 13, 2021 · 1 min · jiezi

关于c:linux工具netstat-工具使用

March 13, 2021 · 0 min · jiezi

关于c:用C程序打印星形右直角三角形

解题思路用10*10网格 第一行9个空格(10-1行号)和一个星号(1行号) 第二行8个空格(10-2行号)和两个星号(2行号) 第三行7个空格(10-3行号)和三个星号(3行号) 第四行6个空格(10-4行号)和四个星号(4行号) 以此类推… 从法则来看,每行打印的都与行号无关 /*打印如下: * ** *** **** ***** ****** ******* ******** ******************* */#include <stdio.h>int main(){ int i; int j; for (i = 1; i <= 10; i++) { for (j = 0; j < 10 - i; j++) { printf(" "); } for (j = 0; j < i; j++) { printf("*"); } printf("\n"); } return 0;}

March 11, 2021 · 1 min · jiezi

关于c++:C注释的常见用法

C++正文的常见用法本文参考:https://www.cnblogs.com/aspir... 1. 根本用法单行正文: // //多行正文: / ..... / /* */2. 几种常见的正文标准文件头的标注 /** * @file Example.h * * @brief 对文件的简述 * * Details. * * * * @author XX.xx * * @email example@126.com * * @version 1.2.3.1(版本号) * * @date example@126.com * * @license GNU General Public License (GPL) * */命名空间的标注 /** * @brief 命名空间的简略概述 \n(换行) * 命名空间的具体概述 */namespace example { }类的标注 /** * @brief 类的简略概述 \n(换行) * 类的具体概述 */class example { };函数的标注 ...

March 10, 2021 · 1 min · jiezi

关于c++:IassPassSasS三种云服务区别

咱们能够把云计算了解成一栋大楼,而这栋楼又能够分为顶楼、两头、低层三大块。那么咱们就能够把Iass(基础设施)、Pass(平台)、Sass(软件)了解成这栋楼的三局部。基础设施在最下端,平台在两头,软件在顶端。别的一些“软”的层能够在这些层下面增加。 接下来咱们再别离用实例给大家介绍下Iass、Sass、Pass。 IaaS:Infrastructure-as-a-Service(基础设施即服务) 第一层叫做IaaS 举例:几年前如果你想在办公室或者公司的网站上运行一些企业应用,你须要去买服务器,或者别的昂扬的硬件来管制本地利用,能力让你的业务失常运行。 但当初能够租用IaaS公司提供的场外服务器,存储和网络硬件。这样一来,便大大的节俭了保护老本和办公场地。 PaaS:Platform-as-a-Service(平台即服务) 第二层就是所谓的PaaS 举例: PaaS公司在网上提供各种开发和散发利用的解决方案,比方虚构服务器和操作系统。这节俭了你在硬件上的费用,也让扩散的工作室之间的单干变得更加容易。网页利用治理,利用设计,利用虚拟主机,存储,平安以及利用开发合作工具等。 SaaS:Software-as-a-Service(软件即服务) 第三层也就是所谓SaaS 举例:生存中,简直咱们每一天都在接触SaaS云服务,比方:咱们平时应用的苹果手机云服务,网页中的一些云服务等。如果你要买网站服务器、云服务器,能够搜寻微信小程序“云来米”,邀请码8KY4FQ4,助你轻松上云。 Iaas和Paas之间的比拟 PaaS的次要作用是将一个开发和运行平台作为服务提供给用户,而IaaS的次要作用是提供虚拟机或者其余资源作为服务提供给用户。接下来,将在五个方面对PaaS和IaaS进行比拟: 1) 开发环境:PaaS根本都会给开发者提供一整套包含IDE在内的开发和测试环境,而IaaS方面用户次要还是沿用之前比拟相熟那套开发环境,然而因为之前那套开发环境在和云的整合方面比拟欠缺,所以应用起来不是很不便。 2) 反对的利用:因为IaaS次要是提供虚拟机,而且一般的虚拟机能反对多种操作系统,所以IaaS反对的利用的范畴是十分宽泛的。但如果要让一个利用能跑在某个PaaS平台不是一件轻松的事,因为不仅须要确保这个利用是基于这个平台所反对的语言,而且也要确保这个利用只能调用这个平台所反对的API,如果这个利用调用了平台所不反对的API,那么就须要对这个利用进行批改。 3) 凋谢规范:尽管很多IaaS平台都存在肯定的公有性能,然而因为OVF等协定的存在,使得IaaS在跨平台和防止被供应商锁定这两面是稳步前进的。而PaaS平台的状况则不容乐观,因为不论是Google的App Engine,还是Salesforce的http://Force.com都存在肯定的公有API。 4) 整合率和经济性: PaaS平台整合率是十分高,比方PaaS的代表Google App Engine能在一台服务器上承载成千上万的利用,而一般的IaaS平台的整合率最多也不会超过100,而且广泛在10左右,使得IaaS的经济性不如PaaS。 5) 计费和监管:因为PaaS平台在计费和监管这两方面不仅达到了IaaS平台所能企及的操作系统层面,比方,CPU和内存的使用量等,而且还能做到利用层面,比方,利用的反应时间(Response Time)或者利用所耗费的事务多少等,这将进步计费和治理的精确性。

March 10, 2021 · 1 min · jiezi

关于c#:C-学习笔记二-C-的基础语法

C# 是由 C 语言和 C++ 演变而来,属于 C 语言系,并兼容了 许多 Java 的个性,C/C++,Java 程序员能够很容易了解 C# 的内容。 标识符和关键字标识符是程序员一块内存起的一个名字(这块内存能够是一个变量,一个类或一个办法)。在 C# 中,标识符必须是一个残缺的词汇(即标识符中不能蕴含空格),由 Unicode 字符组成( C 语言只能蕴含英文字母,数字和下划线),并且以字母或下划线结尾。 关键字对于编译器而言有着非凡的含意,它通常用于指定编译器的零碎行为。关键字都被保留,这意味着你不能在标识符中应用它们。 不过,有的人天生就喜爱打破常规,他就要用关键字作为标识符,能够,微软也为这类人提供了办法,那就是在关键字前加上一个 @ 。这样他就能够被用作标识符了,比方: int @int = 0;这样你就定义了一个名字叫做 int 的 int 类型(整型)的变量。 须要留神的是,加了 @ 的标识符和未加 @ 的标识符含意完全相同。字面值,标点符号和运算符字面值是嵌入到程序中的原始的数值。 标点符号帮忙划分程序的构造。 操作符转换以及连贯所有的表达式。 正文C# 反对单行和多行正文。别离用符号 // 和 /**/ 示意,这一点与 C 语言齐全一样。

March 10, 2021 · 1 min · jiezi

关于c:用C程序打印数字左倒置直角三角形

解题思路用10*10网格 第一行10个数字(0行号) 第二行9个数字(1行号) 第三行8个数字(2行号) 第四行7个数字(3行号) 以此类推… 从法则来看,每行打印的都与行号无关 /* 打印如下:11111111112222222223333333344444445555556666677778889910 */#include <stdio.h>int main(){ int i; int j; int count = 1; for (i = 0; i < 10; i++) { for (j = 0; j < 10 - i; j++) { printf("%d", count); } printf("\n"); count++; } return 0;}

March 10, 2021 · 1 min · jiezi

关于c++:大括号之谜C的列表初始化语法解析

摘要:有敌人在应用std::array时发现一个奇怪的问题:当元素类型是复合类型时,编译通不过。有敌人在应用std::array时发现一个奇怪的问题:当元素类型是复合类型时,编译通不过。 struct S { int x; int y;};int main(){ int a1[3]{1, 2, 3}; // 简略类型,原生数组 std::array<int, 3> a2{1, 2, 3}; // 简略类型,std::array S a3[3]{{1, 2}, {3, 4}, {5, 6}}; // 复合类型,原生数组 std::array<S, 3> a4{{1, 2}, {3, 4}, {5, 6}}; // 复合类型,std::array,编译失败! return 0;}按说std::array和原生数组的行为简直是一样的,可为什么当元素类型不同时,初始化语法还会有差异?更蹊跷的是,如果多加一层括号,或者去掉内层的括号,都能让代码编译通过: std::array<S, 3> a1{{1, 2}, {3, 4}, {5, 6}}; // 原生数组的初始化写法,编译失败!std::array<S, 3> a2{{{1, 2}, {3, 4}, {5, 6}}}; // 外层多一层括号,编译胜利std::array<S, 3> a3{1, 2, 3, 4, 5, 6}; // 内层不加括号,编译胜利这篇文章会介绍这个问题的原理,以及正确的解决形式。 ...

March 8, 2021 · 3 min · jiezi

关于c++:设计模式之单例工厂发布订阅者模式设计模式

设计模式之单例、工厂、公布订阅者模式设计模式单例模式 保障一个类仅有一个实例,并提供一个该实例的全局拜访点 在软件系统中,常常有这样一些非凡的类,必须保障他们 在零碎中只存在一个实例,能力确保它们的逻辑正确性, 以及良好的效率 利用场景:DBPool 、读取配置文件 单例模式分类:1、懒汉式 -- 须要应用单例的时候,才进行初始化2、饿汉式 -- 未调用单例的时候,曾经进行初始化写一个单例模式的demo#include <iostream>#include <mutex>#include <thread> using namespace std; //设计线程的个数#define PTHREAD_NUM 20//懒汉式 饿汉式 单例模式的选型#define SINGELTON_SELECTOR 0 //单例模式 #if SINGELTON_SELECTOR //懒汉式 -- 调用的时候才初始化class Singleton{ private: Singleton(){ cout<<"Singleton construct 1111\n"; } ~Singleton(){ cout<<"Singleton destruct 1111\n"; } //禁止拷贝结构 Singleton(const Singleton &si) = delete; //禁止等号赋值 Singleton & operator=(const Singleton &si) = delete; public: static Singleton * getInstance(){ static Singleton m_singleton; return &m_singleton; }}; #else //饿汉式 -- 调用之前就曾经初始化好,调用的时候间接返回地址class Singleton{ private: Singleton(){ cout<<"Singleton construct 2222\n"; } ~Singleton(){ cout<<"Singleton destruct 2222\n"; } //禁止拷贝结构 Singleton(const Singleton &si) = delete; //禁止等号赋值 Singleton & operator=(const Singleton &si) = delete; static Singleton m_singleton; public: static Singleton * getInstance(){ return &m_singleton; }}; Singleton Singleton::m_singleton; #endif //定义一个互斥锁,保障只有一个线程在打印 单例变量的地址static mutex m;void print_address(){ Singleton* singleton = Singleton::getInstance(); m.lock(); cout<<singleton<<endl; m.unlock();}//测试单例模式void test_singleton(){ thread threads[PTHREAD_NUM]; for(auto &t : threads) t = thread(print_address); for(auto &t : threads) t.join();} int main(int argc,char * argv[]){ cout<<"main\n"; test_singleton(); } 工厂模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化提早(目标:解耦,伎俩:虚函数)到子类在软件系统中,常常面临着创建对象的工作;因为需要的 变动,须要创立的对象的具体类型常常变动应用工厂模式提供一种“封装机制”来防止客户程序和这种“具 体对象创立工作”的紧耦合 来解决这个问题 ...

March 7, 2021 · 3 min · jiezi

关于c:用C程序打印星形左倒置直角三角形

解题思路用10*10网格 第一行10个星(0行号) 第二行9个星(1行号) 第三行8个星(2行号) 第四行7个星(3行号) 以此类推… 从法则来看,每行打印的都与行号无关 /* 打印如下:************************************ */#include <stdio.h>int main(){ int i; int j; for (i = 0; i < 10; i++) { for (j = 0; j < 10 - i; j++) { printf("*"); } printf("\n"); } return 0;}

March 7, 2021 · 1 min · jiezi

关于c:linux工具使用介绍iperf3网络质量测试工具介绍

March 6, 2021 · 0 min · jiezi

关于c:货拉拉女生跳车思考

请让我从多年前的一段个人经历讲起。 过后我住在离机场特地近的小区,相对间隔只有20公里。你可能认为我往返机场很不便,但理论体验恰恰相反,每次出差回京坐出租,其实是十分苦楚的过程。 过后没有叫车APP,出租车司机想在机场拉到一个乘客,往往要消耗几个小时的工夫排队。试想,如果司机接到的乘客间隔过近,在起步价只有10块钱的状况下,实际上司机就等于半天白干。 所以每次司机排到相似我这样一位乘客,他苦楚的表情,能够让人一年难忘。在乘客上车的第一分钟,少数司机就会开始叹气和埋怨,而后试图压服乘客,能不能多给点钱。 你当然能够回绝司机加价的提议,而这个回绝是齐全合乎规定的。 然而,这样做的结果,后续的事件有很大概率是司机胡作非为的踩刹车或者减速。或者拿出烟猛抽,齐全忽视你表白了不喜爱烟味的揭示。 为了防止麻烦,一些乘客在上车时立即说,徒弟,我晓得这趟活太近了,我给你加5块或者10块钱。 还有很多人,对规定是较真的,忽视司机的埋怨,甚至威逼去平台投诉。 在这种出租车计价体系中,如果一个喜爱埋怨的司机,碰到了一个喜爱较真的乘客,抵触就是必然的。而如果一个零碎规定人造会造成潜在抵触,放在一个更大的数据样本下,其实出小事就是早晚的事件。 正如过后出租车不喜爱拉机场的小活,货拉拉的司机也不喜爱40分钟的收费期待,而咱们须要认清的是,造成他们情绪不佳的根本原因,是计价零碎施加的,不是顾客,也不是司机。 心愿多赚一点的司机,较真节约的顾客,实际上是零碎不合理规定的牺牲品。 此次事件中,货车司机抄近路,不理睬顾客的停车诉求,和多年前机场猛踩油门的出租司机,也并没有什么两样。 货拉拉40分钟的收费期待,是平台吸引顾客的伎俩,但货车司机并不喜爱这条规定。在理论状况下,这条规定无时无刻不在引发买卖双方的对抗。在长沙,这种对抗,一方曾经付出了生命,另一方可能是牢狱之灾。 这里不得不再回到「科技向善」主题,奇客故事始终反复一个观点,科技互联网平台向善,不应该变成企业拿钱做慈悲。科技向善,应该是去思考经营一个「向善」的零碎,一个让生态各方都受害的零碎,而非一个平台通过“鱼肉宰割”弱势一方,利益最大化的零碎。 互联网平台有人造垄断性,有更大的数据样本,若规定具备哪怕一丁点“不够向善”的隐患,都可能后续引发劫难。 咱们不能说万分之一的概率就是能够漠视的概率,因为其背地或者就是生命的代价。 货拉拉作出抵偿了,要装摄像头了,要录音了,这些都很好,然而如果零碎没有「向善」的价值观,只去着眼于技术的规定,喜剧最初还会换一种形式产生。 向善的零碎才是要害。

March 5, 2021 · 1 min · jiezi

关于c:用C程序打印星形左直角三角形

解题思路用10*10网格 第一行一个星(1行号) 第二行两个星(2行号) 第三行三个星(3行号) 第四行四个星(4行号) 以此类推… 从法则来看,每行打印的都与行号无关。 /*打印如下:******************************************************* */#include <stdio.h>int main(){ int i; int j; for (i = 1; i <= 10; i++) { for (j = 1; j <= i; j++) { printf("*"); } printf("\n"); } return 0;}

March 5, 2021 · 1 min · jiezi

关于c:C语言二叉树的创建和遍历

二叉树的创立和遍历: #include<stdio.h>#include<stdlib.h>#define OK 1#define OVERFLOW -2typedef int Status;typedef char ElemType;typedef struct BiNode{ ElemType data; struct BiNode* lchild, * rchild;}BiTNode, *BiTree;Status Create_Tree(BiTree *T); //创立Status PreBiTree_Traverse(BiTree T); //结构和遍历思维:递归Status InBiTree_Traverse(BiTree T);Status PostBiTree_Traverse(BiTree T);int main(){ BiTree T; int n; printf("请输出字符(#示意空指针):"); Create_Tree(&T); printf("1.前序遍历 2.中序遍历 3.后序遍历\n"); printf("请输出遍历形式:"); scanf("%d", &n); switch (n) { case 1:PreBiTree_Traverse(T); break; case 2:InBiTree_Traverse(T); break; case 3:PostBiTree_Traverse(T); break; } return 0;}Status Create_Tree(BiTree *T)// 前序结构{ char ch; scanf("%c", &ch); if (ch == '#') //用#代表NULL,即虚结点 { *T = NULL; } else { *T = (BiTree)malloc(sizeof(BiTNode)); if (!*T) exit(OVERFLOW); (*T)->data = ch; Create_Tree(&(*T)->lchild); Create_Tree(&(*T)->rchild); } return OK;}Status PreBiTree_Traverse(BiTree T) //前序遍历{ if (T == NULL) return OVERFLOW; printf("二叉树的数据为:%c\n", T->data); PreBiTree_Traverse(T->lchild); PreBiTree_Traverse(T->rchild); return OK;}Status InBiTree_Traverse(BiTree T) //中序遍历{ if (T == NULL) return OVERFLOW; InBiTree_Traverse(T->lchild); printf("二叉树的数据为:%c\n", T->data); InBiTree_Traverse(T->rchild); return OK;}Status PostBiTree_Traverse(BiTree T) //后序遍历{ if (T == NULL) return OVERFLOW; PostBiTree_Traverse(T->lchild); PostBiTree_Traverse(T->rchild); printf("二叉树的数据为:%c\n", T->data); return OK;}

March 4, 2021 · 1 min · jiezi

关于c#:理解ASPNET-Core-中的WebSocket

在本文中,咱们将具体介绍RFC 6455 WebSocket标准,并配置一个通用的.NET 5应用程序通过WebSocket连贯与SignalR通信。 咱们将深刻底层的概念,以了解底层产生了什么。 对于WebSocket 引入WebSocket是为了实现客户端和服务器之间的双向通信。HTTP 1.0的一个痛点是每次向服务器发送申请时创立和敞开连贯。然而,在HTTP 1.1中,通过应用放弃连贯机制引入了长久连贯(RFC 2616)。这样,连贯能够被多个申请重用——这将缩小提早,因为服务器晓得客户端,它们不须要在每个申请的握手过程中启动。 WebSocket建设在HTTP 1.1标准之上,因为它容许长久连贯。因而,当你第一次创立WebSocket连贯时,它实质上是一个HTTP 1.1申请(稍后具体介绍)。这使得客户端和服务器之间可能进行实时通信。简略地说,下图形容了在发动(握手)、数据传输和敞开WS连贯期间产生的事件。咱们将在前面更深刻地钻研这些概念。 协定中蕴含了两局部:握手和数据传输。 握手 让咱们先从握手开始。 简略地说,WebSocket连贯基于单个端口上的HTTP(和作为传输的TCP)。上面是这些步骤的总结。 服务器必须监听传入的TCP套接字连贯。这能够是你调配的任何端口—通常是80或443。客户端通过一个HTTP GET申请发动开始握手(否则服务器将不晓得与谁对话)——这是“WebSockets”中的“Web”局部。在消息报头中,客户端将申请服务器将连贯降级到WebSocket。服务器发送一个握手响应,通知客户端它将把协定从HTTP更改为WebSocket。客户端和服务器单方协商连贯细节。任何一方都能够退出。上面是一个典型的关上(客户端)握手申请的样子。 GET /ws-endpoint HTTP/1.1Host: example.com:80Upgrade: websocketConnection: UpgradeSec-WebSocket-Key: L4kHN+1Bx7zKbxsDbqgzHw==Sec-WebSocket-Version: 13留神客户端是如何在申请中发送Connection: Upgrade和Upgrade: websocket报头的。 并且,服务器握手响应。 HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: CTPN8jCb3BUjBjBtdjwSQCytuBo=数据传输 咱们须要了解的下一个要害概念是数据传输。任何一方都能够在任何给定的工夫发送音讯——因为它是一个全双工通信协议。 音讯由一个或多个帧组成。帧的类型能够是文本(UTF-8)、二进制和管制帧(例如0x8 (Close)、0x9 (Ping)和0xA (Pong))。 装置 让咱们付诸行动,看看它是如何工作的。 首先创立一个 ASP.NET 5 WebAPI 我的项目。 dotnet new webapi -n WebSocketsTutorialdotnet new slndotnet sln add WebSocketsTutorial当初增加SignalR到我的项目中。 dotnet add WebSocketsTutorial/ package Microsoft.AspNet.SignalR示例代码 咱们首先将WebSockets中间件增加到咱们的WebAPI应用程序中。关上Startup.cs,向Configure办法增加上面的代码。 在本教程中,我喜爱放弃简略。因而,我不打算探讨SignalR。它将齐全基于WebSocket通信。你也能够用原始的WebSockets实现同样的性能,如果你想让事件变得更简略,你不须要应用SignalR。 app.UseWebSockets(); 接下来,咱们将删除默认的WeatherForecastController,并增加一个名为WebSocketsController的新控制器。留神,咱们将只是应用一个控制器action,而不是拦挡申请管道。 这个控制器的残缺代码如下所示。 ...

March 4, 2021 · 2 min · jiezi

关于c:用C程序打印星形镂空正方形

解题思路用5*5网格 在第一行和最初一行,在所有列中打印星号,应用这个条件(i==1||i==5)从第二行到倒数第二行(用红色标记),在第一列行和最初一列打印星号,应用这个条件(j==1||j==5)如果条件不满足,打印空格。 #include <stdio.h>int main(){ int i; int j; for(i=1;i<=5;i++){ for(j=1;j<=5;j++){ if (i==1||i==5){ printf("*"); }else if (j==1||j==5){ printf("*"); }else{ printf(" "); } } printf("\n"); } return 0;}

March 4, 2021 · 1 min · jiezi

关于c:C语言中fun1和fun2void的区别

在一次C语言实训中我发现老师在对无参函数的书写中写成fun2(void)的模式,这引起了我的好奇心,我只晓得fun1()和fun2(void)是两个无参函数,后者是C99中规定的,void的意思就是该函数不承受任何参数,然而我在应用的过程中除了对fun2传参会导致报错以外没有发现别的问题,所以就开始好奇为什么老师在实训时会特意在没有传参的函数里写上void。 通过谷歌搜寻失去以下论断 (C) The difference between int main() and int main(void)A common misconception for C programmers, is to assume that a function prototyped as follows takes no arguments:int foo();In fact, this function is deemed to take an unknown number of arguments. Using the keyword void within the brackets is the correct way to tell the compiler that the function takes NO arguments.参考文章:https://faq.cprogramming.com/... 然而我还是不能了解到底为什么要这样定义,最初在抖音的一个博主(抖抖代码)那里失去了解答 以下是博主演示的代码: #include<stdio.h>int main(void){ void fun1(); void fun2(void); fun1(); fun2(); return 0;}void fun1(){ printf("doudou \n");}void fun2(){ printf("douodu 2\n");}/*失去输入为:doudou douodu 2*/在没有传入任何参数的状况下两者都是被失常运行的。 ...

March 3, 2021 · 1 min · jiezi

关于c++:关于DevC不支持c11标准的解决

记录一下,不便找回!1.关上工具2.抉择编译选项3.没批改前4.勾选第一个方框,并增加 -std=c++11 ,而后确定就行了。

March 3, 2021 · 1 min · jiezi

关于c:读懂汇编代码

对于这样一份 C 代码: int add (int a, int b) { return a + b;}int main (void) { int a = 10; int b = 20; int c = add(a, b); return c;}先应用 gcc 编译 $ gcc -g -O0 hello.c -o hello而后应用 objdump 来查看反汇编只摘取其中后果中最重要的汇编代码,# 之后的内容为手动加的正文 $ objdump -j .text -S -I hello00000000004004ed <add>:int add (int a, int b) { 4004ed: 55 push %rbp # 将 rbp 寄存器的值压入栈 4004ee: 48 89 e5 mov %rsp,%rbp # 将 rsp 寄存器的值 挪动到 rbp 寄存器,栈底(rbp)挪动到原来的栈顶的地位(rsp) 4004f1: 89 7d fc mov %edi,-0x4(%rbp) # 将 edi 寄存器的值,挪动到 -0x4(绝对于 rbp 的地址) 4004f4: 89 75 f8 mov %esi,-0x8(%rbp) # 将 esi 寄存器的值,挪动到 -0x8(绝对于 rbp 的地址) return a + b; 4004f7: 8b 45 f8 mov -0x8(%rbp),%eax # 将 -0x8 的值挪动到 eax 4004fa: 8b 55 fc mov -0x4(%rbp),%edx # 将 -0x4 的值挪动到 edx 4004fd: 01 d0 add %edx,%eax # eax += edx} 4004ff: 5d pop %rbp # 从栈顶弹出一个值,放到 rbp 里 400500: c3 retq0000000000400501 <main>:int main (void) { 400501: 55 push %rbp 400502: 48 89 e5 mov %rsp,%rbp 400505: 48 83 ec 10 sub $0x10,%rsp int a = 10; 400509: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # 将整数 0xa 挪动到 -0x4(绝对于 rbp) int b = 20; 400510: c7 45 f8 14 00 00 00 movl $0x14,-0x8(%rbp) # 将整数 0x14 挪动到 -0x8(绝对于 rbp) int c = add(a, b); 400517: 8b 55 f8 mov -0x8(%rbp),%edx # 将 -0x8 挪动到 edx 40051a: 8b 45 fc mov -0x4(%rbp),%eax # 将 -0x4 挪动到 eax 40051d: 89 d6 mov %edx,%esi # esi = edx 40051f: 89 c7 mov %eax,%edi # edi = eax 400521: e8 c7 ff ff ff callq 4004ed <add> # 调用函数 add 400526: 89 45 f4 mov %eax,-0xc(%rbp) # 将 eax 挪动到 -0xc return c; 400529: 8b 45 f4 mov -0xc(%rbp),%eax # 将 -0xc 挪动到 eax} 40052c: c9 leaveq 40052d: c3 retq 40052e: 66 90 xchg %ax,%ax # nop

March 2, 2021 · 2 min · jiezi

关于c++:C-static-const-volatile-总结

constconst 位于 *的左侧: 用来润饰指针所指向的变量,指针指向常量。// 指针不容许扭转数据int b = 500;const int *a = &b;*a = 600; // error // 能够通过变量自身去批改int b = 500;const int *a = &b;b = 600;cout << *a << endl; // 600const 位于 *的右侧: 用来润饰指针自身,指针是常量。// 指针自身是常量,定义时须要初始化int b = 500;//int * const a; // errorint * const c = &b; // error*c = 600; // 失常,容许改值cout << *c << endl;const 用在成员函数中, 位于 function_name () const {}咱们在定义类的成员函数中,经常有一些成员函数不扭转类的数据成员。 也就是说这些函数的 readonly function,而有一些函数要批改类的数据成员的值。 如果在readonly function都加上const进行标识,无疑会进步程序的可读性。 其实还能进步程序的可靠性,已定义成const的成员函数,一旦希图扭转数据成员的值,则编译器按错误处理。 ...

March 2, 2021 · 2 min · jiezi

关于c:用C程序程序打印数字正方形

解题思路用5*5网格,启动一个内部循环(行),将迭代5次。在内部循环下开始一个外部循环(列),迭代雷同的次数在外部循环中打印列号。 /*打印如下:1234512345123451234512345 */#include <stdio.h>int main(){ int i; int j; for (i = 1; i <= 5; i++) { for (j = 1; j <= 5; j++) { printf("%d", j); } printf("\n"); } return 0;}原文链接

March 1, 2021 · 1 min · jiezi

关于c++:Qtopencv调用camera的简单应用

最近须要应用opencv,就简略写了一个测试示例并记录下来。其中 QCamera 等相干的类同样能够实现以后性能。 仓库 性能反对有线或IP摄像头连贯反对视频流播放反对多分辨率设置反对视频录制反对拍照视频抽帧、拍照、录制等由独单线程解决测试可用的视频流 CCTV1 高清 http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8CCTV3 高清 http://ivi.bupt.edu.cn/hls/cctv3hd.m3u8CCTV5+ 高清 http://ivi.bupt.edu.cn/hls/cctv5phd.m3u8CCTV6 高清 http://ivi.bupt.edu.cn/hls/cctv6hd.m3u8camara.h#ifndef CAMARA_H#define CAMARA_H#include <QImage>#include <QObject>#include <QThread>#include <QTimer>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>Q_DECLARE_METATYPE(QImage);/* *@brief Camara 在独自线程中实现视频抽帧、拍照及录像性能 *@brief open、close 等是耗时操作,请保障在 Camara 线程工夫中实现调用 (可思考异步槽函数、QMetaObject::invokeMethod) */class Camara : public QObject{ Q_OBJECTpublic: Camara(); ~Camara(); bool isOpened() const; bool isTakevideoed() const; QString getSavePath() const; QSize getResolutions() const; bool isTakeVideo() const;signals: void updateImage(QImage); void statusChanged(bool isOpen);public slots: void openCamara(const QString &url); void openCamara(int index); void closeCamara(); void takePicture(); void takeVideo(); void setSavePath(const QString &path); void setResolutions(const QSize &size);private slots: void tbegin(); void tend(); void captureCamara();private: QString m_savepath; QAtomicInteger<bool> m_isTakepicture = false; QAtomicInteger<bool> m_isTakevideo = false; QAtomicInteger<bool> m_isflip = false; QScopedPointer<cv::VideoCapture> m_capture; QScopedPointer<cv::VideoWriter> m_writer; QTimer *m_timer = nullptr; QThread m_thread;};#endif // CAMARA_H#include "camara.h"#include <QDateTime>Camara::Camara(){ moveToThread(&m_thread); connect(&m_thread, &QThread::started, this, &Camara::tbegin); connect(&m_thread, &QThread::finished, this, &Camara::tend); m_thread.start(QThread::HighPriority);}Camara::~Camara(){ m_thread.quit(); m_thread.wait();}void Camara::tbegin(){ m_capture.reset(new cv::VideoCapture); m_writer.reset(new cv::VideoWriter); m_timer = new QTimer(this); m_timer->setTimerType(Qt::PreciseTimer); connect(m_timer, &QTimer::timeout, this, &Camara::captureCamara);}void Camara::tend(){ closeCamara();}void Camara::openCamara(const QString &url){ if (!m_capture->isOpened() && m_capture->open(url.toLatin1().data())) { m_isflip = false; m_timer->start(33); emit statusChanged(true); } else { emit statusChanged(false); }}void Camara::openCamara(int index){ if (!m_capture->isOpened() && m_capture->open(index)) { m_isflip = true; m_timer->start(33); emit statusChanged(true); } else { emit statusChanged(false); }}void Camara::closeCamara(){ m_timer->stop(); if (m_writer->isOpened()) m_writer->release(); if (m_capture->isOpened()) m_capture->release();}void Camara::captureCamara(){ cv::Mat originalframe; cv::Mat flipframe; *m_capture >> originalframe; if (m_isflip) cv::flip(originalframe, flipframe, 1); else flipframe = originalframe; QImage img = QImage(flipframe.data, flipframe.cols, flipframe.rows, QImage::Format_RGB888).rgbSwapped(); if (!img.isNull()) { if (m_isTakepicture) { m_isTakepicture = !m_isTakepicture; QString name = m_savepath + QDateTime::currentDateTime().toString("yyyy-MM-hh hh_mm_ss") + ".jpeg"; img.save(name, "jpeg"); } if (m_isTakevideo) { *m_writer << flipframe; } updateImage(img); } originalframe.release(); flipframe.release();}void Camara::takePicture(){ m_isTakepicture = true;}void Camara::takeVideo(){ if (!m_isTakevideo) { QString name = m_savepath + QDateTime::currentDateTime().toString("yyyy-MM-hh hh_mm_ss") + ".avi"; if (m_writer->open(name.toLatin1().data(), cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), 30.0, cv::Size(m_capture->get(cv::CAP_PROP_FRAME_WIDTH), m_capture->get(cv::CAP_PROP_FRAME_HEIGHT)), true)) { m_isTakevideo = true; } } else { m_isTakevideo = false; m_writer->release(); }}void Camara::setSavePath(const QString &path){ m_savepath = path + '/';}void Camara::setResolutions(const QSize &size){ if (m_capture->isOpened()) { m_capture->set(cv::CAP_PROP_FRAME_WIDTH, size.width()); m_capture->set(cv::CAP_PROP_FRAME_HEIGHT, size.height()); }}QString Camara::getSavePath() const{ return m_savepath;}bool Camara::isOpened() const{ return m_capture->isOpened();}bool Camara::isTakevideoed() const{ return m_isTakevideo;}QSize Camara::getResolutions() const{ QSize ret; ret.setWidth(m_capture->get(cv::CAP_PROP_FRAME_WIDTH)); ret.setHeight(m_capture->get(cv::CAP_PROP_FRAME_HEIGHT)); return ret;}bool Camara::isTakeVideo() const{ return m_writer->isOpened();}

March 1, 2021 · 2 min · jiezi

关于c++:c虚继承多继承

看这一篇文章之前强烈建议先看以下我之前公布的 虚指针,虚函数分析 例1: 以下代码输入什么? #include <iostream>using namespace std;class A {protected: int m_data;public: A(int data = 0) {m_data=data;} int GetData() { return doGetData(); } virtual int doGetData() { return m_data; }};class B : public A{protected: int m_data;public: B(int data = 1) { m_data = data; } int doGetData() { return m_data; }};class C: public B{protected: int m_data;public: C(int data=2) { m_data = data; }};int main(int argc, char const *argv[]){ C c(10); cout << c.GetData() << endl; cout << c.A::GetData() << endl; cout << c.B::GetData() << endl; cout << c.C::GetData() << endl; cout << c.doGetData() << endl; cout << c.A::doGetData() << endl; cout << c.B::doGetData() << endl; cout << c.C::doGetData() << endl; return 0;}构造函数从最初始的基类开始结构,各个类的同名变量没有造成笼罩,都是独自的变量。 ...

February 28, 2021 · 3 min · jiezi

关于c++:PAT甲级1105-Spiral-Matrix

题目粗心将给定的N个正整数按非递增的程序,填入“螺旋矩阵”,所谓“螺旋矩阵”,是指从左上角第1个格子开始,按顺时针螺旋方向填充,要求矩阵的规模为m行n列,满足条件:m*n等于N;m>=n;且m-n取所有可能值中的最小值. 算法思路此题的求解步骤分为求解矩阵规模和填充矩阵 1、求解矩阵规模因为须要行和列都尽可能的相近,所以初始取col为根号n,只有$n $%$ col != 0$,col就递加,从而获取列col和行row。2、填充矩阵这里采纳设置矩阵的4个边界(左右高低),别离为$left=0,right=col-1,up=0,bottom=row-1$,依照从左到右,从上到下,从右到左,从下到上的程序顺次填充,每一次填充结束就更新边界,比方依照从左往右填充了一行就更新上边界up(++up),只有每次填充结束后,index>=n,阐明填充完结。 提交后果 AC代码#include <cstdio>#include <cmath>#include <iostream>#include <algorithm>using namespace std;int main() { int n; scanf("%d", &n); int a[n]; for (int i = 0; i < n; ++i) { scanf("%d", &a[i]); } sort(a, a + n, [&](int a, int b) { return a > b; }); // 计算m和n int col = (int) sqrt(n * 1.0); while (n % col != 0) { --col; } int row = n / col; int result[row][col]; int index = 0;// 标记以后填充的元素 // 定义数组的左右高低边界 int left = 0, right = col - 1, up = 0, bottom = row - 1; while (index < n) { // 从左到右 for (int i = left; i <= right; ++i) { result[up][i] = a[index++]; } // 更新上界 ++up; if (index >= n) break; // 从上到下 for (int i = up; i <= bottom; ++i) { result[i][right] = a[index++]; } // 更新右边界 --right; if (index >= n) break; // 从右到左 for (int i = right; i >= left; --i) { result[bottom][i] = a[index++]; } // 更新下界 --bottom; if (index >= n) break; // 从下到上 for (int i = bottom; i >= up; --i) { result[i][left] = a[index++]; } // 更新左边界 ++left; } for (int i = 0; i < row; ++i) { for (int j = 0; j < col; ++j) { printf("%d", result[i][j]); if (j < col - 1) printf(" "); } printf("\n"); } return 0;}

February 28, 2021 · 2 min · jiezi

关于c++:PAT甲级1057-Stack

题目粗心现有一个栈,对其进行执行N次基本操作,该操作有三种类型,别离是Pop,Push和PeekMedian,代表了出栈,入栈和获取栈中元素的中位数,要求依照每一次输出的指令进行相应的输入 算法思路这里最为简单的就是实时的获取栈中的中位数,应用拷贝到数组排序或者set汇合都会超时,这里借助分块的思维来实现实时获取中位数,除了应用栈st来进行入栈和出栈的基本操作之外,还须要应用block数组和table数字别离保留每一块蕴含的数字个数和每一个数字呈现的次数,第i块(i>=0)保留的数字范畴是[iblockSize,(i+1)blockSize-1],那么求解栈的中位数的办法如下: 1、获取中位数的地位k=st.size()/2+st.size()%2;2、应用sum示意以后累计的数字的个数3、查找第k大的数字所在的块号i,第一个使得sum+block[i]>=k成立的就是第k大的数字所在的块号4、查找第k大的数字在第i号块中的对应数字num,第i号块的第一个数字为iblockSize,让num=iblockSize,而后遍历num数字,只有sum+table[num]==k,就阐明以后的num就是第k大的数字。提交后果 AC代码#include <iostream>#include <stack>#include <string>#include <cmath>#include <cstring>using namespace std;int table[100010];stack<int> st;void push(int block[],int x){ st.push(x); ++table[x]; int blockSize = (int)sqrt(100001*1.0); ++block[x/blockSize];}int pop(int block[]){ int x = st.top(); st.pop(); --table[x]; int blockSize = (int)sqrt(100001*1.0); --block[x/blockSize]; return x;}int getMedian(const int block[]){ // 获取中位数的地位 int k = st.size()/2+st.size()%2; // 累计以后曾经呈现过的数字个数 int sum = 0; int blockSize = (int)sqrt(100001*1.0); // 查找第一个使得sum+block[i]>=k的块号i int i; for(i=0;i<blockSize;++i){ if(sum+block[i]<k){ sum += block[i]; }else{ break; } } // 第k大的数字在第i块中 int num;// 保留以后遍历的数字 int start = i*blockSize; int end = (i+1)*blockSize; for(num=start;num<end;++num){ if(sum+table[num]<k){ sum += table[num]; }else{ // 以后num就是第k大的数字 break; } } return num;}int main() { int blockSize = (int)sqrt(100001*1.0); int block[blockSize]; memset(block,0,sizeof(block)); int n; scanf("%d",&n); string str; int num; for(int i=0;i<n;++i){ cin>>str; if(str=="Pop"){ if(st.empty()){ printf("Invalid\n"); }else{ printf("%d\n",pop(block)); } }else if(str=="Push"){ cin>>num; push(block,num); }else{ if(st.empty()){ printf("Invalid\n"); }else{ printf("%d\n",getMedian(block)); } } } return 0;}

February 28, 2021 · 1 min · jiezi

关于c++:PAT甲级1129-Recommendation-System

题目粗心依据用户每次点击的货色的编号,输入他在点以后编号之前应该给这个用户举荐的商品的编号,只举荐k个,也就是输入用户已经点击过的商品编号的最多的前k个,如果恰好两个商品有雷同的点击次数,就输入编号较小的那个。 算法思路这里依据题意很显著在每一次输出商品编号的时候须要依据排序后的后果输入举荐产品的编号,然而应用sort进行排序肯定会超时,所以应用set汇合的主动排序功能,排序根据的是商品的编号val和之前呈现的频率,所以将这两个属性封装为一个构造体Commodity,并且重载小于号,使得在每一次增加商品后就会依照自定义的排序规定进行排序。在每一次输出的时候,只有不是第一次点击商品,那么就输入set汇合中前k个商品的音讯,而后再将以后商品增加到set汇合中,因为该商品可能曾经呈现在了set汇合中,所以要先查找以后商品并删除,而后再将新的商品音讯增加其中。查找商品的办法就是应用num数组统计曾经增加进set汇合中的每一个商品编号对应的频率,而后将以后商品的编号和频率封装为Commodity,而后在set汇合中查找即可。 提交后果 AC代码#include <cstdio>#include <set>#include <cstring>using namespace std;struct Commodity{ int val; int fre; bool operator < (Commodity node) const{ return this->fre!=node.fre?this->fre>node.fre:this->val<node.val; } Commodity(int _val, int _fre){ val = _val; fre = _fre; }};int main() { int n,k; scanf("%d %d",&n,&k); set<Commodity> s; int num[n+1];// 统计每一个数字呈现的频率 memset(num,0,sizeof(num)); for(int i=1;i<=n;++i){ int query; scanf("%d",&query); if(i!=1){ printf("%d:",query); // 只有不是第一个数字就输入汇合s中前k个数字 int cnt = 0; for(auto it:s){ if(cnt<k){ printf(" %d",it); ++cnt; }else{ break; } } printf("\n"); } // 增加以后数字到汇合中 Commodity toBeFound = Commodity{query, num[query]}; auto it = s.find(toBeFound); if(s.find(toBeFound)!=s.end()){ // 以后数字在s汇合中呈现过 s.erase(it); } ++num[query]; s.insert(Commodity{query, num[query]}); } return 0;}

February 28, 2021 · 1 min · jiezi

关于c++:5分钟掌握C中的三种继承方式

public 形式继承基类成员对派生类的可见性对派生类来说,基类的私有成员和爱护成员可见,基类的私有成员和爱护成员作为派生类的成员时,它们都放弃原有的状态;基类的公有成员不可见,基类的公有成员依然是公有的,派生类不可拜访基类中的公有成员。 基类成员对派生类对象的可见性对派生类对象来说,基类的私有成员是可见的,其余成员是不可见的。 所以,在私有继承时,派生类的对象能够拜访基类中的私有成员,派生类的成员函数能够拜访基类中的私有成员和爱护成员。 简略来说,派生类能拜访基类的public, protected成员,继承过去权限不变,派生类对象只能拜访基类public成员。 测试代码如下: class A{private: int m_data1; void print1() { cout << "private print1" << endl; }protected: int m_data2; void print2() { cout << "protected print2" << endl; }public: A(int x = 1, int y = 2, int z = 3) : m_data1(x), m_data2(y), m_data3(z) {} int m_data3; void print3() { cout << "protected print3" << endl; }};class B : public A{public: void test_public() { cout << m_data3 << endl; print3(); } void test_protected() { cout << m_data2 << endl; print2(); } void test_private() { // 上面两行编译不过,B类内无法访问父类的公有成员 // cout << m_data1 << endl; // print1(); }};int main(int argc, char const* argv[]){ B b; b.test_public(); b.test_protected(); b.test_private(); cout << b.m_data3 << endl; // cout << b.m_data2 << endl; // 编译不过,子类对象无法访问父类protected的成员 // cout << b.m_data1 << endl; // 编译不过,子类对象无法访问父类private的成员 return 0;}private 形式继承基类成员对其对象的可见性与个别类及其对象的可见性雷同,私有成员可见,其余成员不可见 ...

February 28, 2021 · 3 min · jiezi

关于c++:PAT甲级1130-Infix-Expression

题目粗心给定一颗形象语法二叉树,要求输入其中序遍历序列 算法思路应用动态数组nodes存储每一个结点的信息,应用father数组记录所有结点的父亲结点,这样在遍历father的时候其值为0的就是根结点下标root。对于其中序遍历的输入,其特点是对于根结点没有左右括号,除此之外只有有孩子存在就肯定有左右括号,单目运算肯定在右边,而后就是双目运算和数字。 提交后果 AC代码#include <cstdio>#include <algorithm>#include <string>#include <iostream>#include <cstring>using namespace std;struct Node{ string data; int left{}; int right{};}nodes[25];int root = 0;void inOrder(int r){ if(r==-1){ return; } if(r!=root&&(nodes[r].left!=-1||nodes[r].right!=-1)){ // 根节点没有左右括号,只有有孩子,就有左括号 printf("("); } inOrder(nodes[r].left); cout<<nodes[r].data; inOrder(nodes[r].right); if(r!=root&&(nodes[r].left!=-1||nodes[r].right!=-1)){ // 根节点没有左右括号,只有有孩子,就有右括号 printf(")"); }}int main() { int n; scanf("%d",&n); int father[n+1]; memset(father,0,sizeof(father)); for(int i=1;i<=n;++i){ cin>>nodes[i].data>>nodes[i].left>>nodes[i].right; father[nodes[i].left] = i; father[nodes[i].right] = i; } for(int i=1;i<=n;++i){ if(father[i]==0){ root = i; break; } } inOrder(root); return 0;}

February 27, 2021 · 1 min · jiezi

关于c++:PAT甲级1128-N-Queens-Puzzle

题目粗心N皇后问题的改版,输出的每一行数据为一种棋盘摆放地位,其下标为列,值为行,保障每一列不反复,判断是否是该N皇后问题的解 算法思路只需判断以后N个棋子是否在同一行或者对角线上,判断的办法就是在输出每一个棋子的地位的时候就去与后面的所有棋子比拟其行是否一样或者判断行标之差的绝对值是否等于列表之差的绝对值,如果是阐明不是N皇后的解,输入NO,否则输入YES 提交后果 AC代码#include <cstdio>#include <algorithm>using namespace std;int main() { int k; scanf("%d",&k); for(int i=0;i<k;++i){ int n; scanf("%d",&n); int solution[n+1]; bool isAns = true;// 是否是N皇后的解 for(int j=1;j<=n;++j){ scanf("%d",&solution[j]); for(int x=1;x<j;++x){ if(solution[j]==solution[x]||abs(j-x)==abs(solution[x]-solution[j])){ isAns = false; break; } } } if(isAns){ printf("YES\n"); }else{ printf("NO\n"); } } return 0;}

February 27, 2021 · 1 min · jiezi

关于c:C语言中的-int-是什么

从 int* 和 int 说起“int**是什么” 这个问题其实不难。咱们能够递归剖析,先看下 int*是什么,嗯?如同还能够持续递归到 int 咱们都晓得,int是 C 的根底数据类型 整型,而多了个 * 的 int* 是 指向整型变量的指针,那么 int** 是什么就不言自明了,列个表: C语法释义int整型int*指向整型的指针int**指向指向整型的指针的指针看到这里,你对 int** 应该有了个初步的意识,但你可能感觉有点绕,没关系,上面咱们写一段代码看看: #include <stdio.h>int main(){ int i = 418; int* pi; // 依据下面的表格,咱们晓得 int* 是指向“整型”的指针, // 那么 pi 能够保留的是 int 类型的变量 i 的地址: pi = &i; int** ppi; // ppi 能够保留的是 int* 类型的变量 pi 的地址: ppi = &pi; // 祝贺你,当初你曾经晓得了怎么定义 int** 类型的变量和给它赋值 // 咱们先写到这里 return 0;}深刻思考如果定义有 int** p(为了不便,咱们暂且把 p 认为是 ppi 的别名),那么 p, *p, **p, p + 1, *p + 1, *(p + 1), **p + 1, *(*p + 1), **(p + 1) 别离是什么? ...

February 27, 2021 · 2 min · jiezi

关于c++:PAT甲级1127-ZigZagging-on-a-Tree

题目粗心给定一颗二叉树的中序和后序序列,要求依照zigzagging的形式输入该二叉树的层序遍历 算法思路首先依据中序和后序遍历序列建设该二叉树,而后在层序遍历中应用level记录以后所在档次,每一次将以后层的所有结点都出队到temp数组中,更新子节点的level并入队,如果level是奇数就逆序temp,而后增加到ans数组中保留最终的层序遍历后果,++level。最初输入ans数组中的后果即可。 提交后果 AC代码#include <cstdio>#include <queue>#include <vector>#include <algorithm>using namespace std;// 中序,后序和中序序列在in数组中的下标int in[40],post[40],inIndex[40];int n;// 顶点数目vector<int> ans;// zigzagging层序遍历序列struct Node{ int v{}; int level{}; Node* left = nullptr; Node* right = nullptr;};Node* createTree(int postL,int postR,int inL){ if(postL>postR){ return nullptr; } Node* root = new Node; root->v = post[postR]; // 获取根节点在中序遍历中的地位 int rootIndex = inIndex[root->v]; // 左子树长度 int leftSize = rootIndex-inL; root->left = createTree(postL,postL+leftSize-1,inL); root->right = createTree(postL+leftSize,postR-1,rootIndex+1); return root;}// level为偶数从左往右,为奇数从右往左void layerOrder(Node* root){ queue<Node*> que; root->level = 1; que.push(root); int level = 1; while (!que.empty()){ int len = que.size(); vector<int> temp; // 一次性遍历每一层的结点,并保留在temp中 for(int i=0;i<len;++i){ Node* t = que.front(); que.pop(); if(t->left){ t->left->level = t->level + 1; que.push(t->left); } if(t->right){ t->right->level = t->level + 1; que.push(t->right); } temp.push_back(t->v); } // 档次为奇数得逆序 if(level%2!=0){ reverse(temp.begin(),temp.end()); } for(auto v:temp){ ans.push_back(v); } ++level; }}int main() { scanf("%d",&n); for(int i=0;i<n;++i){ scanf("%d",&in[i]); inIndex[in[i]] = i; } for (int i = 0; i < n; ++i) { scanf("%d",&post[i]); } Node* root = createTree(0,n-1,0); layerOrder(root); for(int i=0;i<ans.size();++i){ printf("%d",ans[i]); if(i<ans.size()-1){ printf(" "); } } return 0;}

February 27, 2021 · 1 min · jiezi

关于c++:PAT甲级1126-Eulerian-Path

题目粗心给定N个顶点M条边的无向图,判断该图是Eulerian,semi-Eulerian还是non-Eulerian,并输入每一个顶点的度。 算法思路首先得理清几个概念 Eulerian path:恰好拜访图中所有顶点的门路Eulerian circuit:Eulerian path的终点和起点雷同Eulerian: 在一个连通图中所有顶点的度为偶数semi-Eulerian:连通图含有Eulerian path但没有 Eulerian circuit,即连通图中只有两个顶点的度为奇数non-Eulerian:既不是Eulerian也不是semi-Eulerian对于顶点的度间接应用degree数组统计输入即可,而后咱们判断以后图是否是连通图,判断办法就是从任一终点应用深度优先搜寻,如果该连通重量的顶点数目和N雷同,就阐明该图连通,否则就不是连通图,输入Non-Eulerian,而后再统计每一个顶点的度是否是偶数,如果都是偶数,输入Eulerian,如果只有两个顶点的度为奇数,输入Semi-Eulerian,否则输入Non-Eulerian。 提交后果 AC代码#include <cstdio>using namespace std;int G[505][505];int degree[505];// 每一个顶点的度bool visited[505];// 拜访标记数组int cnt = 0;// 顶点为1的连通重量的顶点数目int n,m;void DFS(int start){ visited[start] = true; ++cnt; for(int i=1;i<=n;++i){ if(!visited[i]&&G[start][i]!=0){ DFS(i); } }}void printDegree(){ for(int i=1;i<=n;++i){ printf("%d",degree[i]); if(i<n) printf(" "); } printf("\n");}int main() { scanf("%d %d",&n,&m); for(int i=0;i<m;++i){ int a,b; scanf("%d %d",&a,&b); G[a][b] = G[b][a] = 1; ++degree[a]; ++degree[b]; } // 统计从顶点1登程的连通重量的顶点数 DFS(1); printDegree(); if(cnt!=n){ // 该图不连通 printf("Non-Eulerian"); }else{ int evenDegree = 0;// 度为偶数的顶点个数 for(int i=1;i<=n;++i){ if(degree[i]%2==0){ ++evenDegree; } } if(evenDegree==n){ printf("Eulerian"); }else if(evenDegree==n-2){ printf("Semi-Eulerian"); }else{ printf("Non-Eulerian"); } } return 0;}

February 27, 2021 · 1 min · jiezi

关于c++:PAT甲级1125-Chain-the-Ropes

题目粗心给定N段绳子,将这N段绳子顺次对折,任意两段对折后绳子的长度为和的一半,要求给出对折这N段绳子后最长的长度。 算法思路因为对折后的绳子在之后又会持续对折,所以尽可能将长的绳子对折次数缩小能力取得最长的绳子,所以将所有的绳子进行升序排序,而后顺次对折就是最初的答案。 提交后果 AC代码#include <cstdio>#include <algorithm>using namespace std;int main() { int n; scanf("%d",&n); int a[n]; for(int i=0;i<n;++i){ scanf("%d",&a[i]); } sort(a,a+n); int b = a[0]; for(int i=1;i<n;++i){ b = (b+a[i])/2; } printf("%d",b); return 0;}

February 27, 2021 · 1 min · jiezi

关于c++:PAT甲级1124-Raffle-for-Weibo-Followers

题目粗心给定M条微博转发条目,针对每一个用户的转发条目,从中抽取一些人作为winner并给予奖品,第一个获奖的人是第S次转发的人,下一个获奖的人为上一个获奖人的地位加N,同一个人不能获奖两次,当初要求你输入获奖名单,对于没有人获奖的状况,输入Keep going...。 算法思路应用一个map——winner记录所有曾经获奖的人,winnerIndex记录下一个获奖的人的地位,如果s>m,阐明没有人获奖,输入Keep going...。否则就依照程序输出每一条转发的微博条目,只有以后人的地位i==winnerIndex,并且winner[a] = false,就阐明此人为以后获奖的人,否则就++winnerIndex往下查找 提交后果 AC代码#include <unordered_map>#include <string>#include <iostream>#include <cstdio>using namespace std;int main() { int m,n,s;// 转发数目,跳跃数目,起始获奖下标 scanf("%d %d %d",&m,&n,&s); if(s>m){ cout<<"Keep going..."; return 0; } // 记录曾经获奖的人 unordered_map<string,bool> winner; // 下一个获奖人的下标 int winnerIndex = s; for(int i=1;i<=m;++i){ string a; cin>>a; if(i==winnerIndex){ if(!winner[a]){ // 以后人没有得过奖 cout<<a<<endl; winner[a] = true; winnerIndex += n; }else{ ++winnerIndex; } } } return 0;}

February 27, 2021 · 1 min · jiezi

关于c++:大厂动态规划面试汇总重量级干货彻夜整理

注:本文是BAT真题收录很值得大家花心思看完,看完会有播种。 前言算法是面试大公司必考的我的项目,所以面试前筹备好算法至关重要,明天整顿的常见的动静布局题目,心愿能够帮到大家。 要想学习其余绝世武功,要先打好根底。算法属于内功,则更为重要。 匪徒抢劫题目:匪徒抢劫一排房间,每个房间都有钱,不能抢劫两个相邻的房间,要求抢的钱最多。数组如:[2,7,9,3,1] 思路:当输出房间数为0,1,2时,这个很好判断,当输出房间数字大于3时,就要用到动静布局了,方程是: dp[i]是当抢到第i个数时,能抢到最大值,从部分最大值推到最终后果最大。 如果抢到第5个房间,那么第5个房间有二种状况,抢不和不被抢,因为只能隔房间。 如果抢到第4个房间,有个最大值;抢到第3个房间,有个最大值。如果加上第3房间最大值,加上第5房间的最大值,大于抢到第4个房间时的最大时。那就抢3,5而不抢4,反而,就按抢4的策略。 这样从前往后推,最初的后果肯定是最大的。代码如下: 跳台阶题目形容:有 N 阶楼梯,每次可上一阶或两阶,求有多少种上楼梯的办法 先来剖析下这个问题: 当N=1时,这个很好了解,只能跨1步这一种了当N=2时,你每次能够跨1步或2步,那就是走2步或走两个1步当N=3时,因为你能够跨1步或2步,那你在台阶1或2都能行。要计算到台阶1有多少种走法,到台阶2有多少种走法,而后2种相加,顺次逆推。 当N=4时,你在台阶2或3都能行,计算到台阶2有多少种走法,到台阶3有多少种走法,而后2者相加,顺次逆推。 总结如下:你会发现,这是斐波拉切数列,应用递归呈现反复计算问题,所以抉择动静布局算法。 层数公式种数1f(1)=112f(2)=223f(3)=f(1)+f(2)34f(4)=f(2)+f(3)5第三层:3种(在第一层走2步或在第二层走1步) 第四层:5种(在第二层走2步或在第三层走1步) 代码如下: i,j首先赋边界值,res保留i+j的值,每次后退,i,j,res的值都会被赋到后面后果。下面的算法是底向上,递归相当于自顶向下,防止了反复计算。 矩形最小门路和题目:给定一个,蕴含非负整数的 m x n 网格。请找出一条,从左上角到右下角的门路。使得门路上,所有数字总和为最小,每次只能向下,或者向右挪动一步。输出:[[1,3,1], [1,5,1], [4,2,1]]输入: 7解释: 因为门路 1→3→1→1→1 的总和最小。先看动静方程: i值j值dp方程i>0j=0dpi = dpi−1 + gridii=0j>0dp0 = dp0 + grid0i<0j>0dpi = min(dpi−1, dpi) + gridi阐明:因为 i=0 和 j=0 是临界条件,所以要先求进去。当 i>0 和 j>0 时,看如上数组,5 能够由上方3,或者左方 1 走过去。当走5的时候,要选取上方3对应的dp,与左方1 对应的dp进行比拟,抉择较小值累加,这样走进去的才是最小值。最初推出,到右下角的最小值。代码如下: sum用来存储,从0到sumi门路的最小和,看看每次sum的变动,sum1=7意思是,从0到1门路最小和是7。程序先把,第2行对应的sum都求进去,再把第2列对应的sum都求进去,最初求sum2就很容易了。最初,sumi-1就是推出的最小值,上述代码就是dp方程的实现。 划分数组为两个相等的子集题目:输出:[1, 5, 11, 5], 输入:[1, 5, 5]和[11] ...

February 27, 2021 · 2 min · jiezi

关于c++:为什么使用初始化列表会快一些

查看上面两段代码: // (1)class classA {...};class classB{public: classB(classA a) {mA = a;}private: classA mA;};// (2)class classA {...};class classB{public: classB(classA a): mA(a) {}private: classA mA;};为什么2的效率要高? 初始化列表的效率要高。 首先把数据成员按类型分类 内置数据类型,复合类型(指针,援用)用户定义类型(类类型)分状况阐明: 对于类型1,在成员初始化列表和构造函数体内进行,在性能和后果上都是一样的对于类型2,后果上雷同,然而性能上存在很大的差异初始化列表,顾名思义,是对成员数据进行初始化,而不是赋值,赋值操作在构造函数体内! 好比: classA a;classA b = a;和 classA a;classA b;b = a;的区别。 上述的代码1不够清晰,咱们写成上面这样: #include <iostream>using namespace std;class classA {public: classA() { cout << "classA()" << endl; } classA(const classA& a) { cout << "copy classA()" << endl; } ~classA() { cout << "~classA()" << endl; } classA& operator=(const classA& a) { cout << "operator=" << endl; return *this; }};class classB{public: classB(classA a) : mA(a) {}private: classA mA;};int main(){ classA a; classB b(a);}// 打印如下://1 classA()//2 copy classA()//3 copy classA()//4 ~classA()//5 ~classA()//6 ~classA()classA a; 调用默认构造函数结构a对象classB(classA a) : mA(a) {}, classB类的构造函数里的 classA a形参拷贝1申明的对象classB(classA a) : mA(a) {}, 初始化列表拷贝2里的形参a的对象2里的形参a析构1里的a析构对象b里的mA析构4,5,6的析构程序没有验证。 ...

February 27, 2021 · 1 min · jiezi

关于c++:虚函数虚表深度剖析

面向对象,从繁多的类开始说起。 class A{private:    int m_a;    int m_b;}; 这个类中有两个成员变量,都是int类型,所以这个类在内存中占用多大的内存空间呢? sizeof(A), 8个字节,一个int占用四个字节。下图验证: 这两个数据在内存中是怎么排列的呢? 原来是这样,咱们依据debug进去的地址画出a对象在内存的结构图 如果 class A 中蕴含成员函数呢? A 的大小又是多少? class A{public:    void func1() {}    private:    int m_a;    int m_b;}; 间接通知你答案,类的成员函数多大? 没人能答复你,并且不是本文的重点,类的成员函数是放在代码区的,不算在类的大小内。 类的对象共享这一段代码,试想,如果每一个对象都有一段代码,光是存储这些代码得占用多少空间?所以同一个类的对象共用一段代码。 共用同一段代码怎么辨别不同的对象呢? 实际上,你在调用成员函数时,a.func1() 会被编译器翻译为 A::func1(&a),也就是A* const this, this 就是 a 对象的地址。 所以依据this指针就能找到对应的数据,通过这同一段代码来解决不同的数据。 接下来咱们讨论一下继承,子类继承父类,将会继承父类的数据,以及父类函数的调用权。 以下的测试能够验证这个状况。 class A{public:    void func1() { cout << "A func1" << endl; }private:    int m_a;    int m_b;};class B : public A{public:    void func2() { cout << "B func2" << endl; }private:    int m_c;};int main(int argc, char const* argv[]){    B b;    b.func1();    b.func2();    return 0;} 输入: // A func1// B func2 那么对象b在内存中的构造是什么样的呢? 继承关系,先把a中的数据继承过去,再有一份本人的数据。 每个蕴含虚函数的类都有一个虚表,虚表是属于类的,而不是属于某个具体的对象,一个类只须要一个虚表即可。同一个类的所有对象都应用同一个虚表。 为了指定对象的虚表,对象外部蕴含指向一个虚表的指针,来指向本人所应用的虚表。为了让每个蕴含虚表的类的对象都领有一个虚表指针,编译器在类中增加了一个指针,*__vptr,用来指向虚表。这样,当类的对象在创立时便领有了这个指针,且这个指针的值会主动被设置为指向类的虚表。 class A{public:    void func1() { cout << "A func1" << endl; }    virtual void vfunc1() { cout << "A vfunc1" << endl; }private:    int m_a;    int m_b;}; cout << sizeof(A);, 输入12,A中包含两个int型的成员变量,一个虚指针,指针占4个字节。 a的内存构造如下: 虚表是一个函数指针数组,数组里寄存的都是函数指针,指向虚函数所在的地位。 对象调用虚函数时,会依据虚指针找到虚表的地位,再依据虚函数申明的程序找到虚函数在数组的哪个地位,找到虚函数的地址,从而调用虚函数。 调用一般函数则不像这样,一般函数在编译阶段就指定好了函数地位,间接调用即可。 class A{public:    void func1() { cout << "A func1" << endl; }    virtual void vfunc1() { cout << "A vfunc1" << endl; }private:    int m_a;    int m_b;};class B : public A{public:    void func1() { cout << "B func1" << endl; }    virtual void vfunc2() { cout << "B vfunc2" << endl; }private:    int m_a;}; 像这样,B类继承自A类,B中又定义了一个虚函数vfunc2, 它的虚表又是怎么样的呢? 给出论断,虚表如下图所示: 咱们来验证一下: A a;B b;void(*avfunc1)() = (void(*)()) *(int*) (*(int*)&a);void (*bvfunc1)() = (void(*)()) *(int*) *((int*)&b);void (*bvfunc2)() = (void(*)()) * (int*)(*((int*)&b) + 4);avfunc1();bvfunc1();bvfunc2();来解释一下代码: void(*avfunc1)() 申明一个返回值为void, 无参数的函数指针 avfunc1, 变量名代表咱们想要取A类的vfunc1这个虚函数。 右半局部的第一局部,(void(*)()) 代表咱们最初要转换成对应上述类型的指针,左边须要给一个地址。 咱们看 (*int(*)&a), 把a的地址强转成int*, 再解援用失去 虚指针的地址。 ...

February 27, 2021 · 1 min · jiezi

关于c++:OpenCV中二维坐标顺序

OpenCV的二维图像中,通过rows、cols、x、y四个属性来示意大小或地位,容易混同。 rows代表的是行,cols代表的是列。 x在cols上,y在rows上。(容易混同) 应留神的构造函数矩阵Mat img(int rows,int cols,int type);//后行(宽)后列(高) 矩形Rect rect(int x,int y,int width, int height);//先横坐标后纵坐标,width对应cols,height对应rows 点Point p(int x,int y);//先横坐标后纵坐标 尺寸Size size(int width,int height);//先宽(行)后高(列) at<>()函数img.at<type>(y,x);//先纵坐标后横坐标 img.at<type>(Point(x,y));//参数为点则先横坐标后纵坐标·

February 26, 2021 · 1 min · jiezi

关于c++:PAT甲级1123-Is-It-a-Complete-AVL-Tree

题目粗心给定一颗均衡二叉树的插入序列,要求输入它的层序序列并判断是否为齐全二叉树。 算法思路首先须要对该AVL树进行建树操作(具体不细说,看代码即可),而后对该树进行层序遍历,一边输入层序变量序列,一遍判断该树是否是齐全二叉树判断二叉树是否是齐全二叉树的办法为: 1、如果以后节点只有右孩子,肯定不是。2、如果以后节点有孩子,然而其前驱节点中存在孩子缺失的状况,那么肯定不是。提交后果 AC代码#include<cstdio>#include<queue>#include<set>using namespace std;struct Node { int v; Node *left; Node *right; int height;};int n;//生成新的结点Node *newNode(int v) { Node *w = new Node; w->v = v; w->height = 1; w->left = nullptr; w->right = nullptr; return w;}int getHeight(Node *root) { if (root == nullptr) { return 0; } else { return root->height; }}int getBalancedFactor(Node *root) { return getHeight(root->left) - getHeight(root->right);}void updateHeight(Node *&root) { root->height = max(getHeight(root->left), getHeight(root->right)) + 1;}void L(Node *&root) { Node *temp = root->right; root->right = temp->left; temp->left = root; updateHeight(root); updateHeight(temp); root = temp;}void R(Node *&root) { Node *temp = root->left; root->left = temp->right; temp->right = root; updateHeight(root); updateHeight(temp); root = temp;}void insert(Node *&root, int x) { if (root == nullptr) { root = newNode(x); return; } if (root->v < x) { insert(root->right, x); // 插入实现后得得更新root的高度 updateHeight(root); if (getBalancedFactor(root) == -2) { if (getBalancedFactor(root->right) == -1) { //RR型须要对root左旋一次 L(root); } else if (getBalancedFactor(root->right) == 1) { // RL型,先对root->right右旋,再对root左旋 R(root->right); L(root); } } } else { insert(root->left, x); // 插入实现后得得更新root的高度 updateHeight(root); if (getBalancedFactor(root) == 2) { if (getBalancedFactor(root->left) == 1) { // LL型须要对root右旋一次 R(root); } else if (getBalancedFactor(root->left) == -1) { // LR型,先对root->left左旋,再对root右旋 L(root->left); R(root); } } }}Node *createTree(int data[]) { Node *root = nullptr; for (int i = 0; i < n; ++i) { insert(root, data[i]); } return root;}bool isComplete = true;bool onlyLeft = false;// 记录前驱是否只有左孩子bool noChildren = false;// 记录前驱是否没有孩子int num = 0;// 打印管制void layerOrder(Node *root) { queue<Node *> q; q.push(root); bool flag1 = false, flag2 = false; while (!q.empty()) { Node *t = q.front(); q.pop(); printf("%d", t->v); if (num < n - 1) { printf(" "); } else { printf("\n"); } ++num; if (t->left) { q.push(t->left); } if (t->right) { q.push(t->right); } // 判断是否是齐全二叉树 if (t->left == nullptr && t->right != nullptr) { // 只有右孩子 isComplete = false; } else if(noChildren||onlyLeft){ if(t->left != nullptr||t->right != nullptr){ // 前驱呈现只有左孩子或者没有孩子的状况,以后节点还有孩子 isComplete = false; } } else if (t->left == nullptr && t->right == nullptr){ // 没有孩子 noChildren = true; } else if(t->left != nullptr && t->right == nullptr){ // 只有左孩子 onlyLeft = true; } }}int main() { scanf("%d", &n); int data[n]; for (int i = 0; i < n; ++i) { scanf("%d", &data[i]); } Node *root = createTree(data); layerOrder(root); if (isComplete) { printf("YES"); } else { printf("NO"); } return 0;}

February 26, 2021 · 2 min · jiezi

关于c++:PAT甲级1122-Hamiltonian-Cycle

题目粗心给定一个无向图,判断查问的门路是否是一个哈密顿圈。 算法思路判断一条门路是一个哈密顿圈的办法为 1、除了首尾节点其余节点没有反复,不反复的节点数目等于N2、首节点只能反复一次,所有节点数目为N+13、首尾节点得相等4、任意两点之间连通在输出每一条门路的时候,首先判断输出节点与上一个输出节点是否连通,如果不是设置flag为false.而后统计节点数目cnt,并将节点增加进set汇合s中,只有s.size()!=n||cnt!=n+1||!flag||start!=End,就阐明该门路不是哈密顿圈,输入NO,否则输入YES。 提交后果 AC代码#include<cstdio>#include<unordered_set>#include<set>#include<vector>using namespace std;int G[205][205];int main() { int n, m; scanf("%d %d", &n, &m); for (int i = 0; i < m; ++i) { int a, b; scanf("%d %d", &a, &b); G[a][b] = G[b][a] = 1; } int k; scanf("%d", &k); for (int i = 0; i < k; ++i) { int num; scanf("%d", &num); unordered_set<int> s; // 终点,节点个数,起点 int start, cnt = 1, End = 0; bool flag = true;// 门路是否连通 scanf("%d", &start); int pre = start; for (int j = 1; j < num; ++j) { int v; scanf("%d", &v); if (G[pre][v] == 0) { flag = false; } if (j == num - 1) { End = v; } pre = v; ++cnt; s.insert(v); } if (s.size() != n || cnt != n + 1 || !flag || start != End) { printf("NO\n"); } else { printf("YES\n"); } } return 0;}

February 26, 2021 · 1 min · jiezi

关于c++:PAT甲级1121-Damn-Single

题目粗心有一个长度为N的couple list,列表上每一行的人都互为情侣,当初有M集体来加入晚会,须要按程序给出没有伴侣的嘉宾 算法思路应用一个map记录每一个人的couple,对于输出的所有的客人,只有没有呈现在couple中,就阐明是独身,增加进singles数组中,如果呈现在了couple中然而其伴侣不在来访嘉宾中,阐明此人也是独身,增加进singles数组中,最初输入singles数组即可。 提交后果 AC代码#include<cstdio>#include<unordered_map>#include<set>#include<vector>using namespace std;unordered_map<int,int> couples;int main() { int n; scanf("%d",&n); for(int i=0;i<n;++i){ int a,b; scanf("%d %d",&a,&b); couples[a+1] = b+1; couples[b+1] = a+1; } int m; scanf("%d",&m); set<int> guests; for(int i=0;i<m;++i){ int a; scanf("%d",&a); guests.insert(a+1); } vector<int> singles; for(auto it:guests){ if(couples[it]==0){ // 没有呈现在couple list上 singles.push_back(it); }else if(guests.find(couples[it])==guests.end()){ // 呈现在了couple list上,然而另外一半没有来 singles.push_back(it); } } printf("%lu\n",singles.size()); for(int i=0;i<singles.size();++i){ printf("%05d",singles[i]-1); if(i<singles.size()-1){ printf(" "); } } return 0;}

February 26, 2021 · 1 min · jiezi

关于c++:PAT甲级1120-Friend-Numbers

题目粗心如果两个数字的位数和雷同,那么就阐明这是一个好友数,当初给定N个数字,要求依照程序输入不同的好友数 算法思路在输出每一个数字的时候计算该数字的位数和,而后增加到set汇合中,set汇合的大小就是不同的好友数目,最初顺次输入set汇合中的元素。 提交后果 AC代码#include<cstdio>#include<set>using namespace std;int calDigitSum(int n){ int r = 0; while(n!=0){ r += n%10; n /= 10; } return r;}int main() { int n; scanf("%d",&n); int num; set<int> s; for(int i=0;i<n;++i){ scanf("%d",&num); s.insert(calDigitSum(num)); } printf("%lu\n",s.size()); int index = 0; for(auto it:s){ printf("%d",it); if(index<s.size()-1){ printf(" "); } ++index; } return 0;}

February 26, 2021 · 1 min · jiezi

关于c++:C怎么判断大小端模式

大小端模式: 大端模式: 先寄存最高无效字节,体现为最高无效字节存储在低地址小端模式: 先寄存最低无效字节,体现为最低无效字节存储在低地址小端模式便于机器解决, 大端模式不便人浏览。 测试平台的字节序模式: // 代码1union test { int a; char b;} c;int main(int argc, char const *argv[]){ c.a = 1; cout << (c.b & 1 ? "小端" : "大端") << endl; return 0;}为什么union能够测出以后平台的字节序到底是大端还是小端呢? union: 共用体,也叫联合体,在一个“联结”内能够定义多种不同的数据类型,一个被阐明为该“联结”类型的变量中,容许装入该“联结”所定义的任何一种数据,这些数据共享同一段内存,以达到节俭空间的目标。 这里所谓的共享不是指把多个成员同时装入一个联结变量内, 而是指该联结变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。 union变量所占用的内存长度等于最长的成员的内存长度。 // 以下程序阐明联结只能对一个成员赋值,所有的变量共享这一段内存union test { int a; char b;} c;int main(int argc, char const *argv[]){ c.a = 65; cout << c.a << endl; // 输入整数65 cout << c.b << endl; // 输入65的ASCII码 c.b = 66; cout << c.a << endl; cout << c.b << endl; return 0;}对于代码1,所以咱们赋值 c.a = 1; 如果是小端模式,内存内 寄存的应该是0x00000001, 此时c.b的值为0x01, 如果是大端模式,寄存的应该是0x01000000, 此时c.b的值为0x00。 ...

February 26, 2021 · 1 min · jiezi

关于c:递归的简单认识c语言

递归程序调用本身的编程技巧称为递归( recursion)。 递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或阐明中有间接或间接调用本身的一种办法,它通常把一个大型简单的问题层层转化为一个与原问题类似的规模较小的问题来求解,递归策略只需大量的程序就可形容出解题过程所须要的多次重复计算,大大地缩小了程序的代码。简而言之,递归就是利用调用本身的办法实现多次重复计算的形式。 设计思维:把问题分解成规模更小,但和原问题有着雷同解法的问题(大事化小) 分类:递归函数又能够分为尾递归和非尾递归函数。尾递归函数是指函数的最初一个动作是调用函数自身的递归函数,是递归的一种非凡情景。尾递归具备两个次要的特色: 调用本身函数(Self-called);计算仅占用常量栈空间(Stack Space)。长处:代码简洁,容易计算验证。 毛病:绝对于循环(迭代),效率低下,存在栈区限度问题(栈溢出)。 特点:后进先出,之后回归先进入的函数再执行下一步。 应用条件:一个问题可能分解成规模更小,且与原问题有着雷同解的问题;存在一个能让递归调用退出的简略进口。 设计条件:设置递归完结的限度条件(尽可能避免栈溢出);设计思路尽可能遵循在每次调用后一直迫近限度条件。 内存分区内存分区分为五种:栈区、堆区、动态区、常量区、代码区。 栈区:寄存函数的参数值(形参)、局部变量和函数调用申请等,由编译器主动调配和开释,通常在函数执行完后就开释了,其操作形式相似于数据结构中的栈。栈内存调配运算内置于CPU的指令集,效率很高,然而调配的内存量无限。 堆区:就是通过new、malloc、realloc和calloc调配的内存块,能够认为是动态分配的内存块,编译器不会负责它们的开释工作,须要用程序区开释。调配形式相似于数据结构中的链表。“内存透露”通常说的就是堆区。 动态区:全局变量和动态变量的存储地位,初始化的全局变量和动态变量在一块区域,未初始化的全局变量和未初始化的动态变量在相邻的另一块区域。程序完结后,由零碎开释。 常量区:常量存储在这里,不容许批改。代码区:寄存编写的代码,不调用。递归引起的栈溢出起因:咱们晓得,正确的递归就是在达到某个限度条件(较小调用次数)之前一直调用函数来实现目标,而每次调用函数都会向栈区申请内存且不开释(函数整体还未完结调用),一旦函数调用过多,栈区容量天然有余,栈溢出也就呈现了。 栈溢出常见谬误:1. 未设置限度条件,函数一直调用。2. 限度条件设置不合理,导致函数调用过多。3. 设计思路存在问题,函数调用完结不再迫近限度条件,导致函数过多调用。 迭代概念迭代是反复反馈过程的流动,其目标通常是为了迫近所需指标或后果。每一次对过程的反复称为一次“迭代”,而每一次迭代失去的后果会作为下一次迭代的初始值。目前对于c语言来说,迭代能够简略认为是循环构造。 递归与迭代递归是一种反复递推与回归过程的构造,而迭代是一种反复循环与更新状态的构造,两者为反复计算服务,实现的形式有所不同。 递归效率低下,循环验证麻烦。迭代能够转换为递归,但递归不肯定能转换为迭代。转换方法:将递归算法转换为非递归算法有两种办法,一种是间接求值(迭代),不须要回溯;另一种是不能间接求值,须要回溯。前者应用一些变量保留两头后果,称为间接转换法,后者应用栈保留两头后果,称为间接转换法。 间接转换法间接转换法通常用来打消尾递归(tail recursion)和单向递归,将递归结构用迭代构造来代替。(单向递归 → 尾递归 → 迭代) 间接转换法递归实际上利用了零碎堆栈实现本身调用,咱们通过应用栈保留两头后果模仿递归过程,将其转为非递归模式。 尾递归函数递归调用返回时正好是函数的结尾,因而递归调用时就不须要保留以后栈帧,能够间接将以后栈帧笼罩掉。

February 26, 2021 · 1 min · jiezi

关于c++:PAT甲级1119-Pre-and-Postorder-Traversals

题目粗心给定一棵二叉树的前序和后序序列,要求判断该树是否惟一并输入中序序列,不惟一的时候输出任意一棵树的中序序列即可 算法思路在给定先序和后序序列后,咱们只能通过先序第一个节点和后序最初一个节点相等来判断残余的左右子树的范畴,然而对于先序和后序中的左右子树的绝对程序是统一的,那么咱们能够设置左子树的长度为leftSize,从0开始进行遍历,只有先序的左子树节点汇合和后序的左子树节点汇合雷同(程序能够不一样),同时先序左子树的首节点和后序左子树的尾节点是雷同的,这样咱们就失去了一个胜利的左右子树的划分,又因为咱们须要判断是否有多种划分后果,在第一次获得成功划分的时候须要持续进行查找,直到取得第二次胜利划分或者没有第二次划分从而退出循环。这里对建树的操作作进一步细说, 1、咱们应用count记录以后子树划分胜利的次数,初始为02、初始设置左子树长度为0,判断是否能够胜利划分的根据就是先序的左子树首节点和后序左子树尾结点是否相等3、判断先序和后序左子树汇合是否雷同的办法,就是应用一个set汇合一次填入先序左子树和后序左子树的节点,其长度恰好为左子树长度就阐明先序和后序左子树汇合雷同4、在每一次获取胜利的划分后就应用leftSize进行记录,并应用全局变量multiChoice记录是否有多个划分可能。5、划分结束之后,先序的左子树范畴为[preL+1,preL+leftSize],右子树范畴为[preL+leftSize+1,preR]。后序的左子树范畴为[postL,postL+leftSize-1],右子树范畴为[postL+leftSize,postR]提交后果 AC代码#include<cstdio>#include<algorithm>#include<unordered_set>#include<vector>using namespace std;int n;int pre[35],post[35];bool multiChoice = false;struct Node{ int v{}; Node* left = nullptr; Node* right = nullptr;};Node* createTree(int preL,int preR,int postL,int postR){ if(preL>preR){ return nullptr; } Node* root = new Node; root->v = pre[preL]; // 统计以后子树划分胜利的次数 int count = 0; // 在左子树长度为0,判断是否能够造成右子树 if(pre[preL+1]==post[postR-1]){ ++count; } int leftSize = 0; unordered_set<int> s; // 遍历左子树长度 int size = preR-preL+1;// 以后子树的长度 for(int i=1;i<size;++i){ s.insert(pre[preL+i]); s.insert(post[postL+i-1]); if(s.size()==i&&pre[preL+1]==post[postL+i-1]){ // 以后划分的左子树元素满足左子树定义 ++count; leftSize = i;// 记录左子树长度 if(count>=2){ // 存在多种划分 multiChoice =true; break; } } } // 先序:左子树范畴为[preL+1,preL+leftSize],右子树范畴为[preL+leftSize+1,preR] root->left = createTree(preL+1,preL+leftSize,postL,postL+leftSize-1); // 后序: 左子树范畴为[postL,postL+leftSize-1],右子树范畴为[postL+leftSize,postR] root->right = createTree(preL+leftSize+1,preR,postL+leftSize,postR-1); return root;}int num = 0;void inOrder(Node* root){ if(root==nullptr) return; inOrder(root->left); printf("%d",root->v); if(num<n-1){ printf(" "); }else{ printf("\n");// 最初得换行 } ++num; inOrder(root->right);}int main() { scanf("%d",&n); for(int i=0;i<n;++i){ scanf("%d",&pre[i]); } for(int i=0;i<n;++i){ scanf("%d",&post[i]); } Node* root = createTree(0,n-1,0,n-1); if(!multiChoice){ printf("Yes\n"); }else{ printf("No\n"); } inOrder(root); return 0;}

February 26, 2021 · 1 min · jiezi

关于c++:PAT甲级1118-Birds-in-Forest

题目粗心当初有N张图片,每一张图片外面有K只鸟,在同一张图片中的鸟属于同一棵树,计算森林中树木的最大数目,并且对于任意一对鸟,判断是否在同一棵树上。 算法思路本题考查并查集的利用,咱们应用set汇合birds保留所有的输出的鸟,并在输出每一张图片的时候,将其中所有的鸟进行合并为一组,而后对于birds中所有的鸟类依据其先人归并为一棵树,并存放到set汇合trees中,最初对于任意两个鸟的编号,只须要比拟father数组的值是否雷同即可。 留神点1、查找father的办法得应用门路压缩,不然会有一个测试点超时。提交后果 AC代码#include<cstdio>#include<algorithm>#include<unordered_set>#include<vector>using namespace std;unordered_set<int> birds;unordered_set<int> trees;int father[10005];int findFather(int x){ int a = x; while(x!=father[x]){ x = father[x]; } while (a!=father[a]){ int z = father[a]; father[a] = x; a = z; } return x;}void Union(int a,int b){ int fa = findFather(a); int fb = findFather(b); if(fa!=fb){ father[fa] = fb; }}int main() { for(int i=0;i<=10000;++i){ father[i] = i; } int n; scanf("%d",&n); for(int i=0;i<n;++i){ int k; scanf("%d",&k); vector<int> t(k); for(int j=0;j<k;++j){ scanf("%d",&t[j]); birds.insert(t[j]); if(j!=0){ Union(t[j],t[j-1]); } } } for(auto it:birds){ int f=findFather(it); trees.insert(f); } printf("%lu %lu\n",trees.size(),birds.size()); int query; scanf("%d",&query); for(int i=0;i<query;++i){ int a,b; scanf("%d %d",&a,&b); if(father[a]==father[b]){ printf("Yes\n"); }else{ printf("No\n"); } } return 0;}

February 26, 2021 · 1 min · jiezi

关于c#:手把手教你爬取优酷电影信息2

上一章节中咱们实现了对优酷单页面的爬取,简略进行回顾一下,应用HtmlAgilityPack库,对爬虫的爬取一共分为三步 爬虫步骤 加载页面解析数据保留数据继第一篇文档后的爬虫进阶,本文章次要是对上一篇的进阶。实现的性能次要为:1、爬取电影类别列表2、循环每个类别的电影信息,对每个类别的信息分页爬取3、爬取的数据保留到数据库中 一、爬取电影类别列表 应用Chrome浏览器,F12,找到以后地位,失去以后地位的Xpath。咱们须要的数据是电影的类别编码和电影类别名称。 规定剖析:XPATH门路为 "//*[@id='filterPanel']/div/ul/li/a")类别编码为A标签Href门路的内容,咱们对其进行截取类别名称为A标签InnerTest,咱们对其进行截取 代码示例 //加载web内容 private static readonly string _url = "http://list.youku.com/category/video/c_0.html"; /// <summary> /// 失去所有的类别 /// </summary> public static List<VideoType> GetVideoTypes() { //加载web内容 var web = new HtmlWeb(); var doc = web.Load(_url); //内容解析-取得所有的类别 var allTypes = doc.DocumentNode.SelectNodes("//*[@id='filterPanel']/div/ul/li/a").ToList(); //类别列表中去掉【全副】这个选项 var typeResults = allTypes.Where((u, i) => { return i > 0; }).ToList(); var reList = new List<VideoType>(); foreach (var node in typeResults) { var href = node.Attributes["href"].Value; reList.Add(new VideoType { Code = href.Substring(href.LastIndexOf("/") + 1, href.LastIndexOf(".") - href.LastIndexOf("/") - 1), Name = node.InnerText }); } return reList; }二、爬取每个类别的总分页数code 为电影类别编码页面规定 $"http://list.youku.com/category/show/{code}.html"依据页面规定进行爬取: ...

February 26, 2021 · 2 min · jiezi

关于c++:PAT甲级1117-Eddington-Number

题目粗心给定N天中每一天的骑行间隔,如果有E天的骑行间隔大于E,那么E就称之为艾丁顿数,请找出这个数字(尽可能大) 算法思路既然要找到E的最大值,那么在每一天的骑行间隔大于N的时候,E获得最大值N,这也是E的初始值。咱们能够想到,(数组的下标值+1)其实就是第几天,那么将骑行的间隔逆序排序,这样对于骑行间隔大于(以后下标值+1)的地位,就是E的一个可能取值(E取下标值+1),咱们为了获得最大值就是一直往右挪动,晓得第一次呈现骑行间隔小于等于以后下标值+1的地位,那么其右边就是E的最大值. 提交后果 AC代码#include<cstdio>#include<algorithm>#include<unordered_set>#include<vector>using namespace std;bool cmp(int a,int b){ return a>b;}int main() { int n; scanf("%d",&n); int num[n]; for(int i=0;i<n;++i){ scanf("%d",&num[i]); } sort(num,num+n,cmp); int E = n;// 没有解的时候,E为n for(int i=0;i<n;++i){ if(num[i]<=i+1){ E = i; break; } } printf("%d\n",E); return 0;}

February 26, 2021 · 1 min · jiezi

关于c++:PAT甲级1116-Come-on-Lets-C

题目粗心给定一个长度为N的排名列表和长度为K的查问列表,须要你依照如下规定输入每一个查问的后果. 1、排名第一的取得Mystery Award奖品2、排名为素数的取得Minion奖品3、所有其余加入较量的人均取得Chocolate奖品4、对于非法查问输入Are you kidding?5、对于反复查问输入Checked算法思路依照规定模仿即可,应用valid数组记录非法的输出,Rank记录每一个人的排名,checked数组记录曾经查问的记录,对于每一次查问,首先判断是否非法,如果非法再判断是否曾经查问过,如果没有,就依照1,2,3规定进行查问即可,最初得将checked[query]置为true 提交后果 AC代码#include<cstdio>#include<algorithm>#include<cmath>#include<vector>using namespace std;int valid[10000];int checked[10000];int Rank[10000];bool isPrime(int x){ if(n<=1) return false; int n = (int)sqrt(x*1.0); for(int i=2;i<=n;++i){ if(x%i==0){ return false; } } return true;}int main() { int n; scanf("%d",&n); vector<int> v(n); for(int i=0;i<n;++i){ scanf("%d",&v[i]); valid[v[i]] = true; Rank[v[i]] = i+1; } int k; scanf("%d",&k); for(int i=0;i<k;++i){ int query; scanf("%d",&query); if(!valid[query]){ printf("%04d: Are you kidding?\n",query); }else{ if(checked[query]){ printf("%04d: Checked\n",query); }else if(query==v[0]){ printf("%04d: Mystery Award\n",query); }else if(isPrime(Rank[query])){ printf("%04d: Minion\n",query); }else{ printf("%04d: Chocolate\n",query); } checked[query] = true; } } return 0;}

February 26, 2021 · 1 min · jiezi

关于c#:如何将IHttpHandler和IHttpModule迁移到ASPNET-Core中间件

ASP.NET Core是一个跨平台、开源的框架,用于在Windows、Mac和Linux操作系统(OS)上开发web应用程序。你能够应用以下任何IDE开发ASP.NET Core 应用程序: Visual StudioVisual Studio for MacVisual Studio Code在这篇博文中,咱们将学习如何如何将asp.net IHttpHandler和IHttpModule迁徙到ASP.NET Core中间件并提供代码示例。 让咱们开始吧! ASP.NET IHttpHandler 在ASP.NET应用程序中,HTTP处理程序是一个过程,它在对向web服务器的每个响应上执行。咱们能够创立本人的自定义HTTP处理程序。 上面是将所有.aspx页重定向到一个新页的代码。 public class RedirectionHandler : IHttpHandler{ public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { var response = context.Response; response.Write("<p>Process files with .aspx extension</p>"); // Any redirection logic can be written here. }}web.config中增加如下代码: <add name="RedirectionHandler" verb="*" path="*.aspx" type="MyWebApplication.RedirectionHandler" resourceType="Unspecified"/>ASP.NET IHTTPModule IHttpModule还将在应用程序的每个申请的HTTP处理程序执行之前和之后。它们帮忙咱们验证传入和传出的申请并批改它们。 上面是用于依据用户的IP地址限度用户的IHttpModule代码。 public class IPRestrictionModule : IHttpModule{ public void Init(HttpApplication context) { context.BeginRequest += (source, arguments) => { var application = (HttpApplication)source; var beginContext = application.Context; beginContext.Response.Write("<p>Restrict Users based on IP</p>"); // Code logic comes here. }; context.EndRequest += (source, arguments) => { var application = (HttpApplication)source; var endContext = application.Context; endContext.Response.Write("<p>Request ended.</p>"); }; }}web.config中增加如下代码: ...

February 26, 2021 · 2 min · jiezi

关于c#:手把手教你爬取优酷电影信息-1

爬虫的制作次要分为三个方面1、加载网页构造2、解析网页构造,转变为合乎需要的数据实体3、保留数据实体(数据库,文本等) 在理论的编码过程中,找到了一个好的类库“HtmlAgilityPack”。介绍:官网:http://html-agility-pack.net/...Html Agility Pack源码中的类大略有28个左右,其实不算一个很简单的类库,但它的性能确不弱,为解析DOM曾经提供了足够弱小的性能反对,能够跟jQuery操作DOM媲美) 应用阐明:Html Agility Pack(XPath 定位),在理论应用过程中,发现有局部内容如果通过Css进行定位会比XPath更加不便,所以通过查找找到了另外一个CSS的解析了类库 ScrapySharp(Css 定位) 整顿:Nuget包须要援用的库1、Html Agility Pack(XPath 定位)2、ScrapySharp(Css 定位) 代码下载地址: https://github.com/happlyfox/FoxCrawler第一点——加载网页构造Html Agility Pack封装了加载内容的办法,使doc.Load(arguments),具备多种重载形式,以下列举官网的三个实例 /// <summary> /// 加载网页构造 /// </summary> private static void LoadDocment() { // 从文件中加载 var docFile = new HtmlDocument(); docFile.Load("file path"); // 从字符串中加载 var docHtml = new HtmlDocument(); docHtml.LoadHtml("html"); // 从网站中加载 var url = "http://html-agility-pack.net/"; var web = new HtmlWeb(); var docWeb = web.Load(url); }第二点——解析网页构造,转变为合乎需要的数据实体 /// <summary> /// 解析网页构造 /// </summary> private static YouKu ParsingWebStructure() { /*选用优酷片库列表 地址:http://list.youku.com/category/show/c_96_s_1_d_1_p_{index}.html */ //首先加载web内容 var url = "http://list.youku.com/category/show/c_96_s_1_d_1_p_1.html"; var web = new HtmlWeb(); var doc = web.Load(url); //输入WebHtml内容 //Console.WriteLine(doc.DocumentNode.InnerHtml); /* HtmlAgilityPack 解析形式官网提供的有俩种示例*/ //1、 With XPath var value = doc.DocumentNode.SelectSingleNode("//*[@id='total_videonum']").Attributes["id"].Value; var resultCount = doc.DocumentNode.SelectSingleNode("//*[@id='total_videonum']").InnerText; Console.WriteLine($"id='{value}' 筛选后果:{resultCount}个"); // 2、With LINQ var linqNodes = doc.DocumentNode.SelectSingleNode("//*[@id='filterPanel']/div[2]/ul").Descendants("li").ToList(); Console.WriteLine("电影产地:"); List<string> videoCountry = new List<string>(); foreach (var node in linqNodes) { videoCountry.Add(node.InnerText); Console.Write($"{node.InnerText} \t"); } //3、应用ScrapySharp进行Css定位 var cssNodes = doc.DocumentNode.CssSelect("#filterPanel > div > label"); Console.WriteLine(); List<string> videoType = new List<string>(); foreach (var node in cssNodes) { videoType.Add(node.InnerText); Console.Write($"{node.InnerText} \t"); } //结构实体 YouKu model = new YouKu() { id = value, videoNum = int.Parse(resultCount), videoCountry = videoCountry, videoType = videoType }; return model; }public class YouKu{ public string id { get; set; } public int videoNum { get; set; } public List<string> videoCountry { get; set; } public List<string> videoType { get; set; }}第三点——保留数据实体,转变为合乎需要的数据实体 /// <summary> /// 保留数据实体 /// </summary> private static void SavaData() { var model = ParsingWebStructure(); var path = "youku.txt"; if (!File.Exists(path)) { File.Create(path); } File.WriteAllText(path, getJsonByObject(model)); } private static string getJsonByObject(Object obj) { //实例化DataContractJsonSerializer对象,须要待序列化的对象类型 DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType()); //实例化一个内存流,用于寄存序列化后的数据 MemoryStream stream = new MemoryStream(); //应用WriteObject序列化对象 serializer.WriteObject(stream, obj); //写入内存流中 byte[] dataBytes = new byte[stream.Length]; stream.Position = 0; stream.Read(dataBytes, 0, (int)stream.Length); //通过UTF8格局转换为字符串 return Encoding.UTF8.GetString(dataBytes); }四 Main static void Main(string[] args) { ///爬虫的制作次要分为三个方面 ///1、加载网页构造 ///2、解析网页构造,转变为合乎需要的数据实体 ///3、保留数据实体(数据库,文本等) /* * 在理论的编码过程中,找到了一个好的类库“HtmlAgilityPack”。 * 介绍: * 官网:http://html-agility-pack.net/?z=codeplex * Html Agility Pack源码中的类大略有28个左右,其实不算一个很简单的类库,但它的性能确不弱,为解析DOM曾经提供了足够弱小的性能反对,能够跟jQuery操作DOM媲美) * 应用阐明: * Html Agility Pack(XPath 定位),在理论应用过程中,发现有局部内容如果通过Css进行定位会比XPath更加不便,所以通过查找找到了另外一个CSS的解析了类库 ScrapySharp(Css 定位) * 整顿: * Nuget包须要援用的库 * 1、Html Agility Pack(XPath 定位) * 2、ScrapySharp(Css 定位) */ //第一点——加载网页构造,Html Agility Pack封装了加载内容的办法,应用doc.Load(arguments),具备多种重载形式,以下列举官网的三个实例 //LoadDocment(); //第二点——解析网页构造,转变为合乎需要的数据实体 //ParsingWebStructure(); //第三点——保留数据实体,转变为合乎需要的数据实体 SavaData(); Console.Read(); }

February 26, 2021 · 2 min · jiezi

关于c#:进击吧Blazor第一章-5组件开发

《进击吧!Blazor!》是自己与张善友老师单干的Blazor零根底入门系列视频,此系列能让一个从未接触过Blazor的程序员把握开发Blazor利用的能力。视频地址:https://space.bilibili.com/48...本系列文章是基于《进击吧!Blazor!》直播内容编写,降级.Net5,改良问题,解说更全面。因为篇幅无限,文章中省略了局部代码,残缺示例代码:https://github.com/TimChen44/...作者:陈超超Ant Design Blazor 我的项目贡献者,领有十多年从业教训,长期基于.Net技术栈进行架构与开发产品的工作,现就职于正泰团体。邮箱:timchen@live.com欢送各位读者有任何问题分割我,咱们共同进步。 这次分享我么要聊聊Blazor的精华,也是我集体认为Blazor框架体系中最优良的个性——组件。 组件组件(Component)是对数据和办法的简略封装。简直所有UI相干的框架都有组件(控件)的概念。 晚期的Delphi组件叫做VCL(Visual Component Library),它采纳本身嵌套的形式组合成所需的用户界面,并提供属性,办法,事件与组件内部进行交互,本身有着独立的生命周期,在必要的时候进行销毁。 之后.Net的WinForms和WPF组件绝对于Delphi尽管设计实现上齐全不同,然而对组件的定义和用处上简直统一。 当初Web前端框架Angular中也采纳了组件的概念,整体理念仍旧类似。 有些框架依据是否可见将组件分为,组件(Component)不可见,控件(Control)可见,比方Delphi,WinForms纵观这些框架的组件设计,能够提炼出组件蕴含以下个性。Blazor利用也是应用组件构建的。组件是自蕴含的用户界面 (UI) 块,例如页、对话框或窗体。 组件蕴含插入数据或响应 UI 事件所需的 HTML 标记和解决逻辑。 组件非常灵活且轻量。 可在我的项目之间嵌套、重复使用和共享。 1.参数(属性)提供组件内部向组件外部传递数据的形式。 在Blazor中咱们称组件的属性(Property)叫参数(Parameter),参数自身就是一个属性,然而为了让Blazor框架能辨别两者,所以咱们在属性上减少 [Parameter]个性来申明属性为组件的参数。 [Parameter]public string Text { get; set; }组件参数组件参数能够接管来在razor页面中给与的值,反对简略类型,也能够反对简单类型。 <!--组件代码--><h1>Blazor is @Text!</h1>@code { [Parameter] public string Text { get; set; }}<!--组件应用--><Component Title="Superior">上例就是将Superior通过参数传入组件,组件中就会输入Blazor is Superior! 路由参数组件能够接管来自 @page 指令所提供的路由模板的路由参数。 路由器应用路由参数来填充相应的组件参数。参数类型受限于路由规定,只反对几个根本类型。 <!--页面代码-->@page "/RouteParameter/{text}"<h1>Blazor is @Text!</h1>@code { [Parameter] public string Text { get; set; }}当应用/RouteParameter/Superior地址进行路由时,跳转到上例中的页面,并且页面输入Blazor is Superior! 级联参数在某些状况下,应用组件参数将数据从先人组件流向子代组件不太不便,尤其是在有多个组件层时。 级联值和参数提供了一种不便的办法,使先人组件为其所有子代组件提供值,从而解决了此问题。 先人组件中应用CascadingValue设定须要向下传递的级联值,子代组件中应用 [CascadingParameter] 个性来申明级联参数用于接管级联值。 ...

February 25, 2021 · 5 min · jiezi

关于c++:关于面向对象的面试知识点整理一

例1: C++ 中的空类默认产生哪些类成员函数? 对于一个空类,编译器默认产生4个成员函数:默认构造函数、 析构函数、 拷贝构造函数和赋值函数。 例2: structure是否能够领有constructor / destructor及成员函数?如果能够, 那么structure和class还有区别么? 区别是class中变量默认是private, struct中的变量默认是public。struct能够有构造函数,析构函数,之间也能够继承,等等。 C++中的struct其实和class意义一样, 惟一不同的就是struct外面默认的访问控制是public, class中默认的访问控制是 private。 C++中存在struct关键字的惟一意义就是为了让C程序员们有个归属感, 是为了让C++编译器兼容以前用C开发的我的项目。 例3: 现有以下代码, 则编译时会产生谬误的是? struct Test{ Test(int) {} Test() {} ~Test() {} void fun() {}};int main(){ Test a(1); a.fun(); Test b(); b.fun(); return 0;}Test b() 这个语法等同于申明了一个函数,函数名为b, 返回值为Test, 传入参数为空。然而实际上,代码作者是心愿申明一个类型为Test,变量名为b的变量,应该写成Test b;, 但程序中这个谬误在编译时是检测不进去的。出错的是b.fun(),它是编译不过来的。 例4: 上面程序的打印出的后果是什么? #include <iostream>using namespace std; class Base{public: Base(int i) : m_j(i), m_i(m_j) {} Base() : m_j(0), m_i(m_j) {} ~Base() {} int get_i() const { return m_i; } int get_j() const { return m_j; } private: int m_i; int m_j;};int main(){ Base obj(98); cout << obj.get_i() << endl; cout << obj.get_j() << endl; return 0;}本题想要失去的后果是"98,98"。 然而成员变量的申明是先m_i, 而后是m_j;初始化列表的初始化变量程序是依据成员变量的申明程序来执行的, 因而m_i会被赋予一个随机值。更改一下成员变量的申明程序能够失去料想的后果。 如果要失去 "98,98"的输入后果,程序须要批改如下 ...

February 25, 2021 · 3 min · jiezi

关于c:三子棋小游戏C语言数组实现

一、游戏成果 二、游戏规则    ❶ 输出1进入页游戏     ❷ 输出0退出页游戏     ❸ 玩家先走     ❹ 玩家落子是抉择棋盘的坐标地位     ❺ 电脑是随机落子     ❻ 如果电脑连了三子则提醒电脑赢了,抉择要不要持续游戏 三、实现游戏的代码思路✪ 先构架游戏整体思路void game(){ char ret = 0; //数组寄存棋盘信息 char board[ROW][COL] = { 0 };//二维数组的初始化并没有这么简略 int row = ROW; int col = COL; //1.初始化棋盘 //肯定要初始化 InitBoard(board, ROW, COL); //2.打印棋盘 DisplayBoard(board, ROW, COL); //3.玩游戏,开始下棋了 while (1) { //玩家下棋 PlayerMove(board, ROW, COL); DisplayBoard(board, ROW, COL); //判断玩家是否赢了 ret = Iswin(board, ROW, COL); //如果不是游戏持续,那么就间接跳出循环 if (ret != 'D') { break; } //电脑下棋 ComputerMove(board, ROW, COL); DisplayBoard(board, ROW, COL); //判断电脑是否赢了 ret = Iswin(board, ROW, COL); //如果不是游戏持续,那么就间接跳出循环 if (ret != 'D') { break; } } if (ret == 'X') printf("玩家赢了\n"); else if (ret == 'O') printf("电脑赢了\n"); else printf("平局\n");}✪ 再分步写出相应所需函数1、菜单函数 ...

February 25, 2021 · 3 min · jiezi

关于c#:线程安全Ⅱ

混合模式因为用户模式和内核模式各有优劣,为了利用两者各自的有点,因而能够同时应用两种模式来进行结构,在没有线程竞争的时候能够具备用户模式的性能劣势,而在多个线程同时竞争一个结构的时候又能提供不产生自旋的长处,使应用程序的性能失去晋升。 示例代码class HybridLock : IDisposable{ private int m_Waiters = 0; private AutoResetEvent m_WaiterLock = new AutoResetEvent(false); public void Enter() { //线程想要取得锁 if (Interlocked.Increment(ref this.m_Waiters) == 1) return; //锁能够应用直,接返回 //另一个线程正在期待,阻塞该线程 this.m_WaiterLock.WaitOne(); //产生较大的性能影响 //WaitOne返回后,这个线程便领有了锁 } public void Leave() { //这个线程筹备开释锁 if (Interlocked.Decrement(ref this.m_Waiters) == 0) return; //没有其它线程阻塞,间接返回 //有其它线程正在阻塞,唤醒其中一个 this.m_WaiterLock.Set(); //产生较大的性能影响 } public void Dispose() { this.m_WaiterLock.Dispose(); }}剖析代码HybridLock对象的Enter办法调用了Interlocked.Increment,让m_Waiters字段递增1,这个线程发现没有线程领有这个锁,因而该线程取得锁并间接返回(取得锁的速度十分快)。如果另一个线程染指并调用Enter,此时m_Waiters字段再次递增值为2,发现锁被另一个线程领有,所以这个线程会调用AutoResetEvent对象的WaitOne来阻塞自身(这里因为是内核模式所以会产生性能影响),避免自旋。 再看看Leave办法,一个线程调用Leave时,会调用Interlocked.Decrement使m_Waiters字段递加1,如果m_Waiters字段是0,阐明没有其它线程在Enter的调用中产生阻塞,这时线程能够间接返回。然而如果线程发现m_Waiters字段的值递加后不为0,阐明存在线程竞争,至多有一个线程在内核中阻塞,这个线程必须只能唤醒一个阻塞的线程,通过调用AutoResetEvent对象的Set办法实现, 自旋、线程所有权和递归因为转换成内核代码会造成性能损失,而线程占有一个锁的工夫通常比拟短,所以能够先让线程处于用户模式且自旋一段时间,若还未取得锁的权限便可让它转为内核模式,如果线程在期待期间锁变得可用便可防止转为内核模式了。 示例代码(提供自旋、线程所有权和递归反对)class HybridLock : IDisposable{ //用户模式 private int m_Waiters = 0; //内核模式 private AutoResetEvent m_WaiterLock = new AutoResetEvent(false); //管制自旋 private int m_SpinCount = 1000; //用有锁的线程 private int m_OwningThreadId = 0; //领有次数 private int m_Recursion = 0; public void Enter() { //如果线程曾经领有,递增递归次数并返回 var threadId = Thread.CurrentThread.ManagedThreadId; if(this.m_OwningThreadId == threadId) { this.m_Recursion++; return; } //尝试获取 var spinWait = new SpinWait(); for (int i = 0; i < this.m_SpinCount; i++) { //如果锁能够应用了 if (Interlocked.CompareExchange(ref this.m_Waiters, 1, 0) == 0) goto GotLock; //给其它线程运行的机会,心愿锁会被开释 spinWait.SpinOnce(); } //自旋完结,依然没有取得锁则再试一次 if(Interlocked.Increment(ref this.m_Waiters) > 1) { //有其它线程被阻塞,这个线程也必须阻塞 this.m_WaiterLock.WaitOne(); //性能损失 //期待该线程用有锁醒来 } GotLock: //一个线程用有锁时,记录ID并指出线程领有锁一次 this.m_OwningThreadId = threadId; this.m_Recursion = 1; } public void Leave() { //如果线程不必有锁,bug var threadId = Thread.CurrentThread.ManagedThreadId; if (threadId != this.m_OwningThreadId) throw new SynchronizationLockException("线程未领有锁!"); //递加递归计数,如果线程依然用有锁,间接返回 if (--this.m_Recursion > 0) return; //当初没有线程领有锁 this.m_OwningThreadId = 0; //若没有其它线程被阻塞间接返回 if (Interlocked.Decrement(ref this.m_Waiters) == 0) return; //唤醒一个被阻塞的线程 this.m_WaiterLock.Set(); //性能损失 } public void Dispose() { this.m_WaiterLock.Dispose(); }}Monitor类这个类提供了一个互斥锁,这个锁反对自旋、线程所有权和递归,是线程同步罕用的类。 ...

February 25, 2021 · 2 min · jiezi

关于c++:PAT甲级1115-Counting-Nodes-in-a-BST

题目粗心给定一颗二叉搜寻树的插入序列,计算最初两层的节点个数 算法思路首先咱们将这n个数字顺次插入到二叉搜寻树中,而后应用层序遍历获取每一层节点的数目和最大层数maxLevel,L[maxLevel],L[maxLevel-1]就是最初一层和倒数第二层的节点个数 提交后果 AC代码#include<cstdio>#include<algorithm>#include<queue>using namespace std;struct Node{ int val; Node* left; Node* right; int level;};/// 将x插入到root中void insert(Node* &root,int x){ if(root== nullptr){ root = new Node; root->val = x; root->left = nullptr; root->right = nullptr; return; } if(root->val<x){ insert(root->right,x); }else{ insert(root->left,x); }}// 依据数组arr建树Node* createTree(int arr[],int n){ Node* root = nullptr; for(int i=0;i<n;++i){ insert(root,arr[i]); } return root;}int L[1000];// 每一层的节点个数int maxLevel = -1;void layerOrder(Node* root){ queue<Node*> que; root->level = 1; que.push(root); while(!que.empty()){ Node* t = que.front(); que.pop(); maxLevel = max(maxLevel,t->level); ++L[t->level]; if(t->left){ t->left->level = t->level + 1; que.push(t->left); } if(t->right){ t->right->level = t->level + 1; que.push(t->right); } }}int main() { int n; scanf("%d",&n); int initial[n]; for(int i=0;i<n;++i){ scanf("%d",&initial[i]); } Node* root = createTree(initial,n); layerOrder(root); printf("%d + %d = %d",L[maxLevel],L[maxLevel-1],L[maxLevel-1]+L[maxLevel]); return 0;}

February 25, 2021 · 1 min · jiezi

关于c++:PAT甲级1114-Family-Property

题目粗心给定一个人的家庭成员及其房产信息,须要晓得每一个家庭的人数,均匀占地面积和房产数目。 算法思路这是一道惯例的并查集利用题目,咱们首先应用families数组保留所有的输出集,并在输出的时候记录哪些是输出的成员(应用visited记录),并且合并那些是一家人的成员,这样就将所有成员都进行了归类在各自的家庭,而后计算每一个家庭的占地总面积和总房产数目,并且应用flag标记以后家庭(在[0,10000]中有意义的家庭),而后在[0,10000]的所有人中统计所有的家庭成员数目(visited[i]=true的就是)和家庭数目(flag为true的人代表一个家庭),最初计算房子的均匀面积和数目。 留神点1、在输出的时候families的下标是从0开始到n-1完结,这样不便遍历输出的成员并进行信息计算2、计算房子的均匀面积和数目的时候,得应用总共的信息total_*除以家庭人数,因为该计算过程会执行屡次。提交后果 AC代码#include<cstdio>#include<algorithm>#include<vector>using namespace std;struct Family { int ID; int father; int mother; vector<int> children; int estate; int area;} families[1001];// 存储后果集struct Node { int ID; int total_number; double Avg_sets; double Avg_area; int total_sets; int total_area; bool flag;// 标记以后家庭} nodes[10000];bool cmp(const Node &a, const Node &b) { return a.Avg_area != b.Avg_area ? a.Avg_area > b.Avg_area : a.ID < b.ID;}// 统计在[0,10000]中哪些是存在的成员bool visited[10000];// 记录每一个人的先人(可能不在输出中)int father[10000];// 找到x的先人,这里采纳了压缩门路的形式int findFather(int x) { int a = x; while (x != father[x]) { x = father[x]; } while (a != father[a]) { int z = father[a]; father[a] = x; a = z; } return x;}void Union(int a, int b) { int fa = findFather(a); int fb = findFather(b); if (fa < fb) { father[fb] = fa; } else { father[fa] = fb; }}int main() { for (int i = 0; i < 10000; ++i) { father[i] = i; } int n; scanf("%d", &n); Family member; int k; for (int i = 0; i < n; ++i) { scanf("%d %d %d %d", &member.ID, &member.father, &member.mother, &k); int child; for (int j = 0; j < k; ++j) { scanf("%d", &child); member.children.push_back(child); visited[child] = true; Union(member.ID, child); } scanf("%d %d", &member.estate, &member.area); families[i] = member; visited[member.ID] = true; if (member.father != -1) { visited[member.father] = true; Union(member.ID, member.father); } if (member.mother != -1) { visited[member.mother] = true; Union(member.ID, member.mother); } } // 将所有归类的家庭进行计算相干信息 for (int i = 0; i < n; ++i) { int id = findFather(families[i].ID); nodes[id].ID = id; nodes[id].total_area += families[i].area; nodes[id].total_sets += families[i].estate; nodes[id].flag = true; } int num = 0; // 统计家庭成员人数和家庭数目 for (int i = 0; i < 10000; ++i) { if (visited[i]) { int id = findFather(i); ++nodes[id].total_number; } if (nodes[i].flag) { ++num; } } // 计算房子的均匀面积和均匀数目 for (int i = 0; i < 10000; ++i) { if (visited[i]) { int id = findFather(i); nodes[id].Avg_area = nodes[id].total_area*1.0/nodes[id].total_number; nodes[id].Avg_sets = nodes[id].total_sets*1.0/nodes[id].total_number; } } printf("%d\n", num); sort(nodes,nodes+10000,cmp); for(int i=0;i<num;++i){ printf("%04d %d %.3f %.3f\n",nodes[i].ID,nodes[i].total_number,nodes[i].Avg_sets,nodes[i].Avg_area); } return 0;}

February 25, 2021 · 2 min · jiezi

关于c++:PAT甲级1113-Integer-Set-Partition

题目粗心给定一个汇合,含有n个数字,要求将其划分为长度为n1和n2的两个汇合,并且要求两个汇合和之差最大,n1与n2的差距最小 算法思路最为直观的感触就是将数组进行排序,而后选取n/2长度的前半部分为第一个局部,剩下的为第二局部,这样两者元素个数之差最小,和之差最大。 提交后果 AC代码#include <iostream>#include <algorithm>#include <vector>using namespace std;int main() { int n, sum = 0, temp = 0; scanf("%d", &n); int v[n]; for (int i = 0; i < n; i++) { scanf("%d", &v[i]); sum += v[i]; } sort(v, v+n); for (int i = 0; i < n / 2; i++) temp += v[i]; printf("%d %d", n % 2, sum - 2 * temp); return 0;}

February 25, 2021 · 1 min · jiezi

关于c++:PAT甲级1112-Stucked-Keyboard

题目粗心给定k和一个字符串s,因为一些键盘的按键损坏,损坏的键按一下会反复呈现k次,要求你找出所有的坏件和原始输出字符串。 算法思路一个键是坏键的前提是该字符每一次间断呈现的次数肯定是k的整数倍,那么咱们能够先采纳hasShownNotStucked哈希表记录那些肯定是好键的字符,又因为坏键只记录一次就好,所以应用hasShownStucked记录记录曾经呈现过并确定是坏键的按键,防止反复增加。咱们采纳两边遍历的形式进行求解 第一次遍历将所有肯定是好键的字符全副记录,具体做法就是比拟以后字符和后一字符是否相等,如果不等那么肯定不是坏键,否则统计其呈现的次数cnt,只有以后字符没有确定为好键并且cnt%n!=0,那么就阐明该键为好键。 第二次遍历进行获取反复的字符组成的字符串repeated和原始字符串origin,具体做法就是,如果以后字符肯定是好键,那么就增加进origin中,否则就得计算呈现的次数cnt,并让origin增加cnt/n个s[i],判断以后字符是否曾经记录为坏键,如果没有就记录该坏键并增加该字符到repeated中。 留神点1、一个键有可能之前呈现k的整数倍次,然而最初呈现的次数不能整除k,那么就阐明不是坏键,比方k=3,s=eeerre,其中e就是好键,所以须要先遍历一遍将所有肯定是好键的键进行记录。提交后果 AC代码#include<cstdio>#include<iostream>#include<unordered_map>using namespace std;unordered_map<char,bool> hasShownNotStucked;// 记录好键unordered_map<char,bool> hasShownStucked;// 记录曾经呈现过并确定是坏键的按键int main() { int n; scanf("%d",&n); string s; cin>>s; string repeated,origin; int i; // 第一次遍历记录所有肯定不是坏键的键 for(i=0;i<s.size()-1;){ if(s[i]!=s[i+1]){ // 以后按键只呈现了一次,肯定不是坏键 hasShownNotStucked[s[i]] = true; ++i; }else{ // 统计呈现反复的次数 int cnt = 0; for(int j=i;j<s.size();++j){ if(s[j]==s[i]){ ++cnt; }else{ break; } } if(!hasShownNotStucked[s[i]]&&cnt%n!=0){ // 以后字符之前不确定,然而无奈整除n阐明肯定不是坏键 hasShownNotStucked[s[i]] = true; } i += cnt; } } if(i<s.size()){ // s[i]!=s[i+1],阐明最初一个键也不是坏键 hasShownNotStucked[s[i]] = true; } for(i=0;i<s.size();){ if(hasShownNotStucked[s[i]]){ // 肯定不是坏键 origin += s[i++]; }else{ // 有可能是坏键 // 统计呈现反复的次数 int cnt = 0; for(int j=i;j<s.size();++j){ if(s[j]==s[i]){ ++cnt; }else{ break; } } // 反复增加cnt/n个s[i] int a = cnt/n; while(a--){ origin += s[i]; } if(!hasShownStucked[s[i]]){ // 之前没有增加过该反复字符 hasShownStucked[s[i]] = true; repeated += s[i]; } i += cnt; } } cout<<repeated<<endl<<origin; return 0;}

February 25, 2021 · 1 min · jiezi

关于c++:我整理了这篇指针的知识点想必对你有用

指针和援用的区别非空区别: 任何状况下都不能应用指向空值的援用,一个援用必须总是指向某些对象。 指针能够指向空。合法性区别: 援用在应用之前不须要测试合法性,指针应该总是要被测试,避免其为空可修改性区别: 援用在初始化时指定对象,当前不能批改。指针传递动态内存例1: 程序测试后会有什么后果? #include<iostream>#include<cstring>using namespace std;void getMemory(char*p, int num){ p = (char*)malloc(sizeof(char) * num);}int main(int argc, const char* argv[]){ char *str = NULL; getMemory(str, 100); strcpy(str, "hello"); return 0;}问题呈现在getMemory里,编译器总是为函数的每个参数制作一个长期正本。在本题中,p为str的拷贝,p申请了一个新的内存空间,然而并没有影响到str,str还是NULL,再调用strcpy(), 则会使代码解体,并且p申请的内存也始终没用开释,造成内存泄露。 正确的办法是把往getMemory内传入str的地址。 #include<iostream>#include<cstring>using namespace std;void getMemory(char**p, int num){ *p = (char*)malloc(sizeof(char) * num);}int main(int argc, const char* argv[]){ char *str = NULL; getMemory(&str, 100); strcpy(str, "hello"); cout << str << endl; return 0;}不过这样写有些麻烦,咱们能够间接把申请好的内存返回。 #include<iostream>#include<cstring>using namespace std;char* getMemory(int num){ return (char*)malloc(sizeof(char) * num);}int main(int argc, const char* argv[]){ char *str = NULL; str = getMemory(100); strcpy(str, "hello"); cout << str << endl; return 0;}例2: 这个函数有什么问题? ...

February 24, 2021 · 3 min · jiezi

关于c++:线程间到底共享了哪些进程资源

过程和线程这两个话题是程序员绕不开的,操作系统提供的这两个抽象概念切实是太重要了。 对于过程和线程有一个极其经典的问题,那就是过程和线程的区别是什么?置信很多同学对答案似懂非懂。 记住了不肯定真懂有的同学可能曾经“背得”滚瓜烂熟了:“过程是操作系统分配资源的单位,线程是调度的根本单位,线程之间共享过程资源”。 可是你真的了解了下面这句话吗?到底线程之间共享了哪些过程资源,共享资源意味着什么?共享资源这种机制是如何实现的?对此如果你没有答案的话,那么这意味着你简直很难写出能正确工作的多线程程序,同时也意味着这篇文章就是为你筹备的。 逆向思考查理芒格常常说这样一句话:“反过来想,总是反过来想”,如果你对线程之间共享了哪些过程资源这个问题想不分明的话那么也能够反过来思考,那就是有哪些资源是线程公有的。 线程公有资源线程运行的实质其实就是函数的执行,函数的执行总会有一个源头,这个源头就是所谓的入口函数,CPU从入口函数开始执行从而造成一个执行流,只不过咱们人为的给执行流起一个名字,这个名字就叫线程。 既然线程运行的实质就是函数的执行,那么函数执行都有哪些信息呢? 在《函数运行时在内存中是什么样子?》这篇文章中咱们说过,函数运行时的信息保留在栈帧中,栈帧中保留了函数的返回值、调用其它函数的参数、该函数应用的局部变量以及该函数应用的寄存器信息,如图所示,假如函数A调用函数B: 此外,CPU执行指令的信息保留在一个叫做程序计数器的寄存器中,通过这个寄存器咱们就晓得接下来要执行哪一条指令。因为操作系统随时能够暂停线程的运行,因而咱们保留以及恢复程序计数器中的值就能晓得线程是从哪里暂停的以及该从哪里持续运行了。 因为线程运行的实质就是函数运行,函数运行时信息是保留在栈帧中的,因而每个线程都有本人独立的、公有的栈区。 同时函数运行时须要额定的寄存器来保留一些信息,像局部局部变量之类,这些寄存器也是线程公有的,一个线程不可能拜访到另一个线程的这类寄存器信息。 从下面的探讨中咱们晓得,到目前为止,所属线程的栈区、程序计数器、栈指针以及函数运行应用的寄存器是线程公有的。 以上这些信息有一个对立的名字,就是线程上下文,thread context。 咱们也说过操作系统调度线程须要随时中断线程的运行并且须要线程被暂停后能够持续运行,操作系统之所以能实现这一点,依附的就是线程上下文信息。 当初你应该晓得哪些是线程公有的了吧。 除此之外,剩下的都是线程间共享资源。 那么剩下的还有什么呢?还有图中的这些。 这其实就是过程地址空间的样子,也就是说线程共享过程地址空间中除线程上下文信息中的所有内容,意思就是说线程能够间接读取这些内容。 接下来咱们别离来看一下这些区域。 代码区过程地址空间中的代码区,这里保留的是什么呢?从名字中有的同学可能曾经猜到了,没错,这里保留的就是咱们写的代码,更精确的是编译后的可执行机器指令。 那么这些机器指令又是从哪里来的呢?答案是从可执行文件中加载到内存的,可执行程序中的代码区就是用来初始化过程地址空间中的代码区的。 线程之间共享代码区,这就意味着程序中的任何一个函数都能够放到线程中去执行,不存在某个函数只能被特定线程执行的状况。 堆区堆区是程序员比拟相熟的,咱们在C/C++中用malloc或者new进去的数据就寄存在这个区域,很显然,只有晓得变量的地址,也就是指针,任何一个线程都能够拜访指针指向的数据,因而堆区也是线程共享的属于过程的资源。 栈区唉,等等!刚不是说栈区是线程公有资源吗,怎么这会儿又说起栈区了? 的确,从线程这个形象的概念上来说,栈区是线程公有的,然而从理论的实现上看,栈区属于线程公有这一规定并没有严格遵守,这句话是什么意思? 通常来说,留神这里的用词是通常,通常来说栈区是线程公有,既然有通常就有不通常的时候。 不通常是因为不像过程地址空间之间的严格隔离,线程的栈区没有严格的隔离机制来爱护,因而如果一个线程能拿到来自另一个线程栈帧上的指针,那么该线程就能够扭转另一个线程的栈区,也就是说这些线程能够任意批改本属于另一个线程栈区中的变量。 这从某种程度上给了程序员极大的便当,但同时,这也会导致极其难以排查到的bug。 试想一下你的程序运行的好好的,后果某个时刻忽然出问题,定位到出问题代码行后基本就排查不到起因,你当然是排查不到问题起因的,因为你的程序原本就没有任何问题,是他人的问题导致你的函数栈帧数据被写坏从而产生bug,这样的问题通常很难排查到起因,须要对整体的我的项目代码十分相熟,罕用的一些debug工具这时可能曾经没有多大作用了。 说了这么多,那么同学可能会问,一个线程是怎么批改本属于其它线程的数据呢? 接下来咱们用一个代码示例解说一下。 文件最初,如果程序在运行过程中关上了一些文件,那么过程地址空间中还保留有关上的文件信息,过程关上的文件也能够被所有的线程应用,这也属于线程间的共享资源。对于文件IO操作,你能够参考《读取文件时,程序经验了什么?》 One More Thing:TLS本文就这些了吗? 实际上本篇结尾对于线程公有数据还有一个项没有具体解说,因为再讲下去本篇就撑爆了,实际上本篇解说的曾经足够用了,剩下的这一点仅仅作为补充。 对于线程公有数据还有一项技术,那就是线程部分存储,Thread Local Storage,TLS。 这是什么意思呢? 其实从名字上也能够看出,所谓线程部分存储,是指寄存在该区域中的变量有两个含意: 寄存在该区域中的变量是全局变量,所有线程都能够拜访尽管看上去所有线程拜访的都是同一个变量,但该全局变量独属于一个线程,一个线程对此变量的批改对其余线程不可见。说了这么多还是没懂有没有?没关系,接下来看完这两段代码还不懂你来打我。 咱们先来看第一段代码,不必放心,这段代码十分十分的简略: int a = 1; // 全局变量void print_a() { cout<<a<<endl;}void run() { ++a; print_a();}void main() { thread t1(run); t1.join(); thread t2(run); t2.join();}怎么样,这段代码足够简略吧,上述代码是用C++11写的,我来解说下这段代码是什么意思。 ...

February 24, 2021 · 1 min · jiezi

关于c:C语言实现循环顺序队列的基本操作

#include<stdio.h>#include<stdlib.h>#define MaxSize 10#define TRUE 1#define ERROR 0typedef int Status;typedef int ElemType;typedef struct{ ElemType *base; //数组基地址,动静分配内存 int front; //头指针 int rear; //尾指针}Queue;Status InitQueue(Queue* Q); //初始化Status InsertQueue(Queue* Q, ElemType e);// 入队Status DeleteQueue(Queue* Q, ElemType* e); //出队Status LengthQueue(Queue* Q); //获取队长void DstoryQueue(Queue *Q); //销毁队int main(){ Queue Q; ElemType e; int n, a; if (InitQueue(&Q) == 1) printf("创立循环队列胜利!\n"); printf("输出插入队尾元素个数:"); scanf("%d", &n); printf("输出插入队尾元素:"); if (n != 0) //判断队空 { for (int i = 0; i < n; i++) { scanf("%d", &e); a = InsertQueue(&Q, e); } } else a = -1; if (a == 1) { printf("插入胜利!\n"); printf("队长为:%d\n", LengthQueue(&Q)); } if (a==0) printf("队已满!无奈持续插入了!\n"); if (DeleteQueue(&Q, &e) == 1) { printf("删除队首元素为:%d\n", e); } else printf("队为空!无奈持续删除了!\n"); printf("删除后队长为:%d\n", LengthQueue(&Q)); DstoryQueue(&Q); printf("销毁结束!"); return 0;}Status InitQueue(Queue* Q){ Q->base = (Queue*)malloc(sizeof(ElemType) * MaxSize); if (!Q->base) exit(0); Q->front = Q->rear = 0; return TRUE;}Status InsertQueue(Queue *Q, ElemType e){ if ((Q->rear + 1) % MaxSize == Q->front) return ERROR; Q->base[Q->rear] = e; Q->rear = (Q->rear + 1) % MaxSize; return TRUE;}Status DeleteQueue(Queue* Q, ElemType* e){ if (Q->front == Q->rear) return ERROR; *e = Q->base[Q->front]; Q->front = (Q->front + 1) % MaxSize; return TRUE;}Status LengthQueue(Queue* Q){ return ((Q->rear-Q->front+MaxSize)%MaxSize);}void DstoryQueue(Queue* Q){ free(Q->base); Q->base = NULL; Q->front = Q->rear = 0;}

February 24, 2021 · 1 min · jiezi

关于c#:RabbitMQ-简介

概述RabbitMQ 是基于 AMQP 实现的一个开源音讯组件,次要用于在分布式系统中存储转发音讯,由因高性能、高可用以及高扩大而出名的 Erlang 语言写成。 特点高牢靠:RabbitMQ 提供了多种多样的个性让你在可靠性和性能之间做出衡量,包含长久化、发送应答、公布确认以及高可用性。 高可用队列:反对跨机器集群,反对队列平安镜像备份,音讯的生产者与消费者不管哪一方呈现问题,均不会影响音讯的失常收回与接管。 灵便的路由:所有的音讯都会通过路由器转发到各个音讯队列中,RabbitMQ 内建了几个罕用的路由器,并且能够通过路由器的组合以及自定义路由器插件来实现简单的路由性能。 工作原理音讯从发送端到接收端的流转过程即 RabbitMQ 的音讯工作机制,请见下图: 根本用法共有 6 种根本用法:单对单、单对多、公布订阅模式、按路由规定发送接管、主题、RPC(即近程存储调用)。咱们将介绍单对单、单对多和主题的用法。 1、单对单:单发送、单接管 2、单对多:一个发送端,多个接收端,如分布式的工作派发 3、主题:Exchange Type 为 topic,发送音讯时须要指定交换机及 Routing Key,消费者的音讯队列绑定到该交换机并匹配到 Routing Key 实现音讯的订阅,订阅后则可接管音讯。只有消费者将队列绑定到该交换机且指定的 Routing Key 合乎匹配规定,能力收到音讯。 其中 Routing Key 能够设置成通配符,如:或 #(示意匹配 Routing Key 中的某个单词,# 示意任意的 Routing Key 的音讯都能被收到)。如果 Routing Key 由多个单词组成,则单词之间用. 来分隔。 命名标准: 交换机名的命名倡议:Ex{AppID}.{自定义 ExchangeName},队列名的命名倡议:MQ{AppID}.{自定义 QueueName} 。 好用的轮子其中EasyNetQ是.NET上RabbitMQ的当先客户端API,在NuGet.org上有超过400万次下载。这是一个凋谢源代码我的项目。 EasyNetQ是为了提供一个尽可能简洁的实用与RabbitMQ的.NET类库。为了实现这些指标,EasyNetQ提供一种自认为你会在.NET下应用RabbitMQ的视图。为了放弃应用灵活性,简略起见,EasyNetQ强制应用了一些简略的约定。包含如下: 音讯用 .NET 类型示意音讯通过.NET类型路由开源地址更多功能见: https://github.com/EasyNetQ/E...

February 24, 2021 · 1 min · jiezi

关于c++:PAT甲级1111-Online-Map

题目粗心现有N个节点和M条边的图,给定终点和起点,找出一条间隔最短的门路和一条耗时起码的门路。其规定如下: 1、对于有多条最短门路,找到耗时最短的2、对于有多条耗时最短门路找到岔路口(顶点)起码的3、如果最短门路和耗时起码门路一样,合并输入。算法思路此题为比拟惯例的最短门路问题,应用两次迪杰斯特拉算法就能够进行求解,第一次求解间隔最短的门路,应用间隔作为第一标尺,耗时作为第二标尺。第二次应用耗时最短的门路,应用耗时作为第一标尺,门路上的节点数目作为第二标尺。迪杰斯特拉算法的过程不再这里赘述。对于两条最短门路是否齐全一样的判断办法就是间接比拟前驱数组,从起点开始始终往前走,遇到不同的阐明是不同门路。 留神点1、测试点4谬误的状况极有可能是在编写第二次迪杰斯特拉算法的时候复制了之前的代码导致有些变量的名字没有更改过去。2、第二次应用迪杰斯特拉算法求解的时候得初始化visited数组。提交后果 AC代码#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 501;int N, M;// 顶点和边的数目int Start, End;// 终点和起点bool visited[maxn];// 拜访标记数组// 间隔最短int L[maxn][maxn];// 每一对节点间的长度int disL[maxn]; // 每一个节点到终点的最短距离int preL[maxn]; // 求解最短距离门路中每一个节点的前驱节点// 耗时最短int T[maxn][maxn];// 每一对节点间的工夫int disT[maxn]; // 每一个节点到终点的最短耗时int preT[maxn]; // 求解最短耗时门路中每一个节点的前驱节点int num[maxn]; // 求解最短耗时门路中每一个节点到终点的最短节点数目void findShortestPath(int start) { fill(disL, disL + maxn, 0x3fffffff); fill(disT, disT + maxn, 0x3fffffff); disL[start] = 0; disT[start] = 0; for (int i = 0; i < N; ++i) { int minD = 0x3fffffff; int minIndex = -1; for (int j = 0; j < N; ++j) { if (!visited[j] && disL[j] < minD) { minD = disL[j]; minIndex = j; } } // 剩下的节点不连通 if (minIndex == -1) return; visited[minIndex] = true; // 依据minIndex更新disL数组 for (int j = 0; j < N; ++j) { if (!visited[j] && L[minIndex][j] != 0) { if (disL[j] > disL[minIndex] + L[minIndex][j]) { disL[j] = disL[minIndex] + L[minIndex][j]; disT[j] = disT[minIndex] + T[minIndex][j]; preL[j] = minIndex; } else if (disL[j] == disL[minIndex] + L[minIndex][j] && disT[j] > disT[minIndex] + T[minIndex][j]) { disT[j] = disT[minIndex] + T[minIndex][j]; preL[j] = minIndex; } } } }}void findFastestPath(int start) { fill(disT, disT + maxn, 0x3fffffff); fill(num, num + maxn, 0x3fffffff); disT[start] = 0; num[start] = 1; for (int i = 0; i < N; ++i) { int minD = 0x3fffffff; int minIndex = -1; for (int j = 0; j < N; ++j) { if (!visited[j] && disT[j] < minD) { minD = disT[j]; minIndex = j; } } // 剩下的节点不连通 if (minIndex == -1) return; visited[minIndex] = true; // 依据minIndex更新disT数组 for (int j = 0; j < N; ++j) { if (!visited[j] && T[minIndex][j] != 0) { if (disT[j] > disT[minIndex] + T[minIndex][j]) { disT[j] = disT[minIndex] + T[minIndex][j]; preT[j] = minIndex; num[j] = num[minIndex] + 1; } else if (disT[j] == disT[minIndex] + T[minIndex][j] && num[j] > num[minIndex] + 1) { preT[j] = minIndex; num[j] = num[minIndex] + 1; } } } }}// 判断最短距离和最短耗时门路是否一样bool isSame() { int t = End; while(preT[t]==preL[t]){ if(preT[t]==Start){ return true; } t = preT[t]; } return false;}// 输入最短门路void printPath(int end, int path[]) { if (Start == end) { printf("%d", Start); return; } printPath(path[end], path); printf(" -> "); printf("%d", end);}int main() { scanf("%d %d", &N, &M); int v1, v2, oneWay, length, time; for (int i = 0; i < M; ++i) { scanf("%d %d %d %d %d", &v1, &v2, &oneWay, &length, &time); L[v1][v2] = length; T[v1][v2] = time; if (oneWay == 0) { // 双向边 L[v2][v1] = length; T[v2][v1] = time; } } scanf("%d %d", &Start, &End); findShortestPath(Start); memset(visited, 0, sizeof(visited)); findFastestPath(Start); if (isSame()) { printf("Distance = %d; Time = %d: ", disL[End], disT[End]); printPath(End, preL); } else { printf("Distance = %d: ", disL[End]); printPath(End, preL); printf("\n"); printf("Time = %d: ", disT[End]); printPath(End, preT); } return 0;}

February 23, 2021 · 3 min · jiezi

关于c++:PAT甲级1110-Complete-Binary-Tree

题目粗心给定一棵含有N个节点的二叉树,判断是否是齐全二叉树 算法思路判断一颗二叉树是否是齐全二叉树的规定: 1、如果呈现只有右孩子节点的,肯定不是2、如果呈现只有左孩子或者没有孩子节点的,记录该状况3、如果以后有孩子,并且呈现了状况2,肯定不是4、遍历树中所有节点后,如果没有1和3,表明该树为齐全二叉树遍历形式采纳层序遍历。在遍历过程中应用count记录遍历的节点个数,在count=N的时候阐明来到了最初一个节点,应用lastNode记录。对于根节点的确定能够应用一个father数组记录每一个节点的父节点编号,初始化全副为-1,在输出完结后,遍历一遍,第一次遇到-1的编号就是根节点。 提交后果 AC代码#include <cstdio>#include <iostream>#include <queue>using namespace std;struct Node{ int left = -1; int right = -1; int index{};}nodes[25];queue<Node> que;int lastNode;bool isComplete(int root,int N){ que.push(nodes[root]); bool flag = false;// 标记是否呈现状况2 int count = 0; while(!que.empty()){ Node t = que.front(); que.pop(); ++count; if(count==N){ // 最初一个节点 lastNode = t.index; } if(t.left==-1&&t.right!=-1) { // 状况1 return false; }else if(t.left!=-1||t.right!=-1) { // 以后节点有孩子 if(flag){ return false; } }else if((t.left!=-1&&t.right==-1)||(t.left==-1&&t.right==-1)){ // 只有左孩子或者没有孩子 flag = true; } if(t.left!=-1){ que.push(nodes[t.left]); } if(t.right!=-1){ que.push(nodes[t.right]); } } return true;}int main() { int N; scanf("%d",&N); int father[N]; for(int i=0;i<N;++i){ father[i] = -1; } string left,right; for(int i=0;i<N;++i){ cin>>left>>right; nodes[i].index = i; if(left!="-"){ int leftChild = stoi(left); father[leftChild] = i; nodes[i].left = leftChild; } if(right!="-"){ int rightChild = stoi(right); father[rightChild] = i; nodes[i].right = rightChild; } } int root = 0; for(int i=0;i<N;++i){ if(father[i]==-1){ root = i; break; } } if(isComplete(root,N)){ printf("YES %d",lastNode); }else{ printf("NO %d",root); } return 0;}

February 23, 2021 · 1 min · jiezi

关于c++:PAT甲级1109-Group-Photo

题目粗心有N集体照相,现将N集体排成K行,每一行都有N/K集体,并依照如下规定排列 1、对于多进去的人全副在最初一排2、前一排的人都比后一排的人矮3、每一行最高的人都在两头地位4、视角从下往上看(面对着看),每一行最两头的人开始,先左再右造成非递增序列5、对于有雷同身高的人,依照字典序升序排列当初要求你输入该排列后果。 算法思路有两种办法解决该问题,能够间接进行输入,不过地位的计算较为简单并且不易浏览,这里采纳模仿排列的过程来求解。咱们将每一个人的姓名和身高进行绑定并且依照规定进行对立排序(高个子的在后面),而后从最初一排往前顺次进行排列(输入的程序),排列办法如下: 1、首先初始化以后队列temp,其容量为m2、应用index记录全局队列中待排列的以后人3、填充两头地位temp[m / 2] = allPeo[index++];4、应用pointLeft和pointRight别离指向两头地位的左右两边邻近的地位,并应用count记录以后曾经填充的人数5、在count为奇数的时候填充右边,否则填充左边6、每一行填充结束后输入temp并换行。提交后果 AC代码#include <cstdio>#include <algorithm>#include <vector>#include <iostream>using namespace std;struct People { string name; int height{};} people;vector<People> allPeo;bool cmp(const People &p1, const People &p2) { return p1.height != p2.height ? p1.height > p2.height : p1.name < p2.name;}int main() { int N, K; scanf("%d %d", &N, &K); for (int i = 0; i < N; ++i) { cin >> people.name >> people.height; allPeo.push_back(people); } sort(allPeo.begin(), allPeo.end(), cmp); int eachRowNum = N / K; int lastRowNum = eachRowNum + N % K; int index = 0; // 输入每一行的排列 for (int i = 0; i < K; ++i) { int m = i == 0 ? lastRowNum : eachRowNum; vector<People> temp(m); int pointLeft = m / 2 - 1; int pointRight = m / 2 + 1; temp[m / 2] = allPeo[index++]; int count = 1; while (count < m) { if (count % 2 != 0) { temp[pointLeft--] = allPeo[index++]; } else { temp[pointRight++] = allPeo[index++]; } ++count; } for (int j = 0; j < temp.size(); ++j) { cout << temp[j].name; if (j < temp.size() - 1) cout << " "; } if (i < K - 1) { cout << endl; } } return 0;}

February 23, 2021 · 1 min · jiezi

关于c++:PAT甲级1108-Finding-Average

题目粗心给定N个输出,这些输出中只有在[-1000,1000]内并且位数在2位以内的数字才是非法的,对于不非法的输出间接输入相干信息,对于非法的数字须要计算平均值并进行输入 算法思路此题惟一的考点就是判断输出是否非法,对于所有的非数字字符进行如下判断: 1、如果该字符为"-"并且呈现在第一位,跳过2、如果该字符为小数点,则计算小数点前面的位数,如果大于2,则非法,否则统计小数点呈现的次数,呈现超过1次,则非法3、对于其余非数字字符均为非法字符。4、如果该数字为实数,如果在$[-1000,1000]$内,间接返回,否则非法,返回-1.提交后果 AC代码#include <cstdio>#include <iostream>using namespace std;/* * 判断输出的字符串是否非法 * 含有非数字字符,超过两个小数点,范畴在[-1000,1000]以外的都是非法字符 */double isLegal(const string &num){ int decimalCount = 0;// 小数点个数 int n = num.size(); for(int i=0;i<n;++i){ char c = num[i]; if(!(c>='0'&&c<='9')){ if(c=='-'&&i==0){ continue; }else if(c=='.'){ // 呈现小数点 int rest = n-i-1;// 计算小数点前面的位数 if(rest>2){ return -1; } ++decimalCount; if(decimalCount>=2){ return -1; } }else{ return -1; } } } // 肯定为数字 double x = stof(num); if(x>=-1000&&x<=1000){ return x; }else{ return -1; }}int main(){ int N; scanf("%d",&N); string in; int legalNum = 0;// 非法输出个数 double sum = 0; for(int i=0;i<N;++i){ cin>>in; double a = isLegal(in); if(a!=-1){ sum += a; ++legalNum; }else{ cout<<"ERROR: "<<in<<" is not a legal number"<<endl; } } if(legalNum>1){ printf("The average of %d numbers is %.2f",legalNum,sum/legalNum); } else if(legalNum==1){ printf("The average of 1 number is %.2f",sum); } else{ printf("The average of 0 numbers is Undefined"); } return 0;}

February 23, 2021 · 1 min · jiezi

关于c++:C-priorityqueue的用法一看就会用

头文件 : include <queue> 定义 : priority_queue<Type, Container, Functional> 默认 : ==大顶堆==,比拟形式默认用operator< ,所以如果把前面2个参数缺省的话,优先队列就是大顶堆(降序),队头元素最大 个别应用 : // 留神 >>和 > >, c++11之后能够不必加空格// 大顶堆priority_queue<int, vector<int>, less<int> > q;// 小顶堆priority_queue<int, vector<int>, greater<int> > q;//greater 和 less 是 std 实现的两个仿函数//(就是使一个类的应用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了相似函数的行为,就是一个仿函数类了)// pair<int, int> 默认大顶堆,先比拟第一个,再比拟第二个;priority_queue<pair<int, int> > q;// 2 5// 2 4// 1 6// 自定义优先级// struct Node //运算符重载<struct Node{ int x; Node(int a) : x(a){} bool operator<(const Node& a) const // 返回 true 时 a的优先级高 { return x < a.x; //大顶堆 }};

February 23, 2021 · 1 min · jiezi

关于c#:应用界面开发小技巧-如何在覆盖表单上显示自定义按钮

点击获取工具>> 留神:GitHub上提供了残缺的示例我的项目,网址为:https://github.com/DevExpress-Examples/how-to-display-a-custom-button-on-an-overlay-form 概述Overlay Form是一个半透明的启动屏幕,他在后盾线程中运行并笼罩控件或表单来避免对其进行拜访,Overlay Form仅蕴含一个期待指示器。 本示例演示如何显示: 期待指示器下方的百分比标签;一个自定义按钮,该按钮终止已解决的工作并敞开Overlay Form。 本示例使您能够更改标签文本、按钮字形以及单击按钮时执行的操作。 实现细节您能够按以下形式自定义Overlay Form图形: 从OverlayWindowPainterBase类继承它;重写Draw办法;将创立的对象作为参数传递给SplashScreenManager.ShowOverlayForm办法。本示例应用OverlayImagePainter和OverlayTextPainter对象(OverlayWindowPainterBase后辈),它们实现了图像和文本的绘制逻辑,并且您能够应用它们的属性来自定义图像和文本。 OverlayImagePainter对象在Overlay Form的顶部核心绘制一个自定义图像,并解决该图像上的单击。 您能够指定以下属性: Image - 失常状态下的图像;HoverImage - 处于悬停状态的图片;ClickAction - 单击图像时执行的操作。OverlayTextPainter对象在期待指示器下方绘制一个自定义标签,您能够指定以下属性: Text - 标签文本;Font - 文本字体(默认应用Tahoma,18);Color - 文本色彩(默认为彩色)。OverlayWindowCompositePainter对象在OverlayImagePainter和OverlayTextPainter对象中组成绘图逻辑,该复合绘制器作为参数传递给SplashScreenManager.ShowOverlayForm办法。 显示Overlay Form时执行的操作是应用.Net Framework类库(工作并行库(TPL))中可用的可勾销工作来实现的。 自定义按钮和标签地位按钮图像显示在Overlay Form的顶部地方,标签显示在期待指示器下方,您能够重写以下办法来指定其地位: OverlayTextPainter.CalcTextBounds — 返回一个矩形,该矩形指定标签的地位;OverlayImagePainter.CalcImageBounds — 返回一个矩形,它指定按钮的地位。每次须要从新绘制叠加表单时(例如,当用户调整重叠控件的大小时),都会调用这些办法,drawArgs办法参数蕴含绘制笼罩图所需的信息。本示例应用以下属性: Bounds — 获取Overlay Form边界;ImageBounds — 获取期待指示器的范畴;上面的代码段显示了如何更新以后示例来在自定义地位显示按钮和标签。 C# `using DevExpress.Utils.Extensions;using DevExpress.XtraSplashScreen; class OverlayImagePainterEx : OverlayImagePainter {public OverlayImagePainterEx(Image image, Image hoverImage = null, Action clickAction = null) : base(image, hoverImage, clickAction) { }protected override Rectangle CalcImageBounds(OverlayLayeredWindowObjectInfoArgs drawArgs) {int indent = 10;return Image.Size.AlignWith(drawArgs.Bounds).WithY(indent).WithX(drawArgs.Bounds.Width - Image.Height - indent);}} ...

February 23, 2021 · 2 min · jiezi

关于c++:766-托普利茨矩阵

766. 托普利茨矩阵给你一个 m x n 的矩阵 matrix 。如果这个矩阵是托普利茨矩阵,返回 true ;否则,返回 false 。 如果矩阵上每一条由左上到右下的对角线上的元素都雷同,那么这个矩阵是 托普利茨矩阵。 思路从(1,1)开始,每个节点左上角的元素与节点比拟,不同为falseclass Solution {public: bool isToeplitzMatrix(vector<vector<int>>& matrix) { int m = matrix.size(); int n = matrix[0].size(); for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { if (matrix[i][j] != matrix[i-1][j-1]) { return false; } } } return true; }};

February 22, 2021 · 1 min · jiezi

关于c#:在NET中使用Apache-Kafka一

已经在你的应用程序中应用过异步解决吗?在解决不须要立刻执行的工作时,异步代码仿佛是不可避免的。Apache Kafka是最罕用和最强壮的开源事件流平台之一。许多公司和开发者利用它的弱小性能来创立高性能的异步操作,用于微服务的数据集成,以及用于应用程序衰弱指标的监控工具。这篇文章解释了在.NET应用程序中应用Kafka的细节,还展现了如何在Windows操作系统上装置及应用。 它是如何工作的 当今世界,数据正在以指数模式增长。为了包容一直增长的数据,Kafka这样的工具应运而生,提供了强壮而令人印象粗浅的架构。 然而Kafka是如何在幕后工作的呢? Kafka在生产者和消费者之间替换信息。生产者和消费者是这一线性过程的两个次要角色。 Kafka也能够在一个或多个服务器的集群中工作。这些服务器被称为Kafka代理,通过代理你能够受害于多种个性,例如数据复制、容错和高可用。 这些代理由另一个叫做Zookeeper的工具治理。总之,它是一种旨在放弃分布式系统中同步和组织配置数据的服务。 Kafka Topics Kafka只是一个代理,所有的行为都产生在这。生产者向世界发送音讯,而消费者读取特定的数据块。如何辨别数据的一个特定局部与其余局部?消费者如何晓得要应用哪些数据?要了解这一点,你须要一个新的内容:topic。 Kafka topics是传递音讯的载体。由生产者产生的Kafka记录被组织并存储到topic中。 假如你正在解决一个用于记录动物目录的API我的项目。你要确保公司中的每个人都可能拜访每一个新注册的动物。所以你选了Kafka。 在零碎中注册的每一个新动物都将通过Kafka进行播送。topic的名称是tree_catalog。 在这种状况下,topic像堆栈一样工作。它将信息保留在达到时的雷同地位,并保证数据不会失落。 达到的每个数据记录被存储在一个slot中,并用一个称为offset的惟一地位号注册。 例如,当一个消费者生产了存储在offset是0的音讯时,它提交音讯,申明一切正常,而后挪动到下一个offset,依此类推。这个过程通常是线性的。然而,因为许多消费者能够同时将记录“插入”到同一个topic中,所以确定哪些数据地位曾经被占用的责任留给了消费者。这意味着消费者能够决定应用音讯的程序,甚至决定是否从头开始从新开始解决(offset为0)。 分区 分布式系统的一个要害个性是数据复制。它容许一个更平安的体系结构,数据能够被复制到其余中央,以防不好的事件产生。Kafka通过分区解决复制。Kafka topics被配置为扩散在几个分区(可配置的)。每个分区通过惟一的offset保留数据记录。 为了实现冗余,Kafka在分区(一个或多个)创立正本,并在集群中流传数据。 这个过程遵循leader-follower模型,其中一个leader正本总是解决给定分区的申请,而follower复制该分区。每次制作人将音讯推送到某个主题时,它都会间接传递给该主题的领导者。 生产组 在Kafka中,生产来自topic的音讯最合适的形式是通过生产组。 顾名思义,这些组由一个或多个消费者组成,目标是获取来自特定主题的所有音讯。 为此,组必须始终具备惟一的id(由属性group.id设置)。无论何时消费者想要退出那个组,它都将通过组id来实现。 每次你增加或删除一个组的消费者,Kafka会从新均衡它们之间的负载,这样就不会过载。 设置 当初,你曾经理解了Kafka的通用工作原理,是时候开始环境设置了。为了简化,这个例子将应用Docker来保留Kafka和Zookeeper映像,而不是将它们装置到你的机器上。这样能够节俭一些空间和复杂性。 对于Windows用户,Docker提供了一种装置和治理Docker容器的简略形式:Docker桌面。进入它的下载页面并下载安装程序。运行它,并在不更改默认设置选项的状况下持续到最初。确保在此过程实现后重新启动计算机。重启后,Docker可能会要求你装置其余依赖项,所以请确保承受每一个依赖项。在Docker上装置一个无效的Kafka本地环境最快的门路之一是通过Docker Compose。通过这种形式,能够通过一个YAML文件建设应用程序服务,并疾速地让它们运行。 创立一个名为docker-compose的新文件,并将以下的内容保留到其中: version: '2'services:  zookeeper:    image: wurstmeister/zookeeper    ports:      - "2181:2181"  kafka:    image: wurstmeister/kafka    ports:      - "9092:9092"    environment:      KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1      KAFKA_CREATE_TOPICS: "simpletalk_topic:1:1"      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181    volumes:      - /var/run/docker.sock:/var/run/docker.sock留神,代码从Docker Hub的wurstmeister帐户中导入了两个服务镜像(kafka和zookeeper)。这是在Docker上应用Kafka最稳固的镜像之一。端口也应用它们的推荐值进行设置,因而请留神不要更改它们。 其中最重要的设置之一属于KAFKA_CREATE_TOPICS。在这里,你必须定义要创立的topic名称。还有其余办法能够创立主题,当前你将看到。 通过命令行导航到docker-compose.yml所在的文件夹。而后执行如下命令启动镜像: docker-compose up这段代码将加载所有依赖项并启动镜像。在此过程中,可能会看到大量的日志。 如果没有谬误日志显示,阐明启动胜利。 为了查看Docker镜像是否启动,在另一个cmd窗口中运行以下命令: docker ps显示如下: 亲自动手 你的Kafka环境曾经能够应用了。下一步是在Visual Studio中进行我的项目创立。进入我的项目创立窗口。搜寻ASP.NET Core Web Application模板,单击Next。 解决方案新建一个名称消费者我的项目和生产者我的项目将在同一个解决方案中共存。 下一个窗口抉择API模板。勾销勾选“配置为HTTPS”选项。 创立我的项目后,右键单击解决方案,抉择增加新我的项目,而后,抉择ASP.NET Core Web Application我的项目类型。 持续并像后面一样抉择API模板。 当初,在ST-Kafka-NET解决方案中有两个我的项目。 NuGet包 ...

February 22, 2021 · 2 min · jiezi

关于c#:Net-NLog日志框架配置与使用

NLog是实用于各种.NET平台(包含.NET规范)的灵便,收费的日志记录平台,NLog可将日志写入多个指标,比方Database、File、Console、Mail。上面介绍下NLog的根本应用办法。 应用步骤增加援用装置NLog Nuget package:Install-Package NLog.Config; 增加配置文件在我的项目中增加一个配置文件(也能够间接将NLog的配置我的项目放入*.exe.config中),重命名为NLog.config;更改如下两项属性内容: 复制到输入目录 - 如果较新则复制生成操作 - 内容增加配置内容,上面展现的是GitHub上的示例配置:<?xml version="1.0" encoding="utf-8" ?><nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- 配置输入指标 --> <targets> <!-- 输入到文件 --> <target name="logfile" xsi:type="File" fileName="file.txt" /> <!-- 输入到控制台 --> <target name="logconsole" xsi:type="Console" /> </targets> <!-- 定义输入规定,可配置多个 --> <rules> <logger name="*" minlevel="Info" writeTo="logconsole" /> <logger name="*" minlevel="Debug" writeTo="logfile" /> </rules></nlog>创立Logger类,获取NLog.Logger实例:public class Log{ // ... private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();}配置示例如下配置为自己罕用配置,可参考该配置及GitHub领导文档自定义配置: 留神:首次应用NLog时,可先将throwExceptions置为true,这样如果配置有问题没有胜利打印日志,VS会抛出异样,不便定位起因。调试好后,再将该项置为false。 另外:示例中fileName(日志文件全门路名称)是通过后盾代码配置的,这样能够动静设置日志的输入地位。 // NLog.config<?xml version="1.0" encoding="utf-8" ?><nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwExceptions="false" autoReload="true" async="true" encoding="UTF-8"> <targets> <target name="logconsole" xsi:type="Console" layout="${date:format=HH\:mm\:ss} | ${level:padding=-5} | ${message}"/> <target name="logfile" xsi:type="File" createDirs="true" keepFileOpen="true" fileName="${gdc:logDirectory:whenEmpty=${baseDir}}/logs/${shortdate}/Whiteboard.log" archiveFileName="${gdc:logDirectory:whenEmpty=${baseDir}/logs/${shortdate}}/Whiteboard_{##}.log" archiveAboveSize="102400" archiveNumbering="Sequence" maxArchiveDays="30" layout="${longdate} | ${level:uppercase=false:padding=-5} | ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}"/> </targets> <rules> <logger name="*" minlevel="Debug" writeTo="logconsole"/> <logger name="*" minlevel="Debug" writeTo="logfile" /> </rules></nlog>// Log.cs 设置日志文件输入地位string logDir = Path.Combine(Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData), Process.GetCurrentProcess().ProcessName);NLog.GlobalDiagnosticsContext.Set("logDirectory", logDir);

February 22, 2021 · 1 min · jiezi

关于c++:leetcode-229-周赛

5685. 交替合并字符串给你两个字符串 word1 和 word2 。请你从 word1 开始,通过交替增加字母来合并字符串。如果一个字符串比另一个字符串长,就将多进去的字母追加到合并后字符串的开端。 返回 合并后的字符串 。输出:word1 = "abc", word2 = "pqr"输入:"apbqcr" 思路通过up进行判断class Solution {public: string mergeAlternately(string word1, string word2) { int i = 0, j = 0; string res; bool up = true; while (i <= word1.size() && j <= word2.size()) { if (i < word1.size() && up == true) { res += word1[i++]; up = false; } else if (j < word2.size() && up == false) { res += word2[j++]; up = true; } if (i == word1.size() && j == word2.size()) { break; } else if (i == word1.size() && j < word2.size()) { while (j < word2.size()) { res += word2[j++]; } } else if (j == word2.size() && i < word1.size()) { while (i < word1.size()) { res += word1[i++]; } } } return res; } };5686. 挪动所有球到每个盒子所需的最小操作数有 n 个盒子。给你一个长度为 n 的二进制字符串 boxes ,其中 boxes[i] 的值为 '0' 示意第 i 个盒子是 空 的,而 boxes[i] 的值为 '1' 示意盒子里有 一个 小球。 ...

February 21, 2021 · 3 min · jiezi

关于c:C语言实现顺序栈的基本操作举例

#include<stdio.h>#include<stdlib.h>#include<windows.h>#define MaxSize 100#define true 1#define error 0#define OK 1#define OVERFLOW -2typedef int ElemType;typedef struct { //程序栈构造(动静) ElemType* top; ElemType* base; int stacksize;}Sqstack;int InitStack(Sqstack* s); //初始化(在C语言中,形参和实参是单向传递,但可用指针(*)传递地址,让形参影响实参,达到双向传递)int EmptyStack(Sqstack* s);int Push(Sqstack* s,ElemType e); //插入元素(在c++中,能够用(&)援用型参数实现双向传递)int StackLength(Sqstack* s); //元素长度int StackPrint(Sqstack* s); //打印元素int Pop(Sqstack* s); //删除栈顶元素int DestroyStack(Sqstack* s); //销毁栈int main(){ int n; ElemType e, a; Sqstack *s; s = (Sqstack*)malloc(sizeof(Sqstack)); //敲黑板重点!指针要有地址!记住调配地址! InitStack(s); printf("请输出插入元素个数:"); scanf("%d", &n); printf("请输出插入元素:"); for (int i = 0; i < n; i++) { scanf("%d", &e); Push(s, e); } if (EmptyStack(s) == 1) printf("**啊!***空表**\n"); printf ("元素长度:%d\n",StackLength(s)); printf("打印元素为:"); StackPrint(s); printf("\n"); a = Pop(s); //我在这里翻了车,后面Pop(s)没赋值a,导致Pop(s)援用两次,引发谬误。 if (a == -2) printf("栈底溢出!\n"); else printf("删除栈顶元素为:%d\n", a); printf("删除后:"); StackPrint(s); printf("\n"); system("pause"); printf("销毁栈中.........\n"); Sleep(3000); system("cls"); if (DestroyStack(s) == 1) printf("销毁胜利!"); else printf("销毁失败!"); return 0;}int InitStack(Sqstack* s){ s->base = (ElemType*)malloc(sizeof(ElemType) * MaxSize); if (!s->base) return error; s->top = s->base; s->stacksize = MaxSize; return OK;}int EmptyStack(Sqstack* s){ if (s->base == s->top) return true; else return error;}int Push(Sqstack* s, ElemType e){ if (s->top - s->base >= MaxSize) return OVERFLOW; if (!s->base) return error; *(s->top) = e; s->top++; return OK;}int StackLength(Sqstack* s){ if (s->base == s->top) return error; else return ((s->top) - (s->base));}int StackPrint(Sqstack* s){ if (s->base == NULL) return error; if (s->base == s->top) printf("没有元素!"); ElemType* p; p = s->base; while (p <(s->top)) { printf("%d ", *p); p++; } return OK;}int Pop(Sqstack* s){ ElemType a; if (s->base == s->top) return OVERFLOW; else { a = *(s->top-1 ); s->top--; } return a;}int DestroyStack(Sqstack* s){ free(s); s->base = s->top = NULL; s->stacksize = 0; return OK;}

February 21, 2021 · 2 min · jiezi

关于c#:线程安全

线程平安多个线程试图同时拜访同一个数据时,数据不会受到毁坏 线程同步结构结构模式别离有用户模式和内核模式两种,其中用户模式结构应用了非凡的CPU指令协调线程(协调是在硬件中产生的事件),所以其结构速度要显著快于内核模式结构,同时用户模式中阻塞的线程池线程永远不会被认为阻塞,所以线程池不会创立新线程替换阻塞线程。在用户模式中运行的线程可能被零碎抢占,但线程会以最快的速度再次调度,所以想要获取某一资源又临时无奈获得时,线程会用户模式中始终运行,这并不是一个良好的景象。而内核模式的结构是由Windows操作系统本身提供的,要求在应用程序的线程中调用在操作系统内核中实现的函数,将线程从用户模式切换为内核模式会造成微小的性能损失。然而也有一个长处:一个线程应用内核模式结构获取一个由其它线程正在拜访的资源时,Windows会阻塞线程,使之不再节约CPU工夫,等到资源可用时会复原线程,容许它拜访资源。 用户模式结构易失结构:在蕴含一个简略数据类型的变量上执行原子性的读或写操作互锁结构:在蕴含一个简略数据类型的变量上执行原子性的读和写操作原子性指事务的不可分割性,意味着一个变量的值的读取都是一次性的,如以下代码 class SomeType{ public static int x;}SomeType.x = 0x01234567;变量x会一次性从0x00000000变成0x01234567,另一个线程不可能看到一个处于两头值的状态,如0x01234000,这便是原子性。 易失结构编写好的代码须要被编译器编译成IL代码,再通过JIT编译器转换老本地CPU指令能力被计算机执行。而在这些转换过程中,编译器、JIT编译器、CPU自身可能都会对原先编写好的代码进行优化。如上面这段代码通过编译后将会隐没 private static void SomeMethod(){ //常量表达式在编译时计算为0 int value = 100 - (50 * 2); //value为0循环永不执行 for (int i = 0; i < value; i++) { //永远执行不到,不须要编译循环中的代码 Console.WriteLine(i); }}上述代码中,编译器发现value为0,循环永远不会执行,没有必要编译循环中的代码,因而这个办法编译后会被优化掉。如果有一个办法中调用了SomeMethod办法,在对这个办法进行JIT编译的时候,JIT编译器会尝试内联SomeMethod办法的代码,因为没有代码,所以JIT编译器会删除调用SomeMethod办法的代码。 编译器、JIT编译器和CPU对代码进行优化的时候,从单线程的角度看,代码会做咱们心愿它做的事件,而从多线程来看,代码的用意不肯定会失去保留,以下的代码进行了演示: class SomeType{ private int m_Flag = 0; private int m_Value = 0; public void Thread1() { this.m_Value = 10; this.m_Flag = 1; } public void Thread2() { //可能会输入0,与预期不统一 if(this.m_Flag == 1) Console.WriteLine("value = {0}", this.m_Value); }}static void Main(){ ThreadPool.QueueUserWorkItem((o) => { someType.Thread1(); }); ThreadPool.QueueUserWorkItem((o) => { someType.Thread2(); });}上述代码的问题在于假设Thread1办法中的代码依照程序执行,编译Thread2办法中的代码时,编译器必须生成代码将m_Flag和m_Value 从RAM读入CPU寄存器。RAM可能先传递m_Value的值(此时为0),而后Thread1可能执行,将Thread1改为10,m_Flag改为1。然而Thread2的CPU寄存器没有看到m_Value的值曾经被另一个线程批改为10,呈现输入后果为0的状况。除此之外Thread1办法中的两行代码在CUP/编译器在解释代码时可能会呈现反转,毕竟这样做也不会扭转代码的用意,同样可能呈现在Thread2中m_Value输入0的状况。 ...

February 20, 2021 · 3 min · jiezi

关于c#:聊聊ASPNET-Core中的配置

作为软件开发人员,咱们当然喜爱一些可配置选项,尤其是当它容许咱们扭转应用程序的行为而无需批改或编译咱们的应用程序时。无论你是应用新的还是旧的.NET时,可能心愿利用json文件的配置。在这篇文章中,咱们将探讨读取配置所需的必要步骤以及应用这些值。 .NET的配置历史 对于那些ASP.NET老兵,你可能还记得wen.config。尽管它没有齐全被摈弃,但它在ASP.NET Core中扮演着不那么重要的角色。web.config是一个基于XML的文件,用于配置IIS的主机环境。在这个文件中,咱们能够搁置应用程序设置、加载额定的web模块、注册处理程序等等。 另一个限度是web.config更改后将迫使应用程序重新启动。更改能够很简略,如增加新的应用程序设置,也能够很简单,如向申请管道增加新模块。ASP.NET应用程序必须从新加载,以确保逻辑一致性。开发人员能够将所有设置通过ConfigurationManager拜访。坦率地说,随着工夫的推移,开发人员将重新启动看作是一种性能,而不是一种阻碍,应用它来重置陷入故障状态的应用程序。 当初的ASP.NET Core配置 ASP.NET Core看到了围绕配置产生次要问题,并试图通过以下三方面为开发人员改良: 除了XML之外,还反对其余模式的配置格局。用依赖注入(DI)的敌对办法替换ConfigurationManager。配置热更改,能够立刻在拜访的代码中产生。这些变动反映了更先进的设置,并且对本地云的web应用程序更敌对。应用程序配置能够来自多个地位,可扩展性使开发人员更容易防止自定义解决方案。 随着.NET采纳async/await和异步编程,应用单例可能会导致死锁和性能开销。使DI反对配置后,给开发人员提供了更多的形式来应用设置依赖项,并将这些数据与任何源解耦。它还能够在不拜访ConfigurationManager或web.config的状况下测试配置设置。 冷启动是所有用户的敌人,它会发明令人丧气的体验。无需重新启动就能够进行更改的能力确保了更好的运行时体验。 看看具体代码 目前,咱们曾经探讨了配置的历史和以后状态,然而让咱们跳到理论应用环节。 第一步是创立一个从配置提供程序读取设置的数据类。ASP.NET Core提供了多个开箱即用的性能,但最罕用的是JSON配置提供程序。该类须要蕴含与JSON局部雷同的构造。 public class HelloWorldOptions{ public string Text { get; set; }}下一部分是讲述ASP.NET Core如何绑定HelloWorldOptions类。咱们能够应用BindConfiguration办法做到这一点。 public void ConfigureServices(IServiceCollection services){ services.AddOptions<HelloWorldOptions>() .BindConfiguration("HelloWorld");}字符串HelloWorld示意appsettings.json文件中的局部。 { "HelloWorld" : { "Text": "Hello, Khalid!" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*"}很好,当初咱们筹备好应用咱们的配置信息了。接下来就有点让人困惑了。咱们有三个接口可供选择: IOptions<T>IOptionsSnapshot<T>IOptionsMonitor<T>每个接口都包装了咱们的配置数据,并为咱们提供了稍微不同的生命周期。 IOptions< T>被注册为一个单例,因而所有的值都被检索一次并存储在ASP.NET Core应用程序的内存。在应用程序启动后,这种办法无奈读取任何更新的配置。注册为单例意味着ASP.NET能够将接口注入到任何依赖项中,而不用放心捕捉它或导致内存透露问题。这个版本很可能是大多数人会应用的。 IOptionsSnapshot< T>具备作用域生存期。ASP.NET Core将对每个HTTP申请从新查看一次。 缓存每个申请的实例,直到用户收到响应。这个办法对于那些心愿动静更改配置但依然须要通过以后管道进行刷新的申请的人十分有用。这个版本有助于应用切换配置,而无需从新加载应用程序。 最初,IOptionsMonitor< T>与IOptionsSnapshot<T>很类似,却是单例生命周期。IOptionsMonitor办法对于应该立刻解决的要害数据更改十分有用。长期存在的后盾服务可能心愿应用IOptionsMonitor持续接管配置更改,但不须要领取低廉的对象创立老本。 既然咱们晓得了每个接口的长处,咱们就能够应用咱们的配置了。在启动时找到的Configure办法中,让咱们增加一个新的GET终结点。 public void Configure(IApplicationBuilder app, IWebHostEnvironment env){ if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { var options = context .RequestServices .GetRequiredService<IOptionsSnapshot<HelloWorldOptions>>() .Value; await context.Response.WriteAsync(options.Text); }); });}留神,在咱们的代码中,咱们应用的是IOptionsSnapshot。通过实例将容许咱们更新配置,而不须要重新启动咱们的应用程序。启动应用程序时,咱们应该看到配置值。更改配置将更改申请的后果。 ...

February 20, 2021 · 1 min · jiezi

关于c:为什么-Python-的-fstring-可以连接字符串与数字

本文出自“Python为什么”系列,归档在 Github 上:https://github.com/chinesehuazhou/python-whydo毫无疑问,Python 是一门强类型语言。强类型语言。强类型语言!(对于强弱类型话题,举荐浏览这篇 技术科普文) 这就意味着,不同类型的对象通常须要先做显式地类型转化, 而后能力进行某些操作。 上面以字符串和数字为例,看看强行操作会产生什么后果: >>> "Python猫" + 666Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: can only concatenate str (not "int") to str它报类型谬误了(TypeError),说字符串只能连贯(concatenate)字符串,不能连贯 int 类型。 这正是强类型语言的根本束缚。 然而,如果咱们先把数字“转化”成字符串类型,再执行“+”操作,就不会报错了: >>> "Python猫" + str(666)'Python猫666'下面的这个例子,对读者们来说,应该并不难理解。 由此,咱们要引出一个问题:如何在不作显式类型转化的状况下,进行字符串与数字类型的拼接呢? 在《详解Python拼接字符串的七种形式》这篇文章中,它梳理了七种拼接字符串的写法,咱们能够一一来试验一下。 几种字符串拼接形式:1、格式化类:%、format()、template 2、拼接类:+、()、join() 3、插值类:f-string 为了节俭篇幅,此处间接把能够顺利拼接的 4 种写法列举如下: >>> "%s %d" % ("Python猫", 666)'Python猫 666'>>> from string import Template>>> s = Template('${s1}${s2}')>>> s.safe_substitute(s1='Python猫',s2=666)'Python猫666'>>> "Python猫{}".format(666)'Python猫666'>>> num = 666>>> f"Python猫{num}"'Python猫666'第一种写法(即 % 格式化)来自古老的 C 语言,其中的“%d”是一个占位符,示意它将要接管一个整数,并格式化成字符串。 ...

February 19, 2021 · 1 min · jiezi

关于c:源代码下载地址linux系统源代码下载

linux源代码下载地址如下:https://mirrors.edge.kernel.o...

February 19, 2021 · 1 min · jiezi

关于c:源码下载地址c语言库函数代码下载位置

所有的c语言库函数代码下载地址分享: 上面这个地址就是C苦函数下载地址。http://ftp.gnu.org/gnu/glibc/

February 19, 2021 · 1 min · jiezi

关于c#:WPF界面应用开发技巧绑定到条件格式规则的集合

点击获取工具>>DevExpress WPF 领有120+个控件和库,将帮忙您交付满足甚至超出企业需要的高性能业务应用程序。通过DevExpress WPF能创立有着弱小互动性能的XAML根底应用程序,这些应用程序专一于当代客户的需要和构建将来新一代反对触摸的解决方案。 应用模型视图ViewModel(MVVM)架构模型设计WPF应用程序时,可能须要在模型或视图模型中形容条件格局设置规定。 网格能够绑定到蕴含条件格式化规定的对象汇合,这些条件在Model或ViewModel中进行了形容,从而最大限度地缩小了“暗藏代码”的需要。 View模型实现本文中应用的示例蕴含一个视图模型代码,其中包含以下类。 Order - 蕴含订单信息(例如数量,折扣等)的数据对象。ViewModel - 订单视图模型,_ViewModel_公开Orders属性(在网格内显示的订单列表)和Rules属性(格局规定列表)。OrderData - 提供要在网格控件中显示的订单信息。FormattingRule - 形容条件格局设置规定,此类提供的属性与所有类型的条件格局设置规定通用的设置绝对应。FormattingType - 枚举利用格局的可能类型。C# `using System.Collections.Generic;using System.Windows;using System.Windows.Controls; namespace GridDemo {// ... public class ViewModel {public ViewModel() {Orders = GetOrders();Rules = GetFormattingRules();} private static List<FormattingRule> GetFormattingRules() {var rules = new List<FormattingRule>();rules.Add(new FormattingRule() {Expression = "([UnitPrice] [Quantity] (1 - [Discount]) - [Freight]) < 0",ApplyToRow = true,Type = FormattingType.Background});rules.Add(new FormattingRule() {FieldName = "Discount",Expression = "[Discount] > 0",ApplyToRow = false,Type = FormattingType.Font});rules.Add(new FormattingRule() {FieldName = "Discount",Expression = "[Discount] > 0",Type = FormattingType.Icon});return rules;} ...

February 19, 2021 · 2 min · jiezi

关于c#:如何在ASPNET-Core中编写高效的控制器

通过遵循最佳实际,能够编写更好的控制器。所谓的“瘦”控制器(指代码更少、职责更少的控制器)更容易浏览和保护。而且,一旦你的控制器很瘦,可能就不须要对它们进行太多测试了。相同,你能够专一于测试业务逻辑和数据拜访代码。瘦控制器的另一个长处是,它更容易保护控制器的多个版本。 这篇文章探讨了使控制器变胖的坏习惯,而后摸索了使控制器变瘦和易于治理的办法。我列出编写控制器的最佳实际可能并不全面,但我曾经探讨了最重要的一些,并在适当的状况下提供了相干的源代码。在接下来的几节中,咱们将钻研什么是胖控制器,为什么它是一种代码坏滋味,瘦控制器是什么,为什么它是无益的,以及如何使控制器瘦、简略、可测试和可治理。 从控制器中删除数据拜访代码在编写控制器时,你应该保持繁多责任准则,这意味着控制器应该有“一个责任”或“有且只有一个起因能够更改”。换句话说,你心愿将更改控制器代码的起因减至起码。上面的代码显示了具备数据拜访逻辑的典型控制器。 在.NET生态系统中应用特定的技术堆栈会产生一些困惑,因为有很多抉择,比方应该应用哪种类型的运行时?在这篇文章中,咱们将试图把这些要点都说分明。 public class AuthorController : Controller{    private AuthorContext dataContext = new AuthorContext();    public ActionResult Index(int authorId)    {        var authors = dataContext.Authors            .OrderByDescending(x=>x.JoiningDate)            .Where(x=>x.AuthorId == authorId)            .ToList();        return View(authors);    }}在action外部应用数据上下文实例读取数据,违反了繁多职责准则,并使你的控制器充斥着不应该呈现在那里的代码。在本例中,咱们应用一个DataContext(假如咱们应用Entity Framework Core)来连贯、解决数据库中的数据。 今天如果你决定更改数据拜访技术(为了更好的性能或其余起因),你也必须更改你的控制器。例如,如果我想应用Dapper连贯到底层数据库该怎么办?更好的办法是应用repository类来封装数据拜访逻辑(只管我不太喜爱repository模式)。让咱们用以下代码更新AuthorController。 public class AuthorController : Controller{    private AuthorRepository authorRepository = new AuthorRepository();    public ActionResult Index(int authorId)    {        var authors = authorRepository.GetAuthor(authorId);        return View(authors);    }}控制器当初看起来更瘦了。那么这是编写这个控制器的最佳办法吗?不是。如果你的控制器正在拜访数据拜访组件,那么它将做太多的事件,因而违反了繁多职责准则。控制器不应该有间接拜访数据拜访组件的数据拜访逻辑或代码。上面是AuthorController类的改良版本。 public class AuthorController : Controller{    private AuthorService authorService = new AuthorService();    public ActionResult Index(int authorId)    {        var authors = authorService.GetAuthor(authorId);        return View(authors);    }}AuthorService类利用AuthorRepository类执行CRUD操作。 ...

February 19, 2021 · 1 min · jiezi

关于c:ccc等等的听说了很多但只学了c有没有来科普一下的

集体了解:c++是基于c,然而面向对象,两者能够说是同源,C#新一些,个性不同,应用的中央也不同,c#优化了内存,然而是否是真的“优化”当然仁者见仁。c++简直齐全兼容c,他对指针的非凡操作能够说是十分独特的,长处毛病都在他,也给了他对底层操作的独特劣势。而感觉c#更像java[url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url]

February 18, 2021 · 1 min · jiezi

关于c#:C如何持续地监视外部信号

我是做PLC开发的,次要是操纵硬件。举个例子来说,X轴马达往前走,遇到传感器SB1,就停下来。这个SB1就必须处于继续的监控状态,程序不能以周期的形式去读这个SB1的状态,否则,在上一个读取SB1的行为完结,下一个读取SB1的行为还没有到来的时候,SB1被触发了,而程序却不晓得,则X轴马达就会冲过去,造成机器损坏。 PLC自身能继续地监控传感器,不须要额定编程,用户只有把SB1与X轴马达关联起来即可;SB1被触发了,X轴马达就会停机。 而C#上位机其实是监控PLC里的某个位的,比方M100.0。M100.0与SB1关联起来。SB1从1变成0,M100.0也会从1变成0;反之,SB1从0变成1,M100.0也会从0变成1。 因而,C#只有监督PLC里的M100.0即可,这种监督是继续的,只有M100.0一有变动,C#就能晓得,并且做出响应。 请问,这种继续的监督怎么做? Ps: 想过用While(true),感觉不大好[url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url]

February 18, 2021 · 1 min · jiezi

关于c:为什么我这代码还是超时

要求:工夫复杂度为O(n),空间复杂度为O(1)。一下是我的代码: include <stdio.h>int main(){int a,b,c,d,i;char ch;a=b=c=d=0;while((ch=getchar())!='\n'){if(ch=='a') a++;else if(ch=='b') b++;else if(ch=='c') c++;else if(ch=='d') d++;}for(i=0;i<a;i++) printf("a");for(i=0;i<b;i++) printf("b");for(i=0;i<c;i++) printf("c");for(i=0;i<d;i++) printf("d");printf("\n");return 0;}[url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url]

February 18, 2021 · 1 min · jiezi

关于c:运行时错误‘214746725980004005

目测是代码外面调用了ODBC,你的SQL server客户端没有装好或者ODBC数据源没设置好。[url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url]

February 18, 2021 · 1 min · jiezi

关于c:c-语句如何转VBNET

if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex + 1].Value is BuiltInType builtInType) {}这句如何转成VB.NET 啊[url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url][url]https://book.douban.com/douli...[/url][url]https://movie.douban.com/doul...[/url][url]https://www.douban.com/doulis...[/url][url]https://m.douban.com/doulist/...[/url]

February 18, 2021 · 1 min · jiezi

关于c#:如何在ASPNET-Core-中使用IHttpClientFactory

利用IHttpClientFactory能够无缝创立HttpClient实例,防止手动治理它们的生命周期。 当应用ASP.Net Core开发应用程序时,可能常常须要通过HttpClient调用WebAPI的办法以查看终结点是否失常工作。要实现这一点,通常须要实例化HttpClient并应用该实例来调用你的办法。然而间接应用HttpClient也有一些毛病,次要与手动治理实例的生命周期无关。 你能够应用IHttpClientFactory创立HttpClient来防止这些问题。IHttpClientFactory是在.Net Core 2.1引入的,它提供了一个命名,配置和创立HttpClient实例的外围性能,并能主动治理实例的池化和生命周期。 上面咱们通过代码进一步探讨HttpClient和IHttpClientFactory,以及所设计的概念。要应用提供的代码,你须要装置Visual Studio 2019。 在Visual Studio 2019中创立一个ASP.NET Core MVC我的项目   假如你的零碎中装置了Visual Studio 2019,请依照上面列出来的步骤创立一个新的ASP.NET Core我的项目。 启动Visual Studio IDE。点击“创立新我的项目”。在“创立新我的项目”窗口中,从模板列表中抉择ASP.NET Core Web应用程序。单击Next。在“配置新我的项目”窗口中,指定新我的项目的名称和地位。能够抉择“将解决方案和我的项目放在同一个目录中”复选框。点击Create。在“创立一个新的ASP.NET Core Web应用程序“窗口中,抉择。NET Core作为运行时,而后抉择asp.net Core作为运行时。NET Core 3.1(或更高版本)。抉择“Web Application (Model-View-Controller)”作为我的项目模板来创立一个新的ASP.NET Core MVC应用程序。确保复选框“启用Docker反对”和“配置HTTPS”没有选中,因为咱们不会在这里应用这些个性。确保身份验证设置为“无身份验证”,因为咱们也不会应用身份验证。单击Create。依照这些步骤将创立一个新的ASP.NET Core MVC应用程序。在新我的项目中,创立一个新的API Controller,并应用默认名称保留它,即ValuesController。咱们将在接下来的局部中应用这个我的项目。 挑战HttpClient只管HttpClient没有间接实现IDisposable接口,但它扩大了System.Net.Http。HttpMessageInvoker,这个类实现了IDisposable。然而,当应用HttpClient实例时,你不应该手动操作开释它们。只管能够在HttpClient实例上调用Dispose办法,但不举荐这样做。 应该怎么做呢?一种抉择是使HttpClient动态化,或者将HttpClient的非动态实例包装在自定义类中,并使其成为单例类。然而更好的代替办法是应用IHttpClientFactory来生成HttpClient的实例,而后应用该实例来调用操作方法。 IHttpClientFactory 和HttpClientFactoryIHttpClientFactory是一个由DefaultHttpClientFactory类实现的接口,这是一个工厂模式。DefaultHttpClientFactory实现了IHttpClientFactory和IHttpMessageHandlerFactory接口。IHttpClientFactory提供了ASP.NET Core对创立、缓存和解决HttpClient实例提供了杰出的内置反对。 请留神,HttpClientFactory只是一个帮忙类,用于创立应用提供的处理程序配置的HttpClient实例。这个类有以下办法: Create(DelegatingHandler[])Create(HttpMessageHandler,DelegatingHandler[])CreatePipeline(HttpMessageHandler,IEnumerable<DelegatingHandler>)重载的HttpClientFactory类的Create办法看起来像这样: public static HttpClient Create(params DelegatingHandler[] handlers){ return Create(new HttpClientHandler(), handlers);}public static HttpClient Create(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers){ HttpMessageHandler pipeline = CreatePipeline(innerHandler, handlers); return new HttpClient(pipeline);}引入HttpClientFactory和IHttpClientFactory是为了更好地治理HttpMessageHandler实例的生命周期。 为什么应用IHttpClientFactory?当你开释HttpClient实例时,连贯将放弃关上状态长达4分钟。此外,能够在任何工夫点关上socket的数量是有限度的——不能同时关上太多socket。因而,当应用太多HttpClient实例时,可能会耗尽socket。 这就是IHttpClientFactory的意义所在。你能够通过利用IHttpClientFactory来创立用于调用HTTP API办法的HttpClient实例,以防止HttpClient所面临的问题。在ASP.NET Core中实现IHttpClientFactory的次要指标是为了确保应用工厂模式创立HttpClient实例的同时防止socket耗尽。 ...

February 18, 2021 · 2 min · jiezi

关于c#:Qt开发Activex笔记三C调用Qt开发的Activex控件

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/113789727 长期继续带来更多我的项目与技术分享,征询请加QQ:21497936、微信:yangsir198808 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) Qt开发专栏:开发技术上一篇:《Qt开发Activex笔记(二):Qt调用Qt开发的Activex控件》下一篇:敬请期待... 前言 开发Activex控件,以供其余应用程序调用,本篇章解说C#调用Activex控件,不限于Qt开发的Activex控件。 Wpf要调用Activex控件,必要先用C#对Activex控件进行包装,而后提供给Wpf调用。 Demo C#调用Activex办法步骤一:注册activex控件 运行之前先要注册,应用Qt下自带的idc注册一下。 idc -regserver activeHelloWorldDemo.dll 步骤二:确认activeQt控件的clsid 查看一下,关上注册表并搜寻一下,确认clsid,如下图: "2F12BFB8-137D-4DC2-9A93-634EFE5A6DFC"步骤三:创立c#我的项目,引入com的dll 将注册的dll引入到我的项目中,如下图: 步骤四:代码中应用控件 步骤五:编写代码private void button1_Click(object sender, EventArgs e){ activeHelloWorldDemoLib.activeHelloWorldDemo dlg = new activeHelloWorldDemoLib.activeHelloWorldDemo(); dlg.show();} 源码using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace trainSimulationDemo{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { activeHelloWorldDemoLib.activeHelloWorldDemo dlg = new activeHelloWorldDemoLib.activeHelloWorldDemo(); dlg.show(); } }} ...

February 17, 2021 · 1 min · jiezi

关于c++:STL总结

Vector数组初始化 int a[5] = {1,2,3,4,5}vector初始化 vector<int> list = {1,2,3,4,5}vector<int> nums;vector<vector<int>> f1(n, vector<int>(m,0));sort(nums.begin(), nums.end());nums.push_back(x);nums.insert(nums.begin(), x);nums.insert(nums.begin() + n , x);nums.erase(nums.begin());int rows=triangle.size();//求得行数int col=triangle[0].size();//求的列数auto x = max_element(a.begin() + i, a.end());用的时候*x整型转字符串to_string(i)字符串转整型int a=atoi(s.c_str());int b=stoi(s);vector中的find()vector<int>::iterator result = find(arr2.begin( ), arr2.end( ), arr1[i]);if ( result == arr2.end( ) ) //如果没找见去重 alls.erase(unique(alls.begin(), alls.end()), alls.end());Stringstr.insert(str.begin(), 'a')切分字符串:str.substr(str.begin(), str.end())字符串增加元素:str.push_back('a')字符串删除开端元素:str.pop_back('a')删除元素 str.substr(0, str.length() - 1);删除元素 str.erase(str.end() - 1);mapmap<int, int> loc;获取键、值for(auto x : f1) x.first,x.second s.find() 查找一个元素,如果容器中不存在该元素,返回值等于s.end()if(numSet.find(findNum)!=numSet.end()代表找到了 setset.insert();set遍历set<int>::iterator it;for(it=notAppearSet.begin ();it!=notAppearSet.end ();it++) cout << *it;autoauto c 主动推断c的类型

February 16, 2021 · 1 min · jiezi

关于c++:C并发与多线程-13线程池浅谈线程数量总结

浅谈线程池线程池(英语:thread pool):一种线程应用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池保护着多个线程,期待着监督管理者调配可并发执行的工作。这防止了在解决短时间工作时创立与销毁线程的代价。线程池不仅可能保障内核的充分利用,还能避免过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数个别取cpu数量+2比拟适合,线程数过多会导致额定的线程切换开销。任务调度以执行线程的常见办法是应用同步队列,称作工作队列。池中的线程期待队列中的工作,并把执行完的工作放入实现队列中。C++11多线程总结线程创立的极限数量个别为 2000 个。线程创立数量倡议 采纳某些开发倡议和批示来确保程序高效执行。依据理论利用场景;思考可能被阻塞的最大线程数量,即创立多余最大被阻塞(耗时工作)线程数量的线程。如,有100个线程可能解决耗时工作,启动 110 个线程就能够保障有闲暇线程解决其它申请。线程的创立数量尽量不要超过 500 个,尽量管制在 200 个之内。C++线程相干参考网址cplusplus.comcppreference.com

February 16, 2021 · 1 min · jiezi

关于c++:CS144-Lab-Assignments-手写TCP-LAB3

CS 144: Introduction to Computer Networking, Fall 2020https://cs144.github.io/My Repohttps://github.com/wine99/cs1... 总体思路tick 不须要咱们来调用,参数的意义是间隔上次 tick 被调用过来的工夫,也不须要咱们来设定。咱们只须要在 tick 中实现,通过参数判断过来了多少工夫,须要执行何种操作即可。 留神依据文档,咱们要不须要实现抉择重传,而是相似回退 N,须要存储已发送并且未被确认的段,进行累计确认,超时时只有重传这些段中最早的那一个即可。 TCPReceiver 调用 unwrap 时的 checkpoint 是上一个接管到的报文段的 absolute_seqno,TCPSender 调用 unwrap 时的 checkpoint 是 _next_seqno。 我的实现中计时器开关的解决: 发送新报文段时若计时器未关上,开启ack_received() 中,如果有报文段被正确地确认,重置计时器和 RTO,如果所有报文段均被确认(bytes in flight == 0),敞开计时器tick() 中,若计时器为敞开状态,间接返回,否则累加计时而后解决超时增加的成员变量class TCPSender { private: bool _syn_sent = false; bool _fin_sent = false; uint64_t _bytes_in_flight = 0; uint16_t _receiver_window_size = 0; uint16_t _receiver_free_space = 0; uint16_t _consecutive_retransmissions = 0; unsigned int _rto = 0; unsigned int _time_elapsed = 0; bool _timer_running = false; std::queue<TCPSegment> _segments_outstanding{}; // See test code send_window.cc line 113 why the commented code is wrong. bool ack_valid(uint64_t abs_ackno) { return abs_ackno <= _next_seqno && // abs_ackno >= unwrap(_segments_outstanding.front().header().seqno, _isn, _next_seqno) + // _segments_outstanding.front().length_in_sequence_space(); abs_ackno >= unwrap(_segments_outstanding.front().header().seqno, _isn, _next_seqno); } public: void send_segment(TCPSegment &seg);};send_segment(TCPSegment &seg) 只在 fill_window() 中被调用,重传只须要 _segments_out.push(_segments_outstanding.front())_receiver_window_size 保留收到无效(无效的含意见下面 ack_valid())确认报文段时,报文段携带的接管方窗口大小_receiver_free_space 是在 _receiver_window_size 的根底上,再减去已发送的报文段可能占用的空间(_bytes_in_flight)fill_window() 实现如果 SYN 未发送,发送而后返回如果 SYN 未被应答,返回如果 FIN 曾经发送,返回如果 _stream 临时没有内容但并没有 EOF,返回如果 _receiver_window_size 不为 0 ...

February 16, 2021 · 3 min · jiezi

关于c++:C并发与多线程-12recursivemutextimedmutexrecursivetimedmutex

window 临界区window 临界区资源对象与C++的 std::mutex 对象相似,能够爱护多个线程对临界区资源的拜访。#include <iostream>#include <thread>#include <Windows.h>static CRITICAL_SECTION g_winsec;void print_block (int n, char c){ EnterCriticalSection(&g_winsec); // 2. 进入临界区 for (int i=0; i<n; ++i) { std::cout << c; } std::cout << '\n'; LeaveCriticalSection(&g_winsec); // 3. 来到临界区}int main (){ InitializeCriticalSection(&g_winsec); // 1. 初始化临界资源对象 std::thread th1 (print_block,50,'*'); std::thread th2 (print_block,50,'$'); th1.join(); th2.join(); return 0;}输入: **************************************************$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$屡次进入临界区试验window 临界资源对象能够在同一线程中多次重复进入,对应次数的来到,程序仍失常执行。std::mutex 对象只能在同一线程进行一次加锁并对应一次解锁,否则程序抛出异样。测试1:window 临界区 #include <iostream>#include <thread>#include <Windows.h>static CRITICAL_SECTION g_winsec;void print_block (int n, char c){ EnterCriticalSection(&g_winsec); // 2. 进入临界区 EnterCriticalSection(&g_winsec); // 屡次进入 。。。 EnterCriticalSection(&g_winsec); // 屡次进入 。。。 for (int i=0; i<n; ++i) { std::cout << c; } std::cout << '\n'; LeaveCriticalSection(&g_winsec); // 3. 来到临界区 LeaveCriticalSection(&g_winsec); // 屡次来到 。。。 LeaveCriticalSection(&g_winsec); // 屡次来到 。。。}int main (){ InitializeCriticalSection(&g_winsec); // 1. 初始化临界资源对象 std::thread th1 (print_block,50,'*'); std::thread th2 (print_block,50,'$'); th1.join(); th2.join(); return 0;}输入:[后果正确] ...

February 15, 2021 · 3 min · jiezi

关于c:排序算法

前沿明天咱们来看看几种常见的排序算法 插入排序定义插入排序的算法形容是一种简略直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应地位并插入。 形容从第一个元素开始,该元素能够认为曾经被排序取出下一个元素,在曾经排序的元素序列中从后向前扫描如果该元素(已排序)大于新元素,将该元素移到下一地位反复步骤3,直到找到已排序的元素小于或者等于新元素的地位将新元素插入到该地位后反复步骤 2~5复杂度工夫复杂度O(N^2) 空间复杂度O(1) 复法void InsertionSort(int *arr, int size) { int i, j, tmp; for (i = 1; i < size; i++) { if (arr[i] < arr[i-1]) { //如果要大在前 改这个判断 和 arr[j] < temp tmp = arr[i]; for (j = i - 1; j >= 0 && arr[j] > tmp; j--) { arr[j+1] = arr[j]; } arr[j+1] = tmp; } } } 冒泡排序形容比拟相邻的元素。如果第一个比第二个大,就替换它们两个 复杂度工夫复杂度O(n^2) 空间复杂度O(1) 算法void BubbleSort(int *arr, int size) { int i, j, tmp; for (i = 0; i < size - 1; i++) { for (j = 0; j < size - i - 1; j++) { if (arr[j] > arr[j+1]) { tmp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tmp; } } } } 抉择排序定义抉择排序,是一种简略直观的排序算法。它的工作原理:首先在末排序列中找到最小(大)元素,寄存到排序序列的起始地位,直到全副待排序的数据元素排完。 ...

February 15, 2021 · 1 min · jiezi

关于c:深入-Python-解释器源码我终于搞明白了字符串驻留的原理

英文:https://arpitbhayani.me/blogs... 作者:arpit 译者:豌豆花下猫(“Python猫”公众号作者) 申明:本翻译是出于交流学习的目标,基于 CC BY-NC-SA 4.0 受权协定。为便于浏览,内容略有改变。 每种编程语言为了表现出色,并且实现卓越的性能,都须要有大量编译器级与解释器级的优化。 因为字符串是任何编程语言中不可或缺的一个局部,因而,如果有疾速操作字符串的能力,就能够迅速地进步整体的性能。 在本文中,咱们将深入研究 Python 的外部实现,并理解 Python 如何应用一种名为字符串驻留(String Interning)的技术,实现解释器的高性能。 本文的目标不仅在于介绍 Python 的外部常识,而且还旨在使读者可能轻松地浏览 Python 的源代码;因而,本文中将有很多出自 CPython 的代码片段。 全文提纲如下: (在 Python猫 公众号回复数字“0215”,下载高清思维导图) 1、什么是“字符串驻留”?字符串驻留是一种编译器/解释器的优化办法,它通过缓存一般性的字符串,从而节俭字符串解决工作的空间和工夫。 这种优化办法不会每次都创立一个新的字符串正本,而是仅为每个适当的不可变值保留一个字符串正本,并应用指针援用之。 每个字符串的惟一拷贝被称为它的intern,并因而而得名 String Interning。 Python猫注:String Interning 个别被译为“字符串驻留”或“字符串留用”,在某些语言中可能习惯用 String Pool(字符串常量池)的概念,其实是对同一种机制的不同表述。intern 作为名词时,是“实习生、实习医生”的意思,在此能够了解成“驻留物、驻留值”。查找字符串 intern 的办法可能作为公开接口公开,也可能不公开。古代编程语言如 Java、Python、PHP、Ruby、Julia 等等,都反对字符串驻留,以使其编译器和解释器做到高性能。 2、为什么要驻留字符串?字符串驻留晋升了字符串比拟的速度。 如果没有驻留,当咱们要比拟两个字符串是否相等时,它的工夫复杂度将回升到 O(n),即须要查看两个字符串中的每个字符,能力判断出它们是否相等。 然而,如果字符串是固定的,因为雷同的字符串将应用同一个对象援用,因而只需查看指针是否雷同,就足以判断出两个字符串是否相等,不用再逐个查看每个字符。因为这是一个十分广泛的操作,因而,它被典型地实现为指针相等性校验,仅应用一条齐全没有内存援用的机器指令。 字符串驻留缩小了内存占用。 Python 防止内存中充斥多余的字符串对象,通过享元设计模式共享和重用曾经定义的对象,从而优化内存占用。 3、Python的字符串驻留像大多数其它古代编程语言一样,Python 也应用字符串驻留来进步性能。在 Python 中,咱们能够应用is运算符,查看两个对象是否援用了同一个内存对象。 因而,如果两个字符串对象援用了雷同的内存对象,则is运算符将得出True,否则为False。 >>> 'python' is 'python'True咱们能够应用这个特定的运算符,来判断哪些字符串是被驻留的。在 CPython 的,字符串驻留是通过以下函数实现的,申明在 unicodeobject.h 中,定义在 unicodeobject.c 中。 PyAPI_FUNC(void) PyUnicode_InternInPlace(PyObject **);为了查看一个字符串是否被驻留,CPython 实现了一个名为PyUnicode_CHECK_INTERNED的宏,同样是定义在 unicodeobject.h 中。 ...

February 15, 2021 · 3 min · jiezi

关于c++:C并发与多线程-11stdatomic叙谈stdlaunchstdasync-深入

std::atomic 叙谈原子类模板齐全专用于根本整数类型(bool除外),以及 <cstdint> 中 typedef 所需的任何扩大整数类型。专用的根本数据类型: charsigned charunsigned charshortunsigned shortintunsigned intlongunsigned longlong longunsigned long longchar16_tchar32_twchar_textended integral types (if any)附加的成员函数: atomic::fetch_addatomic::fetch_subatomic::fetch_andatomic::fetch_oratomic::fetch_xoratomic::operator++atomic::operator--operator (comp. assign.)对于 bool 实例化,仅反对惯例原子操作。请留神,大多数 c-style 原子类型都是这些专门化的别名(或这些专门化继承的基类的别名)原子操作还局部专用于指针类型,具备一下附加成员函数:atomic::fetch_addatomic::fetch_subatomic::operator++atomic::operator--operator (comp. assign.)std::launch(std::async) 深刻了解std::async enum class launch : /* unspecified */ { async = /* unspecified */, deferred = /* unspecified */, /* implementation-defined */};此枚举类型用于定义 aync 异步调用中的启动策略。launch::async入口函数由新线程异步调用,并将其返回其与共享状态的拜访点同步。#include <iostream>#include <future>#include <thread>using namespace std;bool async_func () { cout << "async_func begin " << std::this_thread::get_id() << endl; cout << "async_func end" << endl; return true;}int main (){ cout << "main begin " << std::this_thread::get_id() << endl; std::future<bool> fut = std::async (launch::async, async_func); // 创立新线程并调用线程入口函数 cout << fut.get() << endl; cout << "main end" << endl; return 0;}输入: ...

February 14, 2021 · 1 min · jiezi

关于c:C并发与多线程-11sharedfutureautomic

std::shared_future类模板template <class T> shared_future;template <class R&> shared_future<R&>; // specialization : T is a reference type (R&)template <> shared_future<void>; // specialization : T is void一个 shared_future 对象行为相似于 future 对象,除了它能够被赋值,而且一个以上的 shared_future 能够在他们的共享状态完结时共享所有权。它们还被容许一旦筹备好就屡次检索共享状态下的值。shared_future 对象能够从 future 对象隐式转换,也能够通过 future::share 显式取得。在这两种状况下,原 future 对象本身将生效。共享状态的生存期至多要继续到与之关联的最初一个对象被销毁为止。从 shared_future 中获取值(应用成员函数 get) 不会开释其对共享状态的所有权(与 future 不同)。因而,如果与 shared_future 对象相关联,则共享状态能够在最后取得它的对象(如果有的话)之后持续存在。成员函数形容get当共享状态就绪时,返回存储在共享状态中的值的援用(或引发其异样)valid查看 shared_future 对象是否与共享状态关联wait期待共享状态准备就绪wait_for期待共享状态在 rel_time 指定的工夫内准备就绪wait_until期待共享状态准备就绪,最多直到abs_time工夫点#include <iostream>#include <thread>#include <future>using namespace::std;int mythread(){ cout << "mythread begin" << endl; this_thread::sleep_for(chrono::microseconds(5000)); cout << "mythread end" << endl; return 5;}int main(){ cout << "main begin" << endl; future<int> result = async(launch::async, mythread); shared_future<int> result_s = result.share(); // 等价 // shared_future<int> result_s = async(launch::async, mythread); if (result_s.valid()) { cout << result_s.get() << endl; cout << result_s.get() << endl; cout << result_s.get() << endl; } cout << "main end" << endl; return 0;}输入: ...

February 14, 2021 · 2 min · jiezi

关于c:C语言中的指针和数组

指针是 C 语言中的一个特点,也是内存地址,是内存单元的编号,指针变量是用来寄存内存地址的变量,不同类型的指针变量所占用的存储单元长度是雷同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针当前,不仅能够对数据自身,也能够对存储数据的变量地址进行操作;个别把指针称为指针变量,指向的对象能够是变量或者数组等;指针指向数组时,它内容存储的是数组的首地址,所以数组和指针就产生了肯定的关系。那什么是数组呢?具备雷同类型的若干元素按有序的模式组织起来的一种汇合就叫做数组,上面会对指针、指针和数组相结合的一些用法进行剖析。 1、指针 1、1 定义 int * 类型的指针变量以及批改这个指针变量,其余类型的指针变量写法也相似 int * p; //p是变量的名字,int * 示意 p 变量寄存的是 int 类型变量的地址;它并不是示意定义了名叫 *p 的变量int i = 5;p = &i; //p 保留了 i 的地址,所以 p 指向 iint i2 = 6;p = &i2; //批改 p 的值不影响 i 的值int * p2 = &i;i = 9; //批改 i 的值不影响 p2 的值printf("%d\n",*p2); //*p2 输入为9,*p2 等同于 i 的值,p2 等同于 i 的地址;*p2 能够了解为以 p2 的内容为地址的变量,p2 的内容就是 i 的地址1、2 指针与指针变量是不同的概念 ...

February 12, 2021 · 3 min · jiezi