C++—lambda表达式+优先队列 prority_queue+关键字decltype
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
/*
struct ListNode{
int val;
ListNode *next;
ListNode(int x) : val(x),next(NULL) {}
};
*/
class Solution { //优先队列解题
public:
ListNode *mergeKLists(vector<ListNode*>& lists) {
ListNode dummy();
ListNode *tail = &dummy;
auto comp=[](ListNode *a, ListNode *b) {return a->vl > b->val;};
priority_queue<ListNode*, vector<ListNode*>, decltype(comp)> q(comp);
for(ListNode* list : lists)
if(list)q.push(list);
while(!q.empty())
{
tail->next = q.top();
q.pop();
tail = tail->next;
if(tail->next)
q.push(tail->next);
}
return dummy.next;
}
};
优先队列 — priority_queue
一、相关定义
优先队列容器与队列一样,只能从队尾插入元素,从队首删除元素。但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。这点类似于给队列里的元素进行了由大到小的顺序排序。元素的比较规则默认按元素值由大到小排序,可以重载“<”操作符来重新定义比较规则。
优先级队列可以用向量(vector)或双向队列(deque)来实现(注意list container不能用来实现queue,因为list的迭代器不是任意存取iterator,而pop中用到堆排序时是要求random access iterator 的!):
priority_queue<vector<int>, less<int> > pq1; // 使用递增 less<int> 函数对象排序
priority_queue<deque<int>, greater<int> > pq2; // 使用递减 greater<int> 函数对象排序
其成员函数有“判空(empty)” 、“尺寸(Size)” 、“栈顶元素(top)” 、“压栈(push)” 、“弹栈(pop)”等。
二、基本操作
empty() 如果队列为空,则返回真
pop() 删除对顶元素,删除第一个元素
push() 加入一个元素
size() 返回优先队列中拥有的元素个数
top() 返回优先队列对顶元素,返回优先队列中有最高优先级的元素
在默认的优先队列中,优先级高的先出队。在默认的int型中先出队的为较大的数。
头文件: #include <queue>
声明方式:
1、普通方法
priority_queue<int> q; //通过操作,按照元素从大到小的顺序出队priority_queue<int,vector<int>, greater<int> > q; //通过操作,按照元素从小到大的顺序出队
2、自定义优先级
struct cmp {operator bool ()(int x, int y){return x > y; // x小的优先级高 //也可以写成其他方式,如: return p[x] > p[y];表示p[i]小的优先级高}};priority_queue<int, vector<int>, cmp> q; //定义方法//其中,第二个参数为容器类型。第三个参数为比较函数。
3、结构体声明方式
struct node {int x, y;friend bool operator < (node a, node b){return a.x > b.x; //结构体中,x小的优先级高}};priority_queue<node>q; //定义方法//在该结构中,y为值, x为优先级。//通过自定义operator<操作符来比较元素中的优先级。//在重载”<”时,最好不要重载”>”,可能会发生编译错误
三、代码实现
优先队列,其构造及具体实现我们可以先不用深究,我们现在只需要了解其特性,及在做题中的用法。
以一个例子来解释吧(呃,写完才发现,这个代码包函了几乎所有我们要用到的用法,仔细看看吧):
/*优先队列的基本使用*/
#include<stdio.h>
#include<functional>
#include<queue>
#include<vector>
using namespace std;
//定义结构,使用运算符重载,自定义优先级1
struct cmp1{
bool operator ()(int &a,int &b){
return a>b;//最小值优先
}
};
struct cmp2{
bool operator ()(int &a,int &b){
return a<b;//最大值优先
}
};
//定义结构,使用运算符重载,自定义优先级2
struct number1{
int x;
bool operator < (const number1 &a) const {
return x>a.x;//最小值优先
}
};
struct number2{
int x;
bool operator < (const number2 &a) const {
return x<a.x;//最大值优先
}
};
int a[]={,,,,,,,,,,,};
number1 num1[]={,,,,,,,,,,,};
number2 num2[]={,,,,,,,,,,,}; int main()
{ priority_queue<int>que;//采用默认优先级构造队列 priority_queue<int,vector<int>,cmp1>que1;//最小值优先
priority_queue<int,vector<int>,cmp2>que2;//最大值优先 priority_queue<int,vector<int>,greater<int> >que3;//注意“>>”会被认为错误,
//这是右移运算符,所以这里用空格号隔开
priority_queue<int,vector<int>,less<int> >que4;////最大值优先 priority_queue<number1>que5;
priority_queue<number2>que6; int i;
for(i=;a[i];i++){
que.push(a[i]);
que1.push(a[i]);
que2.push(a[i]);
que3.push(a[i]);
que4.push(a[i]);
}
for(i=;num1[i].x;i++)
que5.push(num1[i]);
for(i=;num2[i].x;i++)
que6.push(num2[i]); printf("采用默认优先关系:\n(priority_queue<int>que;)\n");
printf("Queue 0:\n");
while(!que.empty()){
printf("%3d",que.top());
que.pop();
}
puts("");
puts(""); printf("采用结构体自定义优先级方式一:\n(priority_queue<int,vector<int>,cmp>que;)\n");
printf("Queue 1:\n");
while(!que1.empty()){
printf("%3d",que1.top());
que1.pop();
}
puts("");
printf("Queue 2:\n");
while(!que2.empty()){
printf("%3d",que2.top());
que2.pop();
}
puts("");
puts("");
printf("采用头文件\"functional\"内定义优先级:\n(priority_queue<int,vector<int>,greater<int>/less<int> >que;)\n");
printf("Queue 3:\n");
while(!que3.empty()){
printf("%3d",que3.top());
que3.pop();
}
puts("");
printf("Queue 4:\n");
while(!que4.empty()){
printf("%3d",que4.top());
que4.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式二:\n(priority_queue<number>que)\n");
printf("Queue 5:\n");
while(!que5.empty()){
printf("%3d",que5.top());
que5.pop();
}
puts("");
printf("Queue 6:\n");
while(!que6.empty()){
printf("%3d",que6.top());
que6.pop();
}
puts("");
return ;
}
/*
运行结果 :
采用默认优先关系:
(priority_queue<int>que;)
Queue 0:
83 72 56 47 36 22 14 10 7 3 采用结构体自定义优先级方式一:
(priority_queue<int,vector<int>,cmp>que;)
Queue 1:
7 10 14 22 36 47 56 72 83 91
Queue 2:
83 72 56 47 36 22 14 10 7 3 采用头文件"functional"内定义优先级:
(priority_queue<int,vector<int>,greater<int>/less<int> >que;)
Queue 3:
7 10 14 22 36 47 56 72 83 91
Queue 4:
83 72 56 47 36 22 14 10 7 3 采用结构体自定义优先级方式二:
(priority_queue<number>que)
Queue 5:
7 10 14 22 36 47 56 72 83 91
Queue 6:
83 72 56 47 36 22 14 10 7 3
*/
lambda表达式(C++11)
使用场景
1. lambda表达式又叫匿名函数(可以理解为一个未命名的内联函数),那么肯定就跟函数挂上关系了,通常情况写你在编程的时候需要将这段代码封装到一个函数里面再来调用,那这个时候就避免不了取函数名了,那么这个时候你就要想起我们的lambda表达式了,它可以很好的帮你解决函数命名困难这个问题。
2. 在你的整个项目编程中,你独立出来一个函数,但这个函数实现相对简单并且可能在整个项目只使用了一次(即不存在复用的情况),那么这个时候我们就可以考虑使用下lambda表达式了,这样可以让代码更加紧凑,更加容易维护。
简单应用
先看看lambda表达式变量截取的方式:
[] 不截取任何变量
[&] 截取外部作用域中所有变量,并作为引用在函数体中使用
[=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
[=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
[bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
[this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
场景一
比较两个数的大小,第一个数比第二个数大的时候返回true,反之返回false。
// 1 传统解法
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool compare(int& a, int& b)
{
return a > b;
}
int main(void)
{
int data[] = { , , , , , };
vector<int> testdata;
testdata.insert(testdata.begin(), data, data + );
// 排序算法
sort(testdata.begin(), testdata.end(), compare); // 升序
return ;
}
//2 lambda表达式的解法:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std; int main(void)
{
int data[] = { , , , , , };
vector<int> testdata;
testdata.insert(testdata.begin(), data, data + );
sort(testdata.begin(), testdata.end(), [](int a, int b){ return a > b; });
return ;
}
场景二
使用auto来接收一个lambda表达式,当然我们也可以直接使用C++11里面的新特性function来接收lambda表达式,两者等价的,因为auto是自动类型转换,所以在某些场合使用起来更方便。
#include <iostream>
#include <functional>
using namespace std;
int main(void)
{
int x = , y = ;
auto add = [](int a, int b) { return a + b; };
std::function<int(int, int)> Add = [=](int a, int b) { return a + b; };
cout << "add: " << add(x, y) << endl;
cout << "Add: " << Add(x, y) << endl;
return ;
}
//最终的运行结果都是:17
//解析: function中的第一个int是返回值类型,括号里面的两个int都是函数的参数类型.
场景三
使用lambda表达式来实现递归算法
递归题目:已知f(1)=1,f(2)=2,那么请实现f(n)=f(n-1)+f(n-2),此处的n>2
#include <iostream>
#include <functional>
using namespace std;
int main()
{
std::function<int(int)> recursion = [&recursion](int n) { return n < 2 ? 1 : recursion(n - 1) + recursion(n - 2); };
cout << "recursion(2):" << recursion() << endl;
cout << "recursion(3):" << recursion() << endl;
cout << "recursion(4):" << recursion() << endl;
return ;
}
//运行结果:
//recursion(2):2
//recursion(3):3
//recursion(4):5
链接:https://blog.csdn.net/qq_34199383/article/details/80469780
decltype关键字(C++11)
一、decltype意义
有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了)。为了满足这一需求,C++11新标准引入了decltype类型说明符,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
二、decltype用法
1.基本用法
int getSize();
int main(void)
{
int tempA = 2; /*1.dclTempA为int*/
decltype(tempA) dclTempA;
/*2.dclTempB为int,对于getSize根本没有定义,但是程序依旧正常,因为decltype只做分析,并不调用getSize,*/
decltype(getSize()) dclTempB; return 0;
}
2.与const结合
double tempA = 3.0;
const double ctempA = 5.0;
const double ctempB = 6.0;
const double *const cptrTempA = &ctempA;
/*1.dclTempA推断为const double(保留顶层const,此处与auto不同)*/
decltype(ctempA) dclTempA = 4.1;
/*2.dclTempA为const double,不能对其赋值,编译不过*/
dclTempA = 5;
/*3.dclTempB推断为const double * const*/
decltype(cptrTempA) dclTempB = &ctempA;
/*4.输出为4(32位计算机)和5*/
cout<<sizeof(dclTempB)<<" "<<*dclTempB<<endl;
/*5.保留顶层const,不能修改指针指向的对象,编译不过*/
dclTempB = &ctempB;
/*6.保留底层const,不能修改指针指向的对象的值,编译不过*/
*dclTempB = 7.0;
3.与引用结合
int tempA = 0, &refTempA = tempA; /*1.dclTempA为引用,绑定到tempA*/
decltype(refTempA) dclTempA = tempA;
/*2.dclTempB为引用,必须绑定到变量,编译不过*/
decltype(refTempA) dclTempB = 0;
/*3.dclTempC为引用,必须初始化,编译不过*/
decltype(refTempA) dclTempC;
/*4.双层括号表示引用,dclTempD为引用,绑定到tempA*/
decltype((tempA)) dclTempD = tempA; const int ctempA = 1, &crefTempA = ctempA; /*5.dclTempE为常量引用,可以绑定到普通变量tempA*/
decltype(crefTempA) dclTempE = tempA;
/*6.dclTempF为常量引用,可以绑定到常量ctempA*/
decltype(crefTempA) dclTempF = ctempA;
/*7.dclTempG为常量引用,绑定到一个临时变量*/
decltype(crefTempA) dclTempG = 0;
/*8.dclTempH为常量引用,必须初始化,编译不过*/
decltype(crefTempA) dclTempH;
/*9.双层括号表示引用,dclTempI为常量引用,可以绑定到普通变量tempA*/
decltype((ctempA)) dclTempI = ctempA;
4.与指针结合
int tempA = 2;
int *ptrTempA = &tempA;
/*1.常规使用dclTempA为一个int *的指针*/
decltype(ptrTempA) dclTempA;
/*2.需要特别注意,表达式内容为解引用操作,dclTempB为一个引用,引用必须初始化,故编译不过*/
decltype(*ptrTempA) dclTempB;
三、decltype总结
decltype和auto都可以用来推断类型,但是二者有几处明显的差异:
1.auto忽略顶层const,decltype保留顶层const;
2.对引用操作,auto推断出原有类型,decltype推断出引用;
3.对解引用操作,auto推断出原有类型,decltype推断出引用;
4.auto推断时会实际执行,decltype不会执行,只做分析。
总之在使用中过程中和const、引用和指针结合时需要特别小心。
C++—lambda表达式+优先队列 prority_queue+关键字decltype的更多相关文章
- C++ 11 Lambda表达式、auto、function、bind、final、override
接触了cocos2dx 3.0,就必须得看C++ 11了.有分享过帖子:[转帖]漫话C++0x(四) —- function, bind和lambda.其实最后的Lambda没太怎么看懂. 看不懂没关 ...
- Java 8特性探究(1):通往lambda之路与 lambda表达式10个示例
本文由 ImportNew 函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是只包含一个方法的接口.比如Java标准库中的ja ...
- Java 8 Lambda表达式10个示例【存】
PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是 ...
- 【Java学习笔记之三十一】详解Java8 lambda表达式
Java 8 发布日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Java 8之前 ...
- Java8新特性-Lambda表达式是什么?
目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...
- jdk8 lambda表达式总结
Java8 lambda表达式10个示例 1. 实现Runnable线程案例 使用() -> {} 替代匿名类: //Before Java 8: new Thread(new Runnab ...
- Java 8 lambda表达式示例
例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runna ...
- java8 快速入门 lambda表达式 Java8 lambda表达式10个示例
本文由 ImportNew - lemeilleur 翻译自 javarevisited.欢迎加入翻译小组.转载请见文末要求. Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发 ...
- Java8 lambda表达式10个示例
Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Ja ...
随机推荐
- 错误解决Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: pers.zhb.domain.Student column: classno (should be mapped with insert="false" update="false")
1.在学习hibernate的一对多多对一关系的时候,出现了一下错误: 2.错误原因: 这是因为在配置student.hbm.xml的配置文件的时候出现了将两个属性映射到同一个字段: <?xml ...
- [RN] React Native 实现 类似京东 的 沉浸式状态栏和搜索栏
React Native 实现 类似京东 的 沉浸式状态栏和搜索栏 其原理其实就是在要 隐藏 部分的那个View 前面加入 StatusBar 代码! 代码如下: <StatusBar anim ...
- 服务器使用bbr加速配置
服务器内核升级: 以centos7为例,配置之前可使用以下命令查看内核版本,若是4.0以上则无需对内核升级: uname -r 对内核升级的方法: 直接使用以下命令进行内核版本的下载: rpm --i ...
- ES6基础入门之let、const
作者 | Jeskson来源 | 达达前端小酒馆 01 首先呢?欢迎大家来学习ES6入门基础let,const的基础知识内容.初始ECMA Script6. ESMAScript与JavaScript ...
- x64汇编第二讲,复习x86汇编指令格式,学习x64指令格式
目录 x64汇编第二讲,复习x86汇编指令格式,学习x64指令格式 一丶x86指令复习. 1.1什么是x86指令. 1.2 x86与x64下的通用寄存器 1.3 OpCode 1.4 7种寻址方式 二 ...
- ConcurrentHashMap 无锁读
ConcurrentHashMap 可以做到无锁读,而写使用分段锁机制,把整个哈希表切分成段segment(默认为16段),每段有一个锁,最多可以同时有16个写线程.而读不受限制. 下文转自http: ...
- Java编程思想之三 操作符
在底层,Java中的数据是通过使用操作符来操作的. 3.2 使用Java操作符 操作符接收一个或多个参数,并生成一个新值. 操作符作用于操作数,生成一个新值.有些操作符可能会改变操作数自身的值,这被称 ...
- python lambda表达式简单用法【转】
python lambda表达式简单用法 1.lambda是什么? 看个例子: g = lambda x:x+1 看一下执行的结果: g(1) >>>2 g(2) >>& ...
- HIVE-计算累计和
eg:统计1-12月的累积销量,即1月为1月份的值,2月为1.2月份值的和,3月为123月份的和,12月为1-12月份值的和 SELECT month,SUM(amount) month_amou ...
- ip rule实现源IP路由,实现一个主机多IP(或多网段)同时通(外部看是完全两个独立IP)
利用ip rule实现基于源地址区分路由表,实现一个主机多IP网段同时通.(外部的一个主机无论访问哪个网段都可以访问通)实际应用:创建路由表table200ip route add 192.168.1 ...