首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

算法学习之路|用C++刷算法会用到的STL(三)——string

三、string 1.string的自我介绍 在C语言中,一般使用字符数组 char str[]来存放字符串,很麻烦!在C++中加入了string类型,可以理解为元素为char型的vector,string对字符串的需求功能进行了封装,使得操作简单,不容易犯错。 使用string需要添加的头文件是#include<string>(桥黑板!!string.h(同cstring)和string是不一样的头文件)。当然还要加上using namespace std;这一句的。 2.string的定义 定义的方式和基本数据类型相同,在string后面加上变量名即可: string str; 如果要初始化,可以直接给string类型的变量进行赋值: string str="abcd"; 3.string容器内元素的访问形式 注:之前说过C++容器中有一对好基友,没错! 就是string和vector,只有他俩可以使用直接对迭代器进行加减某个数字,如str.begin()+3 <li>通过下标访问 即可以像访问char型数组一样去访问string,比如:#include<stdio.h>#include<string>string str="hahah";printf("%c",str[2]);//输出 h但是要读入和输出整个字符串,则只能用cin和cout: [php]#include#includeusing namespace std;int main(){ string str; cin>>str; cout<<str;//相当于,printf("%s\n",str.c_str());即将string类型用c_str()变为字符数组 return 0;//并不推荐第二种写法!了解即可 }[/php] <li>通过迭代器访问 因为string不像其他STL容器一样需要参数,因此迭代器的定义很简单:string::iterator it;这样就得到了迭代器,并且可以通过*it来访问string中的每一位元素:for(string::iterator it=str,begin();it!=str.end();it++){printf("%c",*it);} 4.string中的基本操作 (真的只是基本操作,也是常用的,文末推荐几个博客,有更多骚操作!!!里面写的很详细,感兴趣的朋友可以深入研究,string真的很强大,之前说过, STL各个都是武林高手,身怀绝技的啊!) (1)operator+= 这是string的加法,可以将两个string直接拼起来!,比如: string str1="i",str2="love you!",str3; str3=str1+str2;//cout得到str3: i love you!(single dog 一万点伤害(捂脸)) str1+=str2;//将str2直接拼接到str1上,得到str1:同上(捂脸)(捂脸) (2)compare operator 简单说一下,即两个string类型可以直接使用==,!=,<=等比较大小,比较规则为字典序,从两个string的首位开始比较,遇到不一样的即按字典序比较返回结果。但比如 ,str1="aa",str2="aaa",则是str1<str2,不多介绍,用的时候试一下就自然清楚啦。 (3)lenth()/size() 可以认为两个基本相同,时间复杂度都是O(1),返回string的长度,即存放的字符数。比如,str=“aa",返回2。 (4)insert() string的insert()函数写法很多,实际上不只insert,赋值,连接,比较查找等函数都很多,自然,功能也很细节化,很完善,不常用,这里只介绍算法需要用到的,就上上文所说的,文末会推荐一个非常好的博客,如果又需要,可以去仔细研究。 <li><em>insert(pos,string),</em>在pos号位置插入字符串string。</li> string str="abc",str2="xyz"; str.insert(1,str2);//结果str:axyzbc <li><em>intsert(it,it2,it3)</em>,it为原字符串欲插入的位置,it2和it3为待插入字符串的首位迭代器,用来表示串[it2,it3)将被插在it的位置上,比如: string str="abcxyz",str2="opq";str.insert(str.begin()+3,str2.begin(),str2.end());//桥黑板!!再次强调,只有vector和string这两个好基友迭代器加数字的形式!!结果,str:abcopqxyz (5)erase() 删除单个元素: str.erase(it),it为需要删除的元素的迭代器。 删除一个区间内的所有元素: str.erase(first,last),first未删除区间的起始迭代器,last为需要删除区间的末尾迭代器的下一个指针,也即[first,last)。 str.erase(pos,length),其中pos为需要删除的其实位置,length为删除的字符个数。 (6)clear() clear()用来清空string中的数据,时间复杂度O(1)。 substr() substr(pos,len)返回从pos号位开始,长度为len的子串,时间复杂度O(len)。(注:本文只有it才是迭代器,pos是下标) (7)string::npos string::npos是一个常数,其本身的值为-1,但由于是 unsigned_int类型,因此呢,实际上也可以认为是unsigned_int类型的最大值。 string::npos用以作为find函数(如上文所述,find即查找函数非常多,详见下文推荐博客!)失配时的返回值。 可以认为string::npos等于-1或者4294967295。 (8)find() <li>str.find(str2),当str2是str的子串时,返回其在str中第一次出现的位置;如果str2不是str的子串,那么返回上文提到的string::npos(也就是-1和那个无符号整型的最大值啦)。</li> <li>str.find(str2,pos),从str的pos号位开始匹配str2,返回值同上。时间复杂度为O(nm),n,m为str,str2的长度。</li> (9)replace() <li><em>str.replace(pos,len,str2)</em>把str从pos号位开始,长度为len的子串替换为str2。</li> <li><em>str.replace(it1,it2,str2)</em>把str的迭代器[it1,it2)范围的子串换为str2。</li> <li>时间复杂度<em>O(str.length())</em>。</li> 5.string的优良特性 C++ 标准库中的string类型 支持可变长度的字符串,提供了很多有用的操作 标准库将负责管理与存储字符相关的内存。 平均来说 使用string类型的程序执行速度比C风格字符串快很多 而且不容易出错 ;以前的很多地方C语言程序是用C语言风格字符串写的 没有用标准库类型string 可能不具备有移植性 两者都要掌握 现代C++程序员应更多地使用string。 6.string的用途 处理“串”的问题。。。 来道题练练手: PAT A1060. Are They Equal (25) 注:题意不难,编码较为复杂,但也是练string的好题目!加油吧 PAT A1001. A+B Format (20) 注:此题解法很巧妙,简洁,推荐66姐的博客1001. A+B Format (20)-PAT甲级真题 参考:《算法笔记》(胡凡,曽磊) 推荐博客:标准C++中的string类的用法总结 。

优秀的个人博客,低调大师

算法学习之路|用C++刷算法会用到的STL(一)——vector

STL是Standard Template Library的简称,中文名标准模板库。 从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。STL现在是C++的一部分,因此不用安装额外的库文件。 在C++标准中,STL被组织为下面的17个头文件: <algorithm>、<deque>、<functional>、<iterator>、<array>、<vector>、<list>、<forward_list>、<map>、<unordered_map>、<memory>、<numeric>、<queue>、<set>、<unordered_set>、<stack>和<utility>。 一、vector 1. vector的自我介绍 vector是向量的意思,可以理解为“可变长度的数组”。 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。 相当于一个动态数组,在你不知道需要的数组有多大时可以使用它来节省很多空间。在ACM中常常会出现内存溢出(out of memory)的问题导致WA(wrong answer),而使用vector就能节省很多内存。 使用vector要在程序开头加上#include<vector>来包含需要的头文件,还有加上“using namespace std;”,这样就可以在代码中使用vector了。 2.vector的定义 定义一个vector: vector<typename> vectorname; 这个定义相当于定义了一个一维的数组vectorname[SIZE],只不过这个SIZE的长度是可以改变的,随着你“加入”进去数的个数而改变。所谓“可变长度的数组”。 和一维的数组一样,这里的typename可以是任何的类型,如int,double,char,string,long long ,也可以是结构体,甚至是STL的容器如vector,set,queue,stack等。注意!如果typename也是一个容器的话,比如vector<vector<int> > vectorname,要在两个'<'符号之间加上一个空格,否则编译时会误以为是位移操作。 3.vector的创建 vector<double> vec1; // 创建一个空的double向量 vector<int> vec(66); // 创建一个初始大小为66的int向量 vector<double> vec2(vec1); // 创建一个double型的vec2,并用vec1去初始化vec2 vector<char> vec(10,'k'); // 创建一个含有10个char型数据的vector,并全部初始化为'k' vector<int> vec(10,1);//创建一个初始大小为10的并且值都是1的vector vector<int> vec2(vec1.begin(),vec1.begin()+3);//用向量vec1的第0个到第2个值初始化vec2 int arr[5] = {1, 2, 3, 4, 5}; vector<int> vec(arr, arr + 5); //将arr数组的元素用于初始化vec向量,末尾指针指向结束元素 //的下一个 vector<int> vec(&arr[1], &arr[4]); //将arr[1]~arr[4]范围内的元素作为vec的初始值,不包含arr[4], //原因如上 4.特别的,元素为vector的vector数组 (其实就是vector的二维数组)和vector数组! 如果typename是vector,那么就这么定义vector<vector<int> > vectorname; 注意在相邻的'>'之间要加空格。 这个就像二维数组的定义,其中一维是一个元素是vector的vector数组。可以把vector数组 当作两个维长度都可变的二维数组理解。vector数组的定义vector<typename> Arrayname[arraySize]; 比如,vector<int> vec[66]; 这样Arrayname[0]~Arrayname[arraySize-1]中每一个都是vector容器。 而vector<vector<int> > vectorname不同的地方时,前者的第一维长度已经固定为arraySize了, 后者却是两个维度都可变长的数组。哈哈哈,用你的大脑,发挥空间想象能力,出现了什么图形? 很神奇是不是! 5.vector容器内元素的访问形式 vector一般有两种访问形式:通过下标访问或者是通过迭代器访问。 (1)通过下标访问 和访问普通数组是一样的,一个已经定义的vector<typename> vec的vector容器,直接访问vec[index]就可以了(比如 vec[0],vec[1])。需要注意的一点是,首先这个vec得有size!!!桥黑板!什么意思呢?就是如果一开始你定义了 比如vector<int> vec1;直接使用vec[0]是不对的!因为里面还没有长度啊!开始用的时候我就经常犯这个错误(尴尬) 。所以可以通过下标访问的范围是从0~vec.size()-1. (2)通过迭代器访问 啥叫迭代器啊?好可怕~就理解为指针吧,不去考虑细节,两者是一样的(包括在java中最近遇见的引用,这简直是三胞胎!)。 定义如下: vector<typename>::iterator it;(it就是变量名,一般默认都写成it) 这样it就是一个vector<typename>::iterator 型的变量了(hhh,这个名字好长啊),其中,typename就是定义vector时 写的类型。比如: vector<double>::iterator it; vector<int> vec; vector<int>::iterator it2; it2=vec.begin();(或者合成一条:vector<int>::iterator it2=vec.begin(); ) 这样就得到了迭代器it(or it2),并且可以通过*it来访问vector里的元素。 vector<int> vec; vector<int>::iterator it; for (it = vec.begin(); it != vec.end(); it++)//vector的迭代器不支持it<vec.end()写法,因此循环中只能用it!=end() cout << *it << endl; //或者 vector<int>::iterator it=vec.begin(); for(int i=0;i<vec.size();i++){ printf("%d ",*(it+i));//桥黑板!!在STL容器中,只有vector和string这两个好基友,才允许使用vev.begin()+3这种迭代器加上整 //数的写法,只有这俩。 //从这里可以看出,vec[i]和*(vec.begin()+i)是等价的 } //或者 for (size_t i = 0; i < vec.size(); i++) { cout << vec.at(i) << endl;//见下文分解 } 好了,终于说完访问形式了,可以介绍基本操作啦! 6.vector的基本操作 (1)对容量的操作 得到向量的大小: vec.size(); 得到向量最大可以是多大: vec.max_size(); 重新设置容器size的大小: vec.resize(num); 重新设置容器capacity的大小: vec.reserve(num); 向量真实大小: vec.capacity(); 判断向量是否为空: vec.empty(); 注:关于resize()和reverse(),我觉得记住一点就行了,容器调用resize()函数后, 所有的空间都已经初始化了,所以可以直接访问。比如: vector<int> vet; vec.resize(100); vec[0]=1;//合法语句! 而reserve()函数预分配出的空间没有被初始化,所以不可访问。 推荐一个关于resize()和reserve()写的不错的博客vector中resize()和reserve()区别 (2)修改元素 多个元素赋值: vec.assign(); //类似于初始化时用数组进行赋值 末尾添加元素: vec.push_back(i)//在末尾添加元素i 末尾删除元素: vec.pop_back(); 任意位置插入元素: vec.insert(it,x); 用来向vector的任意迭代器(见上文)it处插入一个元素x,时间复杂度O(N); 任意位置删除元素: vec.erase(); erease(it)即删除迭代器为it处的元素; erase(first,last)即删除[first,last)内的所有元素;(老美的左闭右开,你懂的) 交换两个向量的元素: vec.swap();//不多讲,用的真的很少。同样,推荐博客vector利用swap()函数进行内存的释放 (3)惊现迭代器 开始指针:vec.begin();末尾指针:vec.end(); //指向最后一个元素的下一个位置指向常量的开始指针: vec.cbegin(); //意思就是不能通过这个指针来修改所指的内容,但还是可以通过其他方式修改的,而且指针也是可以移动的。(用的很少,不妨先忽略吧)指向常量的末尾指针: vec.cend();(同上,不多说) (4)元素的访问 下标访问: vec[1]; //桥黑板!!并不会检查是否越界at方法访问: vec.at(1); //以上两者的区别就是at会检查是否越界,是则抛出out of range异常访问第一个元素: vec.front();访问最后一个元素: vec.back();返回一个指针: int* p = vec.data(); //可行的原因在于vector在内存中就是一个连续存储的数组,所以可以返回一个指针指向这个数组。这是是C++11的特性。(可忽略) (5)一些算法 遍历元素 Cvector<int>::iterator it; for (it = vec.begin();it != vec.end(); it++) cout << *it << endl; //或者 for (size_t i = 0; i < vec.size(); i++) { cout << vec.at(i) << endl; } 元素翻转 C#include <algorithm> reverse(vec.begin(), vec.end()); 元素排序 C#include <algorithm> sort(vec.begin(), vec.end()); //采用的是从小到大的排序 //如果想从大到小排序,可以采用上面反转函数,也可以采用下面方法: bool Comp(const int& a, const int& b) {//固定套路,要加上const,意思是不能修改引用 return a > b; } sort(vec.begin(), vec.end(), Comp); 7.vector的用武之地 (1)储存数据 vector本身可以作为数组使用,而且在一些元素个数不确定的场合可以很好的节省空间。 有些场合需要根据一些条件把部分数据输出在同一行,数据中间用空格隔开。由于输出的数据个数是不确定的,为了跟方便的处理最后一个满足条件的数据后面不输出额外的空格,可以先用vector记录所有需要输出的数据,然后一次性输出。 有强大的方法可以调用(妈呀,java学多了,请不要喷我,暂且就叫方法吧,介绍如上vector的基本操作(1)~(4)) ( 2 )用邻接表存储图 使用vector实现邻接表可以有效避免指针,而且更容易把握。 哈哈哈,终于结束啦(喝口水)。好了,说了这么多,当然废话也不少~~来几道题目吧!PAT A1039. Course List for Student (25) PAT A1047. Student List for Course (25) 参考:C++ STL之vector用法总结《算法笔记》(胡凡,曽磊)

优秀的个人博客,低调大师

算法学习之路|用C++刷算法会用到的STL(二)——set

二、set 1.set的自我介绍 <li>set意思是集合,从初中就接触到了集合的概念,真是的好东西。set是一个内部自动有序且不含重复元素的容器。</li> <li>set是一种关联式容器,是用来存储同一种数据类型的数据类型,有点绕口,就是sety也就是集合里里面要不然全部装int型的要不然全部装double型的要不然....就是这个意思。并且能从这个同一种数据类型构成的集合中取出元素,而且set中的每个元素都是唯一的,不能重复,好像是数学里集合概念中的唯一性(哈哈哈,强大的数学功底)。更令人欣慰的是,能根据元素的值进行自动排序。</li> <li>一个集合(set)是一个容器,它其中所包含的元素的值是唯一的。这在收集一个数据的具体值的时候是有用的。集 合中的元素按一定的顺序排列,并被作为集合中的实例。如果你需要一个键/值对(pair)来存储数据,map是一个更好的选择。一个集合通过一个链表来组 织,在插入操作和删除操作上比向量(vector)快,但查找或添加末尾的元素时会有些慢。(原因后文简单说说)</li> <li>要注意的是,set中书元素的值不能被直接改变。C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树,即一种自平衡二叉树(以后会讲到啥叫平衡二叉树~~):红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。</li> 2.set的定义 <li>单独定义一个set:</li> set<typename> setname; <li>其定义和大部分STL的定义都差不多,这里的typename依然一样可以是任何基本类型,比如int,double,char,结构体啊,还有STL的标准容器vector,set,queue啊等等。</li> <li>需要注意的是,比如<em>set&lt;vector&lt;int&gt; &gt; setname;</em>两个'&gt;‘之间一定要加上空格,否则会编译错误,原因是会误以为位移运算(详见上篇)。</li> <li>特别的,set数组:</li> set<typename> Arrayname[arraySize]; 比如,set<int>a[100];定义了一个set型的数组,数组中每一个数都是一个集合,每一个集合里都是int型的值。 3.set容器内元素的访问形式 <li>只有一种!</li> hhh,选择 困难症的同学是不是很开森呢? 只能通过迭代器访问(啥叫迭代器?详见上篇): set<typename>::iterator it;(这个也不多说了,和vector是一模一样滴) 比如,set<int>::iterator it; set<double>::iterator it; 同样的,和vector一样可以通过*it来访问set里的元素啦,忍不住再唠叨一句,迭代器就是指针。 4.set中的基本操作 <li>insert(x): 插入元素,并且自动递增排序噢,而且去重,时间复杂度O(logN),N为set中元素的个数。</li> <li>insert(first,second): 将定位器first到second之间的元素插入到set中,返回值是void</li> <li>find(value): 返回set中对应值为value的迭代器,时间复杂度未O(logN)!!后文会重点讲(见下文5.set的注意点和优良特性),有助于加深理解O(logN),举一反三,以后也不过多强调了qwq。</li> <li>begin(): 返回set容器的第一个元素//桥黑板!!begin() 和 end()函数是不检查set是否为空的,使用前最好使用empty()检验一下set是否为空</li> <li>end(): 返回set容器的最后一个元素</li> <li>clear(): 删除set容器中的所有的元素//时间复杂度O(N)</li> <li>empty(): 判断set容器是否为空</li> <li>max_size(): 返回set容器可能包含的元素最大个数</li> <li>size() : 返回当前set容器中的元素个数//时间复杂度O(1),贼快!</li> <li>rbegin: 返回的值和end()相同</li> <li>rend(): 返回的值和rbegin()相同</li> <li>count(): 顾名思义嘛,用来查找set中某个某个键值出现的次数。但是,这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。(小技巧)</li> <li>erase(iterator): 删除迭代器iterator指向的值//时间复杂度O(1),贼快!注意和erase(value)不同噢</li> <li>erase(first,second): 删除定位器first和second之间的值(美国人的思维是左闭右开,最后一次强调)</li> <li>erase(value): 删除值为value的元素,时间复杂度O(logN)//桥黑板!!set中的删除操作是不进行任何的错误检查的,比如定位器的是否合法等等,所以用的时候自己一定要注意。</li> <li>lower_bound(key_value): 返回第一个大于等于key_value的定位器</li> <li>upper_bound(key_value): 返回最后一个大于等于key_value的定位器//二分啦!</li> 5.set的注意点和优良特性 (加深对set的理解,初学者可以先跳过此部分) <li>不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素</li> <li>不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取,而且从迭代器角度来看,元素值是常数</li> <li>元素比较动作只能用于型别相同的容器(即元素和排序准则必须相同) 因为set中重写比较函数的用的真还不多,所以就不细细的讲了,等降到后面的priority_queue的时候,我会重新讲一下结构体的比较函数(其实也叫优先级设置)。 从原型可以看出,可以看出比较函数对象及内存分配器采用的是默认参数,因此如果未指定,它们将采用系统默认方式,另外,利用原型,可以有效地辅助分析创建对象的几种方式。 之前提到了set(map也一样哈)的插入删除效率比用其他序列容器高,简单的讲set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。需要插入或删除,只要改变指针指向的节点就可以啦。(其实本质上还是因为set自带的红黑树的内部结构,就是外挂啊。气哭!STL容器各个都是身怀绝技) set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。 6.set的常见用途 set最主要的作用是自动去重,并在没有写比较函数的情况下,默认按升序排序,因此碰到需要去重但是却不方便直接开数组的情况,可以尝试用set来解决噢。 set/multiset会根据待定的排序准则,自动将元素排序。两者不同在于前者不允许元素重复,而后者允许。 7.练习题,桥黑板!! PAT A1063. Set Similarity (25) 参考:C++中关于set的自定义排序函数的书写,STL中set容器的一点总结 《算法笔记》(胡凡,曽磊)

优秀的个人博客,低调大师

学习了《python网络爬虫实战》第一个爬虫,爬取新浪新闻

请安装anaconda,其中附带的spyder方便运行完查看变量 1.进入cmd控制台, 输入 pip install BeautifulSoup4 pip install requests 2.编写代码,代码已经很清晰了,直接运行不会报错并有成功的结果 def getNewsDetail(newsUrl): import requests from bs4 import BeautifulSoup from datetime import datetime newsWeb = requests.get(newsUrl) newsWeb.encoding = 'utf-8' soup = BeautifulSoup(newsWeb.text,'lxml') result = {} result['title'] = soup.select('.main-title')[0].text result['newsSource'] = soup.select('.source')[0].text timeSource = soup.select('.date')[0].text result['datetime'] = datetime.strptime(timeSource,'%Y年%m月%d日 %H:%M') result['article'] = soup.select('.article')[0].text result['editor'] = soup.select('.show_author')[0].text.strip('责任编辑:') result['comment'] = soup.select('.num')[0].text return result def parseListLinks(url): import requests import json newsDetails = [] request = requests.get(url) jsonLoad = json.loads(request.text.lstrip(' newsloadercallback(').rstrip(');')) newsUrls = [] for item in jsonLoad['result']['data']: newsUrls.append(item['url']) for url in newsUrls: newsDetails.append(getNewsDetail(url)) return newsDetails if __name__ == '__main__': #获取单个新闻页面的信息 newsUrl = 'http://news.sina.com.cn/s/wh/2018-01-08/doc-ifyqkarr7830426.shtml' newsDetail = getNewsDetail(newsUrl) #获取整个列表各个新闻页面的信息 rollUrl='http://api.roll.news.sina.com.cn/zt_list?channel=news&cat_1=gnxw\ &cat_2==gdxw1||=gatxw||=zs-pl||=mtjj&level==1||=2&show_ext=1&show_all=1&\ show_num=22&tag=1&format=json&page=23&callback=newsloadercallback&_=1515911333929' newsDetails = parseListLinks(rollUrl)

优秀的个人博客,低调大师

【案例学习】美国大都会人寿保险公司的 Docker EE 实践

写在前面 MetLife(美国大都会人寿保险公司)是一家拥有150年历史的公司,它是领先的保险及其它金融服务的提供商,为遍布全美的数以百万计的个人和企业客户提供服务,包括美国财富五百强中排名前100位的88家公司。作为一家全球性公司,MetLife 向世界各地提供金融、保险服务——其中有一些是终身服务。有着如此庞大的业务规模,MetLife 需要多种组合的IT基础设施来维持它的日常运作。 降低现有的技术运维成本 今年4月,来自 MetLife 的亚伦·艾代斯(Aaron Aedes)谈到了他们第一次涉足 Docker 容器的经历——即使用一款通过Azure 交付的名为 GSSP 的新应用程序。六个月后,MetLife 来到 DockerCon 欧洲大会的舞台并分享他们使用 Docker 容器的经验——从最初的部署到促使他们主动寻找在 M

优秀的个人博客,低调大师

Hadoop MapReduce概念学习系列之十分钟看透MapReduce(十一)

我们已经知道了Hadoop的三大核心模块:HDFS、MapReduce、Yarn。 MapReduce是什么? MapReduce是一种编程模型,用于大规模数据集的并行计算,其主要思想就是Map(映射)和Reduce(化简)。 MapReduce的创意和灵感来源于函数式编程,在函数式编程中,map对列表的每个元素执行操作或函数。例如:列表[1,2,3,4]上执行 multiple-by-two 函数会产生另一个列表[2,4,6,8],执行时,原列表不被改变。函数式编程认为,应当保持数据不可变,避免在多个进程或线程间共享数据。这意味着,这个函数虽然简单,但可以通过两个或更多线程在同一列表上同时执行,线程间互不影响,因为列表本身未被改变。 MapReduce是用来进行海量数据的并行计算的,需要将工作分配到大量的机器上去做,如果组件间可共享数据,那么数据节点间的数据同步会使系统变得低效且不可靠。实际上,MapReduce上的数据元素是不可变的,即便改变也不会反馈到输入文件,节点间通信只在新的键值对输出时发生,Hadoop会把输出键值对传到下一个阶段。 从概念上讲,MapReduce程序将输入数据列表转变成输出数据列表。一个MapReduce程序会执行两次数据转换操作,一次map,一次reduce。还是举个例子吧: ***********************数据来源****************************** 1 wolys@21cn.com 2 zss1984@126.com 3 294522652@qq.com 4 simulateboy@163.com 5 zhoushigang_123@163.com 6 sirenxing424@126.com 7 lixinyu23@qq.com 8 chenlei1201@gmail.com 9 370433835@qq.com 10 cxx0409@126.com 11 viv093@sina.com 12 q62148830@163.com 13 65993266@qq.com 14 summeredison@sohu.com 15 zhangbao-autumn@163.com 16 diduo_007@yahoo.com.cn 17 fxh852@163.com 18 weiyang1128@163.com 19 licaijun007@163.com 20 junhongshouji@126.com 21 wuxiaohong11111@163.com 22 fennal@sina.com 23 li_dao888@163.com 24 bokil.xu@163.com 25 362212053@qq.com 26 youloveyingying@yahoo.cn 27 boiny@126.com 28 linlixian200606@126.com 29 alex126126@126.com 30 654468252@qq.com 31 huangdaqiao@yahoo.com.cn 32 kitty12502@163.com 33 xl200811@sohu.com 34 ysjd8@163.com 35 851627938@qq.com 36 wubo_1225@163.com 37 kangtezc@163.com 38 xiao2018@126.com 39 121641873@qq.com 40 296489419@qq.com 41 beibeilong012@126.com 第一步:map。读取输入文件内容,解析成key、value对。对输入文件的每一行,解析成key、value对。通过‘@’对value解析出邮箱域。即邮箱账号的@符号后面部分 <21cn.com 1> <126.com 1> <qq.com 1> <163.com 1> <163.com 1> <126.com 1> <qq.com 1> <gmail.com 1> .......... 第二步:combine。对相同的邮箱域合并。 <163.com 1 1 1 1 1 1 1 1 1 1 1 1 1 1> <126.com 1 1 1 1 1 1 1 1 1> <qq.com 1 1 1 1 1 1 1 1 1> <sina.com 1 1> <sohu.com 1 1> <yahoo.com.cn 1 1> <21cn.com 1> <gmail.com 1> <yahoo.cn 1> 第三步:reduce。对相同的邮箱域统计求和。 <163.com 14> <126.com 9> <qq.com 9> <sina.com 2> <sohu.com 2> <yahoo.com.cn 2> <21cn.com 1> <gmail.com 1> <yahoo.cn 1> 好了,我们想要的结果出来了。MapReduce的思想从根源上讲也就是如此,是不是很简单呀? MapReduce的基本流程 MapReduce计算模型由两个阶段组成:Map和Reduce,用户只需要实现map()和reduce()两个函数,即可实现分布式计算,非常简单。 图1 统计图形样式个数的map和reduce过程示意图 map()和reduce()这两个函数的形参是key、value对,表示函数的输入信息。 1. map任务处理 1.1 读取输入文件内容,解析成key、value对。对输入文件的每一行,解析成key、value对。每一个键值对调用一次map函数。 1.2 写自己的逻辑,对输入的key、value处理,转换成新的key、value输出。 1.3 对输出的key、value进行分区。 1.4 对不同分区的数据,按照key进行排序、分组。相同key的value放到一个集合中。 1.5 (可选)分组后的数据进行归约。 2.reduce任务处理 2.1 对多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点。 2.2 对多个map任务的输出进行合并、排序。写reduce函数自己的逻辑,对输入的key、value处理,转换成新的key、value输出。 2.3 把reduce的输出保存到文件中。 图2 word count的map和reduce过程示意图 MapReduce的基本设计思想 上面说了这么多,其实MapReduce的设计思想可以归结为如下三个: (1)对付大数据并行处理:分而治之 (2)上升到抽象模型:Map与Reduce (3)上升到构架:以统一构架为程序员隐藏系统层细节 *******************扩展********************* 同学:博主,怎么给萌妹子解释MapReduce呢?小讲:那就先来看看印度Java程序员Shekhar Gulati怎样向妻子解释MapReduce的吧(来源:CSDN) 我:你是如何准备洋葱辣椒酱的? 妻子: 我会取一个洋葱,把它切碎,然后拌入盐和水,最后放进混合研磨机里研磨。这样就能得到洋葱辣椒酱了。但这和MapReduce有什么关系? 我: 你等一下。让我来编一个完整的情节,这样你肯定可以在15分钟内弄懂MapReduce. 妻子: 好吧。 我:现在,假设你想用薄荷、洋葱、番茄、辣椒、大蒜弄一瓶混合辣椒酱。你会怎么做呢? 妻子: 我会取薄荷叶一撮,洋葱一个,番茄一个,辣椒一根,大蒜一根,切碎后加入适量的盐和水,再放入混合研磨机里研磨,这样你就可以得到一瓶混合辣椒酱了。 我:没错,让我们把MapReduce的概念应用到食谱上。Map和Reduce其实是两种操作,我来给你详细讲解下。Map(映射):把洋葱、番茄、辣椒和大蒜切碎,是各自作用在这些物体上的一个Map操作。所以你给Map一个洋葱,Map就会把洋葱切碎。 同样的,你把辣椒,大蒜和番茄一一地拿给Map,你也会得到各种碎块。 所以,当你在切像洋葱这样的蔬菜时,你执行就是一个Map操作。 Map操作适用于每一种蔬菜,它会相应地生产出一种或多种碎块,在我们的例子中生产的是蔬菜块。在Map操作中可能会出现有个洋葱坏掉了的情况,你只要把坏洋葱丢了就行了。所以,如果出现坏洋葱了,Map操作就会过滤掉坏洋葱而不会生产出任何的坏洋葱块。Reduce(化简):在这一阶段,你将各种蔬菜碎都放入研磨机里进行研磨,你就可以得到一瓶辣椒酱了。这意味要制成一瓶辣椒酱,你得研磨所有的原料。因此,研磨机通常将map操作的蔬菜碎聚集在了一起。 妻子: 所以,这就是MapReduce? 我: 你可以说是,也可以说不是。 其实这只是MapReduce的一部分,MapReduce的强大在于分布式计算。 妻子: 分布式计算? 那是什么?请给我解释下吧。 我: 没问题。 假设你参加了一个辣椒酱比赛并且你的食谱赢得了最佳辣椒酱奖。得奖之后,辣椒酱食谱大受欢迎,于是你想要开始出售自制品牌的辣椒酱。假设你每天需要生产10000瓶辣椒酱,你会怎么办呢? 妻子: 我会找一个能为我大量提供原料的供应商。 我:是的……就是那样的。那你能否独自完成制作呢?也就是说,独自将原料都切碎? 仅仅一部研磨机又是否能满足需要?而且现在,我们还需要供应不同种类的辣椒酱,像洋葱辣椒酱、青椒辣椒酱、番茄辣椒酱等等。 妻子: 当然不能了,我会雇佣更多的工人来切蔬菜。我还需要更多的研磨机,这样我就可以更快地生产辣椒酱了。 我:没错,所以现在你就不得不分配工作了,你将需要几个人一起切蔬菜。每个人都要处理满满一袋的蔬菜,而每一个人都相当于在执行一个简单的Map操作。每一个人都将不断的从袋子里拿出蔬菜来,并且每次只对一种蔬菜进行处理,也就是将它们切碎,直到袋子空了为止。 这样,当所有的工人都切完以后,工作台(每个人工作的地方)上就有了洋葱块、番茄块、和蒜蓉等等。 妻子:但是我怎么会制造出不同种类的番茄酱呢? 我:现在你会看到MapReduce遗漏的阶段---搅拌阶段。MapReduce将所有输出的蔬菜碎都搅拌在了一起,这些蔬菜碎都是在以key为基础的 map操作下产生的。搅拌将自动完成,你可以假设key是一种原料的名字,就像洋葱一样。 所以全部的洋葱keys都会搅拌在一起,并转移到研磨洋葱的研磨器里。这样,你就能得到洋葱辣椒酱了。同样地,所有的番茄也会被转移到标记着番茄的研磨器里,并制造出番茄辣椒酱。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5077646.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

[Android学习笔记四] 自定义Android组件之组合方式创建密码框组件

自定义Android组件基本可以从2个入口着手,一是继承Viewe类拿起画笔和画布绘制组件,而是通过继承View的子类和组合已有的组件的方式构造自定义的组件。 本文通过自定义一个PassWordView组件来实现密码能够通过点击点选框来决定是否显示。PassWordView组件类通过继承LinearLayout类和组合EditText,CheckBox组件实现。 效果如下图: 一: 实现上述密码框组件需要以下步骤: a. 设计PassWordView组件 b. 自定义样式属性,res/value/attrs.xml c. 创建PassWordView c. 实现PassWordView的功能,如:事件,属性设置,组合组件 二: 使用密码框组件: a. 使用PassWordView组件,设置属性 b. 在Activity中对其进行操作 三: 案例: 1. 密码框组件主要是组合EditText和CheckBox组件,通过CheckBox的选中状态来决定密码是否显示为明文,EditText和CheckBox组件要求并列一行。故采用LinearLayout布局。 2. 密码框组件的自定义样式属性,通常根据具体需要来定义。 PassWordView自定义组件中称EditText为left Component(左组件),CheckBox为right Component(右组件)。 定义样式属性(位置文件:res/value/attrs.xml): 1 2 3 4 5 6 7 8 9 10 < declare-styleable name = "PassWordView" > <!--直接使用系统中已定义的语意明确的属性,不用设置format--> < attr name = "android:inputType" /> <!--自定义属性--> < attr name = "left_component_weight" format = "float" /> < attr name = "right_component_weight" format = "float" /> </ declare-styleable > 其中inputType使用了android系统已经定义的属性,注意书写格式。 3. 实现PassWordView类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 package secondriver.viewlibrary; import android.content.Context; import android.content.res.TypedArray; import android.text.InputType; import android.text.method.HideReturnsTransformationMethod; import android.text.method.PasswordTransformationMethod; import android.util.AttributeSet; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.LinearLayout; /** *PassWordView *<p/> *leftComponent是一个EditText *RightComponent是一个CheckBox *<p/> *Author:secondriver *Created:2015/11/25 */ public class PassWordView extends LinearLayout{ private EditTextmPassWordEditText; private CheckBoxmShowCheckBox; private LinearLayout.LayoutParamsmPassWordParams; private LinearLayout.LayoutParamsmShowParams; private float leftComponentWeight; private float rightComponentWeight; private int inputType; public PassWordView(Contextcontext,AttributeSetattrs){ super (context,attrs); initProperty(context,attrs); initComponent(context); } private final void initProperty(Contextcontext,AttributeSetattrs){ //获取设置的值,未设置使用默认值 TypedArraytypedArray=context.obtainStyledAttributes(attrs,R.styleable.PassWordView); leftComponentWeight=typedArray.getFloat(R.styleable.PassWordView_left_component_weight, 5 .0f); rightComponentWeight=typedArray.getFloat(R.styleable.PassWordView_right_component_weight, 1 .0f); //来自Android系统已定义的属性 inputType=typedArray.getInt(R.styleable.PassWordView_android_inputType,InputType.TYPE_TEXT_VARIATION_PASSWORD); typedArray.recycle(); } private void initComponent(Contextcontext){ mPassWordEditText= new EditText(context); mPassWordEditText.setInputType(inputType); mPassWordEditText.setTransformationMethod(PasswordTransformationMethod.getInstance()); mShowCheckBox= new CheckBox(context); //通过权重来决定EditText和CheckBox占据父视图的空间的比例 mPassWordParams= new LinearLayout.LayoutParams( 0 ,ViewGroup.LayoutParams.WRAP_CONTENT,leftComponentWeight); mShowParams= new LinearLayout.LayoutParams( 0 ,ViewGroup.LayoutParams.WRAP_CONTENT,rightComponentWeight); //父视图是一个容器视图,指定水平排列子视图 setOrientation(HORIZONTAL); addView(mPassWordEditText,mPassWordParams); addView(mShowCheckBox,mShowParams); addCheckBoxListener(); } /** *获取PassWord * *@return */ public StringgetPassWord(){ return mPassWordEditText.getText().toString(); } /** *获取PassWord组件 * *@return */ public EditTextgetPassWordEditText(){ return mPassWordEditText; } private final void addCheckBoxListener(){ /** *CheckBox点击事件处理 * *如果选中EditText中的密码明文显示 * *如果未选中EditText中的密码黑点显示 * */ mShowCheckBox.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener(){ @Override public void onCheckedChanged(CompoundButtonbuttonView, boolean isChecked){ if (isChecked){ mPassWordEditText.setTransformationMethod(HideReturnsTransformationMethod.getInstance()); } else { mPassWordEditText.setTransformationMethod(PasswordTransformationMethod.getInstance()); } } }); } } 4. 使用PassWordView组件 文件:activity_combine_view.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" xmlns:passwordview = "http://schemas.android.com/apk/res-auto" android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "vertical" > < secondriver.viewlibrary.PassWordView android:id = "@+id/password_view" android:layout_width = "300dp" android:layout_height = "wrap_content" android:layout_margin = "10dp" android:background = "#565354" android:inputType = "textPassword" android:padding = "10dp" passwordview:left_component_weight = "5.0" passwordview:right_component_weight = "1.0" /> < Button android:layout_width = "match_parent" android:layout_height = "wrap_content" android:onClick = "onShowPassWord" android:text = "获取密码" /> < TextView android:id = "@+id/password_text_view" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:hint = "显示password" /> </ LinearLayout > 文件:CombinePassWordViewActivity.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package secondriver.sdk.activity; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.TextView; import secondriver.sdk.R; import secondriver.viewlibrary.PassWordView; /** *Author:secondriver *Created:2015/11/25 */ public class CombinePassWordViewActivity extends Activity{ private PassWordViewmPassWordView; private TextViewmPassWordTextView; @Override protected void onCreate(BundlesavedInstanceState){ super .onCreate(savedInstanceState); setContentView(R.layout.activity_combine_view); mPassWordView=(PassWordView)findViewById(R.id.password_view); mPassWordTextView=(TextView)findViewById(R.id.password_text_view); } public void onShowPassWord(Viewview){ mPassWordTextView.setText(mPassWordView.getPassWord()); } } AndroidManifest.xml中添加CombinePassWordViewActivity即可。 5.结果 如文中一开始展示的效果图 6. 总结 本文主要演示的通过组合的方式实现自定义Android组件,一般情况通过组合已有的的组件来实现复杂组件相对更容易一些,也能够得到组件重用的福利;现有组件不能满足的情况下可以考虑绘制组件,该方式最为原始和灵活。 本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1716830,如需转载请自行联系原作者

优秀的个人博客,低调大师

Hadoop Hive概念学习系列之hive的正则表达式初步(六)

说在前面的话 hive的正则表达式,是非常重要!作为大数据开发人员,用好hive,正则表达式,是必须品! Hive中的正则表达式还是很强大的。数据工作者平时也离不开正则表达式。对此,特意做了个hive正则表达式的小结。所有代码都经过亲测,正常运行。 1.regexp 语法: A REGEXP B 操作类型: strings 描述: 功能与RLIKE相同 select count(*) from olap_b_dw_hotelorder_f where create_date_wid not regexp '\\d{8}' 与下面查询的效果是等效的: select count(*) from olap_b_dw_hotelorder_f where create_date_wid not rlike '\\d{8}'; 2.regexp_extract 语法: regexp_extract(string subject, string pattern, int index) 返回值: string 说明:将字符串subject按照pattern正则表达式的规则拆分,返回index指定的字符。 hive>selectregexp_extract('IloveYou','I(.*?)(You)',1) from test1 limit1; Total jobs =1 ... Total MapReduce CPU Time Spent:7 seconds340 msec OK love Time taken:28.067 seconds, Fetched:1 row(s) hive>selectregexp_extract('IloveYou','I(.*?)(You)',2) from test1 limit1; Total jobs =1 ... OK You Time taken:26.067 seconds, Fetched:1 row(s) hive>select regexp_extract('IloveYou','(I)(.*?)(You)',1) from test1 limit1; Total jobs =1 ... OK I Time taken:26.057 seconds, Fetched:1 row(s) hive>select regexp_extract('IloveYou','(I)(.*?)(You)',0) from test1 limit1; Total jobs =1 ... OK IloveYou Time taken:28.06 seconds, Fetched:1 row(s) hive>select regexp_replace("IloveYou","You","") from test1 limit1; Total jobs =1 ... OK Ilove Time taken:26.063 seconds, Fetched:1 row(s) 3.regexp_replace 语法: regexp_replace(string A, string B, string C) 返回值: string 说明:将字符串A中的符合Java正则表达式B的部分替换为C。注意,在有些情况下要使用转义字符,类似Oracle中的regexp_replace函数。 hive> selectregexp_replace("IloveYou","You","") from test1 limit1; Total jobs =1 ... OK Ilove Time taken:26.063 seconds, Fetched:1 row(s) hive>selectregexp_replace("IloveYou","You","lili") from test1 limit1; Total jobs =1 ... OK Ilovelili Hive里的正则表达式 如,https://cwiki.apache.org/confluence/display/Hive/GettingStarted 输入regex可查到 CREATE TABLE apachelog ( host STRING, identity STRING, user STRING, time STRING, request STRING, status STRING, size STRING, referer STRING, agent STRING) ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' WITH SERDEPROPERTIES ("input.regex" = "([^ ]*) ([^ ]*) ([^]*) \[()\] ([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\".*\") ([^ \"]*|\".*\"))?" ) STORED AS TEXTFILE; 下面就是hive里的正则表达式,9个字段,对应定义那边也要9个 "input.regex" = "([^ ]*) ([^ ]*) ([^.]*) \[(.*)\] "(.*)" (-|[0-9]*) (-|[(0-9]*) "(.*)" "(.*)"" ([^ ]*) ([^ ]*) ([^.]*) \[(.*)\] "(.*)" (-|[0-9]*) (-|[(0-9]*) "(.*)" "(.*)" ([^ ]*) ([^ ]*) ([^.]*) \\[(.*)\\] "(.*)" (-|[0-9]*) (-|[(0-9]*) \"(.*)\" \"(.*)\" 数据来源, yarn-root-nodemanager-master.log 或 yarn-spark-nodemanager-master.log yarn-hadoop-nodemanager-master.log 这里,有个正则表达式的好工具! RegexBuddy.exe 很好用的这款软件!双击它即可。 如上图所示颜色,代表我们测试的正则表达式,是正确的! 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/6102789.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Hadoop Hive概念学习系列之内部表和外部表对比分析(二)

Hive 的数据表分为两种,内部表和外部表。 内部表:这种表可以理解为数据和表结构都保存在一起的数据表。 外部表:在表结构创建以前,数据已经保存在 HDFS 中,通过创建表结构,将数据格式化到表的结果里。 进一步分析,内部表而言,当通过 DROP TABLE table_name 删除元数据中表结构的同时,表中的数据也同样会从 HDFS 中被删除。 外部表而言,当进行 DROP TABLE table_name 操作的时候,Hive 仅仅删除元数据的表结构,而不删除 HDFS 上的文件(即表里的数据),所以,相比内部表,外部表可以更放心大胆地使用。 数据表在删除的时候,内部表会连数据一起删除,而外部表只删除表结构,数据还是保留的。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5660245.html,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册