包含min函数的栈

题目描述

定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。

题解:
使用一个小根堆和一个元素出现次数数组来维护这个栈;
每次push一个元素,该元素出现次数+1,并把该元素压进小根堆
每次pop一个元素,该元素出现次数-1,如果小根堆的栈顶元素出现次数为0,则一直pop,直到栈顶元素出现次数不为0

AC代码:

[shell]
/*
题目描述

定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。

题解:
使用一个小根堆和一个元素出现次数数组来维护这个栈;
每次push一个元素,该元素出现次数+1,并把该元素压进小根堆
每次pop一个元素,该元素出现次数-1,如果小根堆的栈顶元素出现次数为0,则一直pop,直到栈顶元素出现次数不为0
*/
class Solution {
public:

stack<int> s;
map<int, int> m;
static struct cmp
{
bool operator()(const int&a, const int &b)
{
return a>b;
}
};
priority_queue<int, vector<int>, cmp> pq;

void push(int value) {
s.push(value);
pq.push(value);
m[value]++;
}
void pop() {
m[s.top()]–;
s.pop();
while (m[pq.top()] == 0)
pq.pop();
}
int top() {
return s.top();
}
int min() {
return pq.top();
}
};
[/shell]

关于linux系统安装出现Buffer I/O error和end_requestc错误

在安装centOS的时候,出现了大量的错误,如下:

[shell]
Buffer I/O error on device sr0, logical block 512
end_request: critical target error, dev sr0, sector 4096
[/shell]

QQ图片20151201194258

导致无法继续安装。后来在网上找到ubuntu论坛的相关说法:http://ubuntuforums.org/showthread.php?t=999549

其中提到是否是安装盘出现错误,于是我想起了我通过两个usb扩展坞来接USB,用USB来安装,可能导致安装失败。于是我把USB直接插到电脑上,可以正常安装。

里程计是什么东西?

    很多SLAM的论文中涉及到里程计这个概念。下面这段话是从一篇论文中复制过来的,基本符合里程计的解释,刚入门的童鞋们可以看看:
     里程计作为移动机器人相对定位的有效传感器,为机器人提供了实时的位姿信息。移动机器人里程计模型决定于移动机器人结构和运动方式,即移动机器人运动学模型。
    针对双轮差动移动机器人平台,里程计的工作原理是根据安装在左右两个驱动轮电机上的光电编码器来检测车轮在一定时间内转过的弧度,进而推算机器人相对位姿的变化 。

linux下的程序运行时间测量

方法一:

计算整个程序运行的时间。可以使用time命令,譬如我要运行的文件是app,正常情况下是在终端里面输入./app ,我们可以使用time  ./app运行程序,在程序结束后,会看到一些时间参数,其中Real是程序实力占用时间user是程序用时间包括一些输出信息等,sys是系统使用时间,比如库的调用。

 

方法二:

测量程序中部分代码运行时间。

首先包含头文件:

[c language=”++”]
#include <sys/time.h>
[/c]

然后新建时间结构:

[c language=”++”]
struct timeval StartTime;
struct timeval EndTime;
double TimeUse=0;
gettimeofday(&StartTime, NULL);

//要测量的程序代码

gettimeofday(&EndTime, NULL);

TimeUse = 1000000*(EndTime.tv_sec-StartTime.tv_sec)+EndTime.tv_usec-StartTime.tv_usec;
TimeUse/=1000;
cout<<“总花费时间为:”<<TimeUse<<“ms”<<endl;
cout<<“总花费时间为:”<<TimeUse/1000<<“s”<<endl;
cout<<“总花费时间为:”<<(int)(TimeUse/1000)/60<<“分”<<((int)(TimeUse/1000))%60<<“秒”<<endl;
[/c]

解决应用程序无法正常启动(0xc000007b)问题

自从安装了win7或者win864位系统后,配置完成opencv会出现下图的问题:应用程序无法正常启动(0xc000007b)问题。请单击“确定”关闭应用程序。

 

经过多轮尝试,终于解决了这个问题。我们一般创建控制台程序的时候,配置管理器默认给我们配置了win32的活动解决方案平台。

我们新增一个x64平台,如下图,从原来的Win32平台复制设置过去。

然后查看项目属性,把库目录中的opencvx86改为x64即可。(假如环境变量当初使用了x86,也要改为x64),如下图:

 

 

最后编译运行程序,顺利解决问题!

 

 

unix网络编程:检查选项是否受支持并获取默认值

1.需要包含头文件netinet/in.h,IPPROTO_TCP、IPPROTO_IPV6等定义在这个头文件中。

2.exit定义在stdlib.h中。

3.需要定义sock_str_flag、sock_str_int、sock_str_linger和sock_str_timeval。

4.理论上每个sock_opts都应该用ifdef进行判断,但是考虑到centos本身就没有sctp相关选项,所以直接屏蔽。

checkopts.cpp,github网址:https://github.com/siukwan/unix/tree/master/7thChapterSocketOpt
代码如下:

[c language=”++”]
/*
* sock_opts定义应该每一个都有if else的判断
* 实际情况是没有sctp的选项,于是直接屏蔽
*
*/
#include<stdio.h>
#include<iostream>

#include<netinet/tcp.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include <stdarg.h>
#include<syslog.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>

using namespace std;
#define MAXLINE 1024
int daemon_proc;

void err_ret(const char *fmt,…);
void err_quit(const char *fmt,…);
union val{
int i_val;
long l_val;
linger linger_val;
timeval timeval_val;
}sock_val;

static char *sock_str_flag(val *,int);
static char *sock_str_int(val*,int);
static char *sock_str_linger(val* ,int);
static char *sock_str_timeval(val*,int);

struct opts{
const char *opt_str;
int opt_level;
int opt_name;
char *(*opt_val_str)(val *,int);
}sock_opts[]={
{"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, sock_str_flag },
{"SO_DEBUG", SOL_SOCKET, SO_DEBUG, sock_str_flag },
{"SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE, sock_str_flag },
{"SO_ERROR", SOL_SOCKET, SO_ERROR, sock_str_int },
{"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, sock_str_flag },
{"SO_LINGER", SOL_SOCKET, SO_LINGER, sock_str_linger },
{"SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE, sock_str_flag },
{"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, sock_str_int },
{"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, sock_str_int },
{"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, sock_str_int },
{"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, sock_str_int },
{"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, sock_str_timeval },
{"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, sock_str_timeval },
{"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, sock_str_flag },

#ifdef SO_REUSEPORT
{"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, sock_str_flag },
#else
{"SO_REUSEPORT", 0, 0, NULL },
#endif
{"SO_TYPE", SOL_SOCKET, SO_TYPE, sock_str_int },

#ifdef SO_USELOOPBACK
{"SO_USELOOPBACK", SOL_SOCKET, SO_USELOOPBACK, sock_str_flag },
#else
{"SO_USELOOPBACK", 0, 0, NULL },
#endif

#ifdef IP_TOS
{"IP_TOS", IPPROTO_IP, IP_TOS, sock_str_int },
#else
{"IP_TOS", 0, 0, NULL },
#endif

#ifdef IP_TTL
{"IP_TTL", IPPROTO_IP, IP_TTL, sock_str_int },
#else
{"IP_TTL", 0, 0, NULL },
#endif

#ifdef IPV6_DONTFRAG
{"IPV6_DONTFRAG", IPPROTO_IPV6, IPV6_DONTFRAG, sock_str_flag },
#else
{"IPV6_DONTFRAG", 0, 0, NULL },
#endif

{"IPV6_UNICAST_HOPS", IPPROTO_IPV6, IPV6_UNICAST_HOPS, sock_str_int },
{"IPV6_V6ONLY", IPPROTO_IPV6, IPV6_V6ONLY, sock_str_flag },
{"TCP_MAXSEG", IPPROTO_TCP, TCP_MAXSEG, sock_str_int },
{"TCP_NODELAY", IPPROTO_SCTP, TCP_NODELAY, sock_str_flag },
// {"SCTP_AUTOCLOSE", IPPROTO_TCP, SCTP_AUTOCLOSE, sock_str_int },
// {"SCTP_MAXBURST", IPPROTO_SCTP, SCTP_MAXBURST, sock_str_int },
// {"SCTP_MAXSEG", IPPROTO_SCTP, SCTP_MAXSEG, sock_str_int },
// {"SCTP_NODELAY", IPPROTO_SCTP, SCTP_NODELAY, sock_str_flag },
{NULL, 0, 0, NULL },
};

int main(int argc,char **argv)
{
int fd;
socklen_t len;
opts *ptr;

for(ptr=sock_opts;ptr->opt_str !=NULL;ptr++)
{
printf("%s:",ptr->opt_str);

if(ptr->opt_val_str == NULL)
printf("(undefined)\n");
else
{
switch(ptr->opt_level)
{
case SOL_SOCKET:
case IPPROTO_IP:
case IPPROTO_TCP:
fd = socket(AF_INET,SOCK_STREAM,0);
break;
default:
err_quit("Can’t create fd for level %d\n",ptr->opt_level);
}

len = sizeof(val);
if(getsockopt(fd,ptr->opt_level,ptr->opt_name,&sock_val,&len) == -1)
err_ret("getsockopt error");
else
printf("default = %s\n",(*ptr->opt_val_str)(&sock_val,len));

close(fd);

}

}
}

//记录日志
void err_doit(int errnoflag, int level ,const char *fmt, va_list ap)
{
int errno_save,n;
char buf[MAXLINE+1];

errno_save = errno;
#ifdef HAVE_VSNPRINTF
vsnprintf(buf,MAXLINE, fmt , ap);
#else
vsprintf(buf,fmt,ap);
#endif
n=strlen(buf);
if(errnoflag)
snprintf(buf+n,MAXLINE-n,": %s",strerror(errno_save));
strcat(buf,"\n");

if(daemon_proc)
{
syslog(level,buf);
}
else
{
fflush(stdout);
fputs(buf,stderr);
fflush(stderr);
}
}
//错误退出,和上面一样
void err_quit(const char *fmt,…)
{
va_list ap;
va_start(ap,fmt);
err_doit(0,LOG_ERR, fmt,ap);
va_end(ap);
exit(1);
}
void err_ret(const char *fmt,…)
{
va_list ap;
va_start(ap,fmt);
err_doit(1,LOG_INFO,fmt,ap);
va_end(ap);
return ;
}

static char strres[128];

static char *
sock_str_flag(union val *ptr, int len)
{
/* *INDENT-OFF* */
if (len != sizeof(int))
snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
else
snprintf(strres, sizeof(strres),
"%s", (ptr->i_val == 0) ? "off" : "on");
return(strres);
/* *INDENT-ON* */
}
/* end checkopts3 */

static char *
sock_str_int(union val *ptr, int len)
{
if (len != sizeof(int))
snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
else
snprintf(strres, sizeof(strres), "%d", ptr->i_val);
return(strres);
}

static char *
sock_str_linger(union val *ptr, int len)
{
struct linger *lptr = &ptr->linger_val;

if (len != sizeof(struct linger))
snprintf(strres, sizeof(strres),
"size (%d) not sizeof(struct linger)", len);
else
snprintf(strres, sizeof(strres), "l_onoff = %d, l_linger = %d",
lptr->l_onoff, lptr->l_linger);
return(strres);
}

static char *
sock_str_timeval(union val *ptr, int len)
{
struct timeval *tvptr = &ptr->timeval_val;

if (len != sizeof(struct timeval))
snprintf(strres, sizeof(strres),
"size (%d) not sizeof(struct timeval)", len);
else
snprintf(strres, sizeof(strres), "%d sec, %d usec",
tvptr->tv_sec, tvptr->tv_usec);
return(strres);
}

[/c]

 

数据结构学习–AVL树

AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个儿子子树的高度最大差别为一,所以它也被称为高度平衡树。AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 “An algorithm for the organization of information” 中发表了它。

其中AVL树主要的操作包括:左旋、右旋、两种情况的双旋转。下面先给出旋转的示意图:

单旋:

单旋

两种情况的双旋:

双选-左-右

双旋-右-左

 

下面,根据上述的旋转示意图编写递归的代码:

[c language=”++”]
struct AvlNode{
int val, height;
AvlNode*l, *r;
AvlNode() :val(-1), height(-1), l(NULL), r(NULL){};
AvlNode(int x) :val(x), height(0), l(NULL), r(NULL){};
};
static int Height(AvlNode* T)
{//求高度
if (T == NULL) return -1;
else return T->height;
}
static AvlNode* SingleRotateLeft(AvlNode* k2)
{//左旋,把树顺时针旋转
AvlNode*k1 = k2->l;
k2->l = k1->r;
k1->r = k2;
//注意更新高度
k2->height = max(Height(k2->l), Height(k2->r)) + 1;
k1->height = max(Height(k1->l), k2->height) + 1;
return k1;
}
static AvlNode* SingleRotateRight(AvlNode* k1)
{//右旋,把树逆时针旋转
AvlNode*k2 = k1->r;
k1->r = k2->l;
k2->l = k1;
//注意更新高度
k1->height = max(Height(k1->l), Height(k1->r)) + 1;
k2->height = max(Height(k2->r), k1->height) + 1;
return k2;
}
static AvlNode* DoubleRotateLeft(AvlNode* k3)
{//先把k2(k3->l)逆时针旋转,再把k3顺时针旋转
k3->l = SingleRotateRight(k3->l);
return SingleRotateLeft(k3);
}

static AvlNode* DoubleRotateRight(AvlNode* k1)
{//先把k2(k1->r)逆时针旋转,再把k1顺时针旋转
k1->r = SingleRotateLeft(k1->r);
return SingleRotateRight(k1);
}

static AvlNode* Insert(int x, AvlNode*T)
{
if (T == NULL)//如果节点为空,则新建一个节点
T = new AvlNode(x);
else if (x < T->val)
{//x小于T的值,则插入左边
T->l = Insert(x, T->l);
if (Height(T->l) – Height(T->r) == 2)
{//插入后,左边比右边高2,则需要调整
if (x < T->l->val)//如果插入的值是在左子树的左边,则左旋即可
T = SingleRotateLeft(T);
else//如果插入的值是在左子树的右边,那么需要双旋转
T = DoubleRotateLeft(T);
}
}
else if (x > T->val)
{//如果插入的值大于T的值,则插入T的右子树中
T->r = Insert(x, T->r);
if (Height(T->r) – Height(T->l) == 2)
{//高度差为2,需要调整
if (x>T->r->val)//如果在右子树的右边,单选即可
T = SingleRotateRight(T);
else//在右子树的左边,需要双旋
T = DoubleRotateRight(T);
}
}
//注意更新高度
T->height = max(Height(T->l), Height(T->r)) + 1;
return T;
}
[/c]

cvCreateImage内存泄露

这些天在弄OpenCV,用来把两张640*480的图片拼在一起,拼成1280*480,然后发现调用下面这个函数的时候内存一直在增大,貌似有些变量无法释放内存.

[c language=”++”]
void Show2Image(cv::Mat cvImg1, cv::Mat cvImg2)
{
beginTime =clock();
std::cout<<“图片合并开始时间:”<<beginTime<<std::endl;
IplImage* image1=&cvImg1.operator IplImage();
IplImage* image2=&cvImg2.operator IplImage();
IplImage* image3 = cvCreateImage( cvSize(image1->width+image2->width,MAX(image1->height,image2->height)),IPL_DEPTH_8U,3);

CvRect rect=cvRect(0,0,image1->width,image1->height);
cvSetImageROI(image3,rect);
cvCopy(image1,image3);
cvResetImageROI(image3);
rect=cvRect(image1->width,0,image2->width,image2->height);
cvSetImageROI(image3,rect);

cvCopy(image2,image3);
cvResetImageROI(image3);

cvShowImage(“Kinect Follow & Xtion ObstacleAvoide”,image3);

//cvReleaseImage(&image3);
endTime =clock();
std::cout<<“结束时间:”<<endTime<<std::endl
<<“图片合并花费时间:”<<endTime-beginTime<<std::endl<<std::endl;
}
[/c]

经过排查,发现是

   IplImage* image3 = cvCreateImage( cvSize(image1->width+image2->width,MAX(image1->height,image2->height)),IPL_DEPTH_8U,3);

这句代码导致内存增大.

然后发现cvCreateImage需要和cvReleaseImage配合用,譬如上述代码,需要用cvReleaseImage(&image3);来释放image3的内存,而image1和image2不是用cvCreateImage创建的,所以不用使用cvReleaseImage来释放,假如你使用了,反而会报错.

 

解决方案[LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏]

解决方案:

在VS2010经历一些更新,或者是在装完VS2010后再安装了更高级的版本,例如VS2012,VS2013等,会出现

LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

的错误!

解决方案为将 项目|项目属性|配置属性|清单工具|输入和输出|嵌入清单 “是”改为“否”即可,但是没新建一个项目都要这样设置一次。
在建立VS2010 Win32 Project项目时,按照上面解决方案依然发生了“error LNK1123”错误,经过上网查资料,解决方案为:
第一步:与上相同。
第二步:将 项目|项目属性|配置属性|连接器|清单文件|嵌入清单 “是”改为“否”。
第三步:一般计算机经过上两步设置就能解决问题了,但是如果还有问题,那就按一下方法解决:

找到Microsoft Visual Studio 10.0\VC\bin ,把cvtres.exe删除,然后找到新版本的VC\bin里面的cvtres.exe拷贝过来.

例如,我的VS2010 bin路径是在 C:\Program Files\Microsoft Visual Studio 10.0\VC\bin

VS2012 bin路径是在D:\Program Files\Microsoft Visual Studio 12.0\VC\bin

把10.0\bin里面的cvtres.exe删除,把12.0\bin里面的cvtres.exe复制到10.0\bin里面

然后运行程序就没问题了!

意外的是,治本的办法是第三步,删除旧版本的cvtres.exe后,就不需要每次都设置配置了。