目录

201.数组al[O,mid-l]和al[mid,num-l],都分别有序。将其 merge成有序数组al[O,num-1],要求空间复杂度0(1).

202. 一个url指向的页面里面有另一个url,最终有一个url指 向之前岀现过的url或空,这两种情形都定义为nulL这样构 成一个单链表。给两条这样单链表,判断里面是否存在同样 的url。url以亿级计,资源不足以hasho本題可以抽象为有环和无环情况下的链表交叉问题:

203.将单向链表reverse,如ABCD变成DCBA,只能搜索链表一 次.

204. A,B,C,D四个进程,A向Buf里面写数据,B,C,D向Buf里面读 数据,当A写完,且B,C,D都读一次后,A才能再写.用PV操作实 现.

205. 进程和线程的区别介绍?

206. 请描述分布式的优势.

207. 阅读下面代码,回答问题.

208. 变量a是一个64位有符号的整,初始值用16进制表示 为:0x7FFFFFFFFFFFFFFF;变量b是一个64位有符号的整数,初 始值用16进制表示为0x8000000000000000.则a+b的结果 用10进制表示为多少?

209. if [$2 -a $2 = "test"]中-a 是什么意思?

210. 已知 int 占个字节,unsigned char 占 1 个字节,unsigned int number=Oxffaabcdd;下 种方式 可以将number的 值变为 Oxffaacddd?

211. 模式串的长度是m,主串的长度是n(m),使用kmp算法>

212.求O-n之间二进制内没有连续三个1的数的个数.

213. C++ 智能指针 shared_ptr、weak ptr 的实现.

214.请问C++11有哪些新特性?

215. 智能指针是线程安全的吗?哪些地方需要考虑线程安全?

216. 如何访问非法内存区?

217. 决策树是如何解决过拟合问题的?

218. 什么是GBDT算法?

219.写一个C++回调函数示例.

220. Linux日志文件统计某几个字符串,如何一条命令就能统 计岀来?


201.数组al[O,mid-l]和al[mid,num-l],都分别有序。将其 merge成有序数组al[O,num-1],要求空间复杂度0(1).

首先把给定的数组分成两部分,前一部分包括A m]中的元素,而后者则包括(m口]中的 元素。然后找到第一个数组中的中间值,也就是ql=(l侦)/2, ql位置的元素就是我们 要找的元素,大家可以举个例子自己算一下,当找到ql的时候,Q1前面的元素有Q1个, 这对接下来的编程很有影响,所以这点一定要弄清楚。这样第一个数组我们就分为了两 部分。接下来我们用Q1去划分(人工】这段元素,也是分成两部分。建议在取元素范围的 时候,(叫工】这段的前一部分个数为(q2-l-m)个,后一部分为(r - q2 +1)个,这样 约定后思路会清晰。接下来划分好了之后就是交换,有一种叫做block swapping的算 法,这个算法能在。(1)的空间复杂度下交换两个长度不相同的相邻存储区的数组。

#include<stdio. h>
Siiic lude^assert.
void swap (int *a, int low, int high; {
while(low < high) {
int temp = *(a + low);
*(a + low) = *(a + high);
*(a + high) = temp;
low++;
high—;
void block_exchange (int int low, int mid, int high) {
swap (a, low, mid);
swap (a, mid + 1$ high);
swap (a, low, high);
int b inar y_s e ar ch (int value, int *a, int low, int high) { /*
如果数组中存在要查找的元素,那么返回high的位置的前后都有可能等于value 的值:
a: 1, 2, 4,4, 7,9 value=4 mid=2返回的high位置的元素后有值等于value
b: 1, 2, 4,4, 7,9,10 value=4 mid=3.返回的high位置的元素前有值等于value
c: 1,2, 7,9 value=4 high=3,返回的high值之前的元素都小于value,包括high 在内的以后得元素都大于value
*/
assert(a != NULL);
while(low < high) {
int mid = low + (high - low: / 2;
if(value 仁 a[mid])
high = mid;
else
low = mid + 1;
}
return high;
void merge__iri_place (int *a, int low, int mid, int high) {
int length! = mid 一 low +1;
int length2 = high - mid;
if(J(lengthl >= 0 && length2 >= 0))
return ;
if (lengthl >= length2) {
if (leng th2 <= 0)
return;
int ql = (low + mid) / 2;
int qZ = binary^sear ch (a [ql., a, mid 十 1 , high); int q3 = ql + (q2 - 1 - mid;;
ql, mid, q2 - 1); low, ql - 1, q3 - 1); q3 + 1, q2 - 1, high);
} else {
if (leng thl <= 0)
return;
int ql = (mid + 1 int q2 = binary_search(a[ql_, a, low, mid);
int q3 = q2 + (ql - 1 - mid;; block_exchange (a, q2, mid, ql);
merge_in_place (a, low, q2 - 1, q3 -1);
merge_in_place (a, q3 + 1, ql, high);
}
I
void main() {
int a[] = {爲 3, 5, 7,9, 2, 4,6,8,10};
int len = sizeof(a) /sizeof(int;;
int mid = len / 2 - 1;
merge_in_place (a, 0, mid, len - 1);
for(int i = 0; i < len; i++)
printf a[i]);
printfCXn^);
}

202. 一个url指向的页面里面有另一个url,最终有一个url指 向之前岀现过的url或空,这两种情形都定义为nulL这样构 成一个单链表。给两条这样单链表,判断里面是否存在同样 的url。url以亿级计,资源不足以hasho本題可以抽象为有环和无环情况下的链表交叉问题:

情况一:两条单链表均无环
最简单的一种情况,由于两条链表如果交叉,他们的尾节点必然相等(Y字归并), 所以只需要判断他们的尾节点是否相等即可。

情况二:两条单链表均有环
这种情况只需要拆开一条环路(注意需要保存被设置成null的节点),然后判断 另一个单链表是否仍然存在环路,如果有在,说明无交叉,反之,则有交叉的情况。 情况三:两条单链表,一条有环路,一条无环路
这种情况显然他们是不可能有交叉的

附:如何判断一条单链表是否存在环路,以及找出环路的入口
快慢指针:在表头设置两个指针fast与slow, fast指针与slow指针同时向前移动, 但是f as t每次移动2个节点,slow每次移动1个节点,若fast指向null或者fast==slow 时停止,这时如果fast指向mil,则说明没有环路,若faSt==slow则说明有环路。 找环路入口:当fast==slow时,将fast重新指向表头。slow原地不动。然后fast和 slow在同时以每次一个节点的速度向前移动,当他们再次重合时,就是环路入口。证 明如下:

1.证明fast和slow肯定会重合 在slow和fast第一次相谒的时候,假定Slow走了 n步骤,环路的入口是在p步的时 候经过的那么有slow走的路径:p+c = n; c为pl和p2相交点,距离环路入口 的距离;fast走的路径:p+c+k*L =如;L为环路的周长,k是整数。显然,如 果从p+c点开始,pl再走n步骤的话,还可以回到p+c这个点同时p2从头开始走的话, 经过n步,也会达到p+c这点。

2. fast和slow在p+c点会重合,显然他们从环的入口点就开始重合


203.将单向链表reverse,如ABCD变成DCBA,只能搜索链表一 次.

#include <iostream>
using namespace std;
struct node
[
char data;
struct node *next;
};
typedef struct node NODE;
void test_exercise()
[
NODE *head = new NODE; /健立附加头结点 head~>next = NULL;
/彳创建链表*/
NODE *curr ent, *pr evi ous;
previous = head;
char irput;
cout « ^Irput your list table NODE data, end with
cin » irput;
while(irput J=)
{
current - new NODE;
current-〉data - irpu■:; current">next = NULL.
previous">next - curlent;
previous = pr evi ous"/ne x t;
cout « ^Irput your list table NODE data, end with cin » irput;
/欄出链表*/ current - head">next; while(current != NULL)
[
cout << current-〉data << current - current~>next;
}
cout << endl;
湖转链表*/ current - head">next;
NODE *p = current~>next;
NODE *q = p->next;
while(q != NULL)
[
p->next = current; current - p;
P = q;
q = q->next;
}
p->next = current;
current - p; head->next->next = NULL; head">next = current;
/欄出链表*/
current = head~>next; while(current != NULL) {
cout << current-〉data << current - current~>next;

204. A,B,C,D四个进程,A向Buf里面写数据,B,C,D向Buf里面读 数据,当A写完,且B,C,D都读一次后,A才能再写.用PV操作实 现.

响B,C, D四个进程,A向buf里面写数据,B, C, D向buf里面读数据, 当A写完,
semaphore semaphore semaphore semaphore semaphore semaphore
while(true){ P(empty);
P(b);
Pic 丿;
P(d); p(mutex); write ();
v(mutex): v(full)
while(true){ p(full); p(mutex); write ();
v(mutex); v(empty); v(b);
C(){
while(true){p (full);
p(mutex);
write ();
v(mutex);
v(empty);
v(c);
}
I
D (){
while(true){
P (full);
p(mutex);
write ();
v(mutex);
v(empty);
v(d);

205. 进程和线程的区别介绍?

1、 首先是定义
进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。 进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的 单位。
线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位。

2、 一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允 许一个进程中在同一时刻执行多个任务

3、 线程是一种轻量级的进程,与进程相比,线程给操作系统带来侧创建、维护、和管 理的负担要轻,意味着线程的代价或开销比较小。

4、 线程没有地址空间,线程包含在进程的地址空间中。线程上下文只包含一个堆栈、 一个寄存器、一个优先权,銭程文木包含在他的进程的文木片段中,进程拥有的所有 资源都属于线程。所有的线程共享进程的内存和资源。同一进程中的多个线程共享代 码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥 有自己的栈段,寄存器的内容,栈段又叫运行时段,用来存放所有局部变量和临时变 里。

5、 父和子进程使用进程间通信机制,同一进程的线程通过读取和写入数据到进程变量 来通信。

6、 进程内的任何线程都被看做是同位体,且处于相同的级别。不管是哪个线程创建了 哪一个线程,进程内的任何线程都可以销毁、挂起、恢复和更改其它线程的优先权。线程也要对进程施加控制,进程中任何线程都可以通过销毁主线程来销毁进程,销毁主线 程将导致该进程的销毁对主线程的修改可能影响所有的线程。

7、子进程不对任何其他子进程施加控制,进程的线程可以对同一进程的其它线程施加 控制。子进程不能对父进程施加控制,正程中所有线程都可以对主线程施加控制。
相同点:
进程和线程都有ID脣存器组、状态和优先权、信息块,创建后都可更改自己的属性, 都可与父进程共享资源、都不鞭直接访问其他无关进程或线程的资源。


206. 请描述分布式的优势.

分布式结构就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在分 布式结构中,每个子系统就被称为“服务”。这些子系统能够独立运行在web容器中, 它们之间通过RPC方式通信。
举个例子,假设需要开发一个在线商城。按照微服务的思想,我们需要按照功能模块拆 分成多个独立的服务,如:用户服务、产品服务、订单服务、后台管理服务、数据分析 服务等等。这一个个服务都是一个个独立的项目,可以独立运行。如果服务之间有依赖 关系,那么通过RPC方式调用。
分布式的好处:
系统之间的耦合度大大降低,可以独立开发、独立部署、独立测试,系统与系统之间的 边界非常明确,排错也变得相当容易,开发效率大大提升。
系统之间的耦合度降低,从而系统更易于扩展。我们可以针对性地扩展某些服务。假设 这个商城要搞一次大促,下单量可能会大大提升,因此我们可以针对性地提升订单系统、 产品系统的节点数量,而对于后台管理系统、数据分析系统而言,节点数量维持原有水 平即可。
服务的复用性更高。比如,当我们将用户系统作为单独的服务后,该公司所有的产品都 可以使用该系统作为用户系统,无需重复开发。


207. 阅读下面代码,回答问题.

# include <stdio.h> nainO {
int su)n^ pad^ pAd;
Sum = pad = 5;
pAd = ++sum^ pA<R+^ ++pad; printf ( , pad);6

208. 变量a是一个64位有符号的整,初始值用16进制表示 为:0x7FFFFFFFFFFFFFFF;变量b是一个64位有符号的整数,初 始值用16进制表示为0x8000000000000000.则a+b的结果 用10进制表示为多少?

-1


209. if [$2 -a $2 = "test"]中-a 是什么意思?

并且


210. 已知 int 占个字节,unsigned char 占 1 个字节,unsigned int number=Oxffaabcdd;下 种方式 可以将number的 值变为 Oxffaacddd?

A. *( (unsigned char*) (&number) + l)=0xcd;
B. number = (number & OxffffiJOff) | OxOOcdOO;
C. number = (number & 0xffee43dd) | Oxbbaacddd;
D. number = (number & Oxffccbcff) + 0x1100;

A,B,C


211. 模式串的长度是m,主串的长度是n(m<n),使用KMP算法 匹配的时间复杂度是?

0 (m+n)
KMP字符串匹配时间复杂度一定是0(N)銭性


212.求O-n之间二进制内没有连续三个1的数的个数.

#include <iostreajn>
using namespace std;
int v[100];
int dp [100] [3];
int dfs (int len, int flag, bool limit; {
if (flag == 3)return 0;
if (len == 0) return 1;
if (J limit&&dp [len] [flag] != T; return dp [len] [flag];
int maxx = limit ? v[len] : 1;
int ent = 0;
for (int i = 0; i <= maxx; i++)[
if (i == 0){
ent += dfs (lernl, 0, == v[len]):
}
else{
ent += dfs (lern 1, flag+1 , == v[len]);
}
}
return limit ? ent : dp[len] [flag] = ent;
}
int solve(long long x){
memset (v, 0, sizeof (v));
int k = 0;
while (x){
v[++k] = x % 2;
x »=1;
}
return df s (k, 0, true);
}
int main() {
memset(dp, -1, sizeof(dp));
long long a;
cin >> a;
cout«solve (a) «endl;
return 0;

213. C++ 智能指针 shared_ptr、weak ptr 的实现.

Counter类
Counter 象的目地就是用来申请一个块内存来存引用计数。shareCount是SharedPtr 的引用计数,weakCount是弱引用计数。
当shareCount为0时,删除X对象。
当 weakCount 为 0 同时 shareCount 为 0 时,删除 Count er*对象。

Counter实现如下:

class Counter
[
public:
int shareCount - 0;
int weakCount = 0;
};

SharedPtr类

主要的成员函数包括:
默认构造函数
参数为T*的explicit单参数构造函数
参数为WeakPtr&的explicit单参数构造丞数
拷贝构造函数
拷贝赋值函数
析构函数
隐式类型转换操作符operator bool ()
operator -〉()
operator * ()
ShazedPtr实现如下:

template<class T> class WeakPtr;
template<class T> class SharedPtr
{
public:
friend class WeakPtr<T>; /防便v/eak_ptr与share」h设置弓囲计数和赋值。
SharedPtr ()
:m_pResource(nullptr)
, m_pCounter(new Count er())
[
m_pCount er">shareCount = 1;
explicit SharedPtr(T* pResource = nullptr)
:m_pResource(pResource)
, m_pCounter(new Count er())
m_pCount er~>shareCount - 1;
SharedPtr (const WeakPtr<T>& other) // 供 WeakPtr 的 lock。使用 :m_pResource (other. m_pResource)
, m_pCounter(other・ m_pCounter)
[
if (0 -- m_pCounter">shareCount) m_pResource - nullptr;
SharedPtr(const SharedPtr<T>& o^her)
:m_pResource (other">m_pResource)
, m_pCounter(other">m_pCounter)
[
■H-(m_pCounter->shareCount); // 増加引用计数
SharedPtr<T>& operator = (const SharedPtr<T>& other)
[
if (this == Mother) return xthis;
release ();
m_pCounter = other・ m_pC ounter; m_pResource = other. m_pResource;
++(m_pCounter->shareCount); // 増加引用计数
return *this;
}
"'SharedPtr ()
I
release ();
T& operator bool ()
[
return m_pResource != nullpir;
// 如果nullptr == m_pResource,抛出异常 return *m_pResource;
}
T* operator -> ()
[
return m_pResource;
}
private:
void release ()
[
// T*肯定由 SharedPtr 释放,Count er*如果没有 WeakPtr,也由 SharedPtr 释放
--m_pCount er~>shareCount;
if (0 == m_pCount er~>shareCount)
[
delete m_pResource; m_pResource - nullptr;
if (0 == m_pCount er~>weakCount)
[
delete m_pCounter;
m_pCounter = NULL;
public:
T* m_pResource = nullptr;
Counter* m_pCounter - nullptr;

WeakPtr类
主要的成员函数包括:
默认构造函数
参数为SharedPh&的explicit单参数构造函数
拷贝构造函数
拷贝赋值函数
析构函数

lock。函数:取指向的SharePtr,如果未指向任何ShazePtr,或者已被析构,返回指 向 nullptr 的 SharePtr
expired ()©数:是否指向SharePtr,如果指向Share Ptr其是否已经析构
release ()© 数
WeakPtr实现如下:

template<class T> class WeakPtr
[
public:
friend class SharedPtr<T>; If%便 weak_ptr 与 share_ptr 设置引用计数和赋值。
WeakPtr ()
m_pResource(nullptr)
, m_pCount er (new Count er ())
[
m_pCount er-^weakCount = 1;
}
WeakPtr(SharedPtr<T>& other)
:m_pResource(other. m_pResource)
,m_pCount er (other. m_pCounter)
[
++(m_pCounter->weakCount);
}
WeakPtr(WeakPtr<T>& other)
:m_pResource(other. m_pResource)
, m_pCounter(other. m_pCounter)
{
++(m_pC ount er-we akC ount);
}
WeakPtr<T>& operator = (WeakPtr<T>& other)
[
if (this == &other) return xthis;
release ();
m_pCounter = other. m_pCount er;
m_pResource = other. m_pResource;
++m_pCount er-^weakCount;
return *this;
release ();
m_pCounter = other・ m_pCounter;
m_pResource - other. m_pCount er;
+-hn_pCount er->weakCount; // 増加弱引用计数 return *this;
}
WeakPtr ()
[
release ();
}
SharedPtr<T> lock()
[
return SharedPtr<T>(*this);
}
bool expired ()
[
if (m_pCounter != nullptr && m_pCountershareCount != 0) return false;
return true;
}
private:
void release()
{
--m_pCount er">weakCount;
if (0 == m_pCourrt er->weakCount && 0 == m_pCount er->shareCount) // 必 须都为0才能删除
{
delete m_pCounter;
m_pCounter = NULL;
private:
T* m_pResource; //可能会成为悬挂指针
Counter* m_pCounter;

214.请问C++11有哪些新特性?

c卄11最常用的新特性如下:
aut。关键字:编译器可以根据初始值自动推导出类型。但是不能用于函数传参以及数 组类型的推导
nullptr关键字:mllptr是一种特殊类型的字面值,它可以被转换成任意其它的指针 类型;而NULL-般被宏定义为0,在谒到重载时可能会出现问题。
智能指针:C++11新増了 std: :shared_p-rk std: : weak_ptr等类型的智能指针,用于 解决内存管理的问题。
初始化列表:使用初始化列表来对类进行初始化
右值引用:基于右值引用可以实现移动语义和完美转发,消除两个对象交互时不必要的 对象拷贝,节省运算存储资源,提高效率
atomic原子操作用于多线程资源互斥操作
新増STL容器array以及tuple


215. 智能指针是线程安全的吗?哪些地方需要考虑线程安全?

1. 智能指针对象中引用计数是多个智能指针对象共享的,两个线程中智能指针的引用计 数同时卄或者一,这个操作不是原子的,引用计数原来是1,卄了两次,可能还是2, 这样引用计数就乱了,有可能造成资源粹放或者程序崩溃的风险。所以说智能指针中 I或一的操作是需要加锁的也就是说引用计数的操作是线程安全的
2. 智能指针的对象存放在堆上,两个线程同时去访问,就会造成线程安全问题.

std:: shaxed_ptr 循环引用 struct ListNode
{
int _data;shared_ptr<ListNode/r shared_ptr〈ListNode, listNodeO { cout « ); int main。
shared_ptr<ListNode> nodel(new ListNode); shared_ptr<ListNode> node2(new ListNode); cout « no del. use__count () « endl; cout « node2. use__count () « endl;
nodel->_next = node2;
node2-^_prev - no del;
cout « no del. use__count () « endl;
cout « node2. use__count () « endl;
return 0;

no del和no de2两个智能指针对象指向两个节点,引用计数变为1,我们不需要手动 delete nodel的_next指向node2, node2的丄工邮指向no del,引用计数变成2
no del和no de2析构,引用计数减到1,但是_mxt还指向下一个节点,_prev指向上一 个节点
也就是说一next析构了,no de2释放了
也就是说_prev析构了,no del释放了
但是一next属于node的成员,no del释放了,_mxt才会析构,而rodel由_prevW理, _?工印属于1101^2成员,所以这就叫循环引用,谁都不会释放

解决方案
在引用计数的场景下,把sharedjtr换成weak_ptr就可以了
原理就是,nodel->_next = node2;和 node2->_prev = no del;时 weak_ptr 的 _next 和口通卩不会増加nodel和node2的引用计数

struct ListNode
[
int _data;
weak_ptr<ListNode/r _prev; weak_ptr<ListNode^ _next;
^ListNode () {
cout « "TistNodeO” « endl;
int main。
[
shared_ptr<ListNode> nodel(new ListNode); shared_ptr<ListNode> node2(new ListNode); cout « no del. use__count () « endl; cout « node2. use__count () « endl; nodel->_next = node2;
node2~^_prev - no del;
cout « no del. use__count () « endl;
cout « node2. use__count () « endl;
return 0;
}

如果不是new出来的空间如何用智能指针管理呢?
其实shared_ptr设计了 一个删除器来解决这个问题
//仿函数的删除器

template'Cclass T>
struct FreeFunc {
void operator () (T* ptr)
[
cout « "free:" « ptr « endl;
free (ptr);
I
};
template'Cclass T>
struct DeleteAxrayFunc {
void operator () (T* ptr)
[
cout « "delete]]" « ptr « endl;
delete[] ptr;
}
};
int main()
[
FreeFunc<int〉 freeFunc;
shared_ptr<int> spl((int*)malloc(4), freeFunc);
DeleteAxrayFunc<int> de1eteAxrayFunc;
shared_ptr<int> sp2((int*)malloc(4), deleteAxrayFunc); return 0;
}

216. 如何访问非法内存区?

1、在下列程序中,i和*Pi都是未初始化的变量,它们的值都是不确定的。而Pi指向 的是未知位置,不属于程序所拥有的存儲单元,该指针变量称为野指针

#include<stdio. h> int main。
[
int i,*pi;
*pi=5;
printf (°%d\n°, i, *pi);
return 0;

2、 使用已经释放过后的指针
堆空间用空闲链表法来组织,释放后的地址返回链表中,可能其他函数申请了该地址处 的空间。如果写了其他函数使用的空间,可能导致其他程序出错。malloc

3、 指针所指向的变量在指针之前被销毁
例如,指针指向了某个函数中的局部变量,当函数返回后,局部变量被销毁,如果栈空 间又被使用,再使用该指针可能就会出错。


217. 决策树是如何解决过拟合问题的?

产生过度拟合数据问题的原因
原因1:样本问题
(1) 样本里的噪音数据干扰过大,大到模型过分记住了噪音特征,反而忽略了真 实的输入输出间的关系5(什么是噪音数据?)
(2) 样本抽职错误,包括(但不限于)样本数量太少,抽样方法错误,抽样时没 有足够正确考虑业务场景或业务特点,等等导致抽出的样本数据不能有效足够代表业务 逻辑或业务场景;
(3) 建模时使用了样本中太多无关的输入变量。
原因2:构建决策树的方法问题
在决策树模型搭建中,我们使用的算法对于决策树的生长没有合理的限制和修萸的 话,决策树的自由生长有可能每片叶子里只包含单纯的事件数据或非事件数据,可以想 象,这种决策树当然可以完美匹配(拟合)训练数据,但是一旦应用到新的业务真实数 据时,效果是一塌糊'涂。
二.如何解决过度拟合数据问题
针对原因1的解决方法:
合理、有效地抽样,用相对能够反映业务逻辑的训练集去产生决策树;
针对原因2的解决方法(主荽):
萸枝:提前停止树的増长或者对已经生成的树按照一定的规则进行后萸枝。 萸枝的方法
萸枝是一个简化过拟合决策树的过程。有两种常用的萸枝方法:
(1)先萸枝(prepruning):通过提前停止树的构建而对树"萸枝”,一旦停止, 节点就成为树叶。该树叶可以持有子集元组中最频繁的类; 先萸枝的方法
有多种不同的方式可以让决策树停止生长,下面介绍几种停止决策树生长的方法: 限制决策树的高度和叶子结点处样本的数目
―1.定义一个高度,当决策树达到该高度时就可以停止决策树的生长,这是一种最为 简单的方法;
2. 达到某个结点的实例具有相同的特征向量,即使这些实例不属于同一类,也可以 停止决策树的生长。这种方法对于处理数据中的数据冲突问题非常有效:
3. 定义一个阚值,当达到某个结点的实例个数小于该阚值时就可以停止决策树的生 长;
4. 定义一个阚值,通过计算每次扩张对系统性能的増益,并比较増益值与该阚值的 大小来决定是否停止决策树的生长。
⑵后萸枝(postpruning):它首先构造完整的决策树,允许树过度拟合训练数据, 然后对那些置信度不够的结点子树用叶子结点来代替,该叶子的类标号用该结点子树中 最频繁的类标记。后萸枝的萸枝过程是删除一些子树,然后用其叶子节点代替,这个叶 子节点所标识的类别通过大多数原则(majority class criterion)确定。所谓大多数原 则,是指萸枝过程中,将一些子树删除而用叶节点代替,这个叶节点所标识的类别用这 棵子树中大多数训练样本所属的类别来标识,所标识的类称为majority class .相比于 先萸枝,这种方法更常用,正是因为在先萸枝方法中精确地估计何时停止树増长很困难。
后萸枝的方法
DEEP方法是一种比较简单的后萸枝的方法,在该方法中,可用的数据被分成两 个样例集合:一个训练集用来形成学习到的决策树,一个分离的验证集用来评估这个决 策树在后续数据上的精度,确切地说是用来评估修萸这个决策树的影响。这个方法的动 机是:即使学习器可能会被训练集中的随机错误和巧合规律所误导,但验证集合不大可 能表现出同样的随机'波动。所以验证集可以用来对过度拟合训练集中的虚假特征提供防 护检燈。
该萸枝方法考虑将书上的每个节点作为修萸的候选对象决定是否修萸这个结点有 如下步骤组成:
1:删除以此结点为根的子树
2:使其成为叶子结点
3:赋予该结点关联的训练数据的最常见分类
4:当修萸后的树对于验证集合的性能不会比原来的树差时,才真正删除该结点
因为训练集合的过拟合,使得验证集合数据能够对其进行修正,反复进行上面的操 作,从底向上的处理结点,删除那些能够最大限度的提高验证集合的精度的结点,直到 进一步修萸有害为止(有害是指修萸会减低验证集合的精度)。
REP是最简单的后萸枝方法之一,不过由于使用独立的测试集,原始决策树相比, 修改后的决策树可能偏向于过度修萸。这至因为一些不会再测试集中出现的很稀少的训 练集实例所対应的分枝在荆枝辿如果训练集段小通常不岑虑釆用KEP算法。
尽管REP有这个缺点,不过REP仍然作为一种基准来评价其它萸枝算法的性能。它 对于两阶段决策树学习方法的优点和缺点提供了了一个很好的学习思路。由于验证集合 没有参与决策树的创建,所以用REP萸枝后的决策树对于测试样例的偏差要好很多,能 够解决一定程度的过拟合问题。
2)PEP,悲观错误萸枝,悲观错误萸枝法是根据萸枝前后的错误率来判定子树的修 萸。该方法引入了统计学上连续修正的概念弥补REP中的缺陷,在评价子树的训练错误 公式中添加了一个常数假定每个叶子结点都白动对实例的某个部分进行错误的分类。 它不需要像REP (错误率降低修萸)样需要用部分样本作为测试数据而是完全使用训 练数据来生成决策树,又用这些训练数据来完成萸枝。决策树生成和萸枝都使用训练集, 所以会产生错分。
把一棵子树(具有多个叶子节点)的分类用一个叶子节点来替代的话,在训练集上 的误判率肯定是上升的,但是在测试数据上不一定,我们需要把子树的误判计算加上一 个经验性的惩罚因子,用于估计它在测试数据上的误判率。对于一棵叶子节点,它覆盖 了 N个样本,其中有E个错误,那么该叶子节点的错误率为(E+0.5)/No这个0.5就 是惩罚因子,那么对于该棵子树,假设它有L个叶子节点,则该子树的误判率估计为:
(£&+0.5*乙)/少,
萸枝后该子树内部节点变成了叶子节点,该叶子结点的误判个数J同样也需要 加上一个惩罚因子,变成Jb. 5。那么子树是否可以被萸枝就取决于萸枝后的错误5 在
工 Ei + 0.5 * L
的标准误差内。对于样本的误差率e,我们可以根据经验把它估计成伯努利分布,那么 可以估计出该子树的误判次数均值和标准差
E^subtree.err.count) = N * e

var^subtree-err.count) = \/N * e * (1 — e)
使用训练数据,子树总是比替换为一个叶节点后产生的误差小,但是使用校正的 误差计算方法却并非如此。萸枝的条件:当子树的误判个数大过对应叶节点的误判个数 —个标准差之后,就决定萸枝:
E^subtree.err.count) — var(subtree-err.count) > E(leaf.err.count)
这个条件就是萸枝的标准。当然并不一定非要大一个标准差,可以给定任意的 萤信区间,我们设定一定的显著性因子,就可以估算出误判次数的上下界。


218. 什么是GBDT算法?

GBDT (Gradient Boosting Decision Tree)梯度提升迭代决策树。GBDT 也是 Boosting算法的一种,但是和.WaBoost算法不同(AdaBoost算法上一篇文章已经介 绍);区别如下:AdaBoost算法是利用前一轮的弱学习器的误差来更新样本权重值, 然后一轮一轮的迭代;GBDT也是迭代,但是GBDT要求弱学习器必须是CART模型, 而且GBDT在模型训练的时候,是要求模型预测的样本损失尽可能的小。
每一轮预测和实际值有残差,下一轮根据残差再进行预测,最后将所有预测相加,就是 结果。

GBDT模型可以表示为决策树的加法模型:
M
其中,T(x; 8m)表示决策树;8m为决策树的参数;M为树的个数。
采用前向分布算法,首先确定初始提升树fo (x) =0,第m步的模型是:
())()A(X)"0)+7(")
通过经验风险极小化确定下一棵树的参数:(其实就是让残差尽可能的小找到最优划分 点)
如 曾不)=arg曾+不;QJ)−/=i
这里的L()是损失函数,回归算法选择的损失函数一般是均方差(最小二乘)或者绝对 值误差;而在分类算法中一般的损失函数选择对数函数来表示.
GBDT既可以做回归也可以做分类,下面先描述一下做回归的算法流程:

已知一个训练数据集T = {(xL yl), (x2沱),...,(xn, yn)},如果将训练集分为不同的 区域Rl,R2,...,m然后可以确定每个区域输出的常识c,c的计算是将每个区域的y 值相加再除以y的个数,其实就是求一个平均值。树可以表示为:

华。)£勺[(郊)J华;。)=£勺[(∗郊)j=i

然后通过下图方式来确定具体分割点:

■ — min min Y (3 -c) +min £ (yt-c2)2 , L q 砂曷 ‘ Xier2 _■ — min min Y (3 -c) +min £ (yt-c2)2 , L q 砂曷 ‘ Xier2 _

以上就是GBDT选择分割点的过程,如果特征有多个的话也是一样的道理,选择特征 和特征值使得误差最小的点,作为分割点。所以其实GBDT也可以用作特征选择,通过 GBDT可以将重要的特征选择出来,当特征非常多的时候可以用来做降维。然后再融合 类似逻辑回归这样的模型再进行训练。


219.写一个C++回调函数示例.

#include <stdio・h>
//函数指针
type def void(*lpFunc) (void *, char *, int);
//调用回调函数的宿主函数,参数callback是原型名称为IpFunc的函数指针 void GetCallBack(void *lpVoid, IpFunc callback, char* name, int age){
//执行回调函数callback,其实是调用通过形参callback实际传过来的
//函数 fCallback
callback (ipVoid, name, age);
}
class A{
public:
AO {};
void outName(char szAlarm[], int age){
printf(^My name is %s, %d years old \n^, szAlarm, age);
}
/庞又一个类A的静态成员函数fCallback
static void fCallback(void *lpVoid, char szAlarmt], int age){
//类A的成员函数中,使用类A定义一个对象指针p指向传进来的指针
//参数IpVoid,强制类型转换为:A*
A *p = (A*) (ipVoid);
//A类型的对象指针P调用A类的成员寒素outName p~>outName(szAlarm, age);
//A类的成员函数Test
void Test () {
/座类A的成员函数Test中调用外部函数GetCallBack,将类A的静态 //成员函数fCallback名称传给第二个参数,实现fCallback函数的回调 GetCallBack (this, fCallback, "kevin^, 38);
int main(void)
[
A a;
a. TestO;
}

220. Linux日志文件统计某几个字符串,如何一条命令就能统 计岀来?

1-使用vim统计

用vim打开目标文件,在命令模式下,输入:%s/objStr//gn

2. 使用grep

grep -o 'objStrl\|objStr, filenane|wc ~1 #直接用\ | 链接起来即可


秋招大厂经典面试题及答案整理不断更新中,感兴趣且正在学习的同学可以点个关注;狮会不断更新文章连载,有问题或者见解可以评论区讨论。

2023秋招大厂经典面试题及答案整理归纳(201-220)校招必看相关推荐

  1. 2023秋招大厂经典面试题及答案整理归纳(141-160)校招必看

    目录 141. 动态连接库的两种方式? 142. IP组播有那些好处? 143. 列举几种进程的同步机制及优缺点 144. 什么是预编译,何时需要预编译? 145. int(*s[10])(int)表 ...

  2. 2023秋招大厂经典面试题及答案整理归纳(161-180)校招必看

    目录 161. MySQL 中 myisam 与 innodb 的区别. 162. 画出OSI和TCP/IP协议栈的对应关系. 163. 简述停止-等待协议(ARQ)的工作原理? 164. redis ...

  3. 2023秋招大厂经典面试题及答案整理归纳(1-20)校招必看

    目录 前言 1. 使用mysql索引都有哪些原则?索引什么数据结构? 1). 对于查询频率高的字段创建索引: 2). 对排序.分组.联合查询频率高的字段创建索引: 3). 索引的数目不宜太多 4). ...

  4. 【2023秋招大厂真题】携程校招-2022.9.28-k-好数组

    2023大厂真题提交网址(含题解): www.CodeFun2000.com(http://101.43.147.120/) 最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练 ...

  5. 【2023秋招大厂真题】科大讯飞校招-2022.10.14-奖品发放

    2023大厂真题提交网址(含题解): www.CodeFun2000.com(http://101.43.147.120/) 最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练 ...

  6. 【2023秋招大厂真题】华为校招-2022.10.11-字母加密

    2023大厂真题提交网址(含题解): www.CodeFun2000.com(http://101.43.147.120/) 最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练 ...

  7. 2023最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)

    近期总结一一些面试题 都是企业的面试题笔记题 感觉薪资10k-15k的常见面试题 个人录制的最新Vue项目学习视频:B站 小胖梅-的个人空间_哔哩哔哩_Bilibili 红色为常见面试题 ====== ...

  8. 2022年最新互联网大厂前端面试题及答案-前端工程必备技能(持续整理更新中【关注收藏不迷路】)

    对于做前端的朋友,或者做了前端几年了,基础不好的,或者想进大厂的想了解深入,下面的知识点很多前端朋友都没有深入了解.很重要,看完有种茅塞顿开感觉,**关注+收藏哦,总有一天用的得.** 涉及到知识点: ...

  9. 大疆秋招IBG后端笔试题 2023

    大疆秋招IBG后端笔试题 2023 题型 编程 计算时间差(Leetcode359) 最小偏移量(Leetcode1657) 题型 单选:20道:(不可修改答案好像,我没找到返回上一题的界面) 多选: ...

最新文章

  1. JVM 方法区 ORACLE官方文档
  2. Microsoft Dynamics CRM 2011 多客户端安装共用同一Sql Server 实例设置
  3. 题解 P4753 【River Jumping】
  4. Windows Phone开发(35):使用Express Blend绘图 转:http://blog.csdn.net/tcjiaan/article/details/7493010...
  5. new date.gettime 与传入时间相差毫秒数不对_给女票解释为什么日本时间比中国时间快一个小时?...
  6. 查看修改MySQL字符集
  7. 算法—快速排序Sqrt (C语言)
  8. 第一阶段 07类与对象
  9. 解决win10系统下,git Bash闪退的问题
  10. 微软计划Windows 7 SP2开发
  11. oracle外表日期,三步教会你掌握oracle外表(external table)
  12. ASP.NET MVC应用程序把文字写在图片上
  13. 计算机网络考试卷2014B答案,计算机网络考试卷2014B
  14. 终结者:HTTPS在Tomcat中的使用(三)——Java代码生成密钥库文件及其对应的安全证书
  15. 《剑指offer》面试题46、47、49
  16. 【Spring揭秘】Spring简介
  17. 南京邮电大学《管理学原理C》2019/2020 学年第 2 学期期末试卷
  18. 【Microsoft Azure 的1024种玩法】三十四.将本地数据文件快速迁移到Azure Blob云存储最佳实践
  19. 如何创建对电脑屏幕的自动点击的脚本
  20. 用芯弹一首《大加洛普舞曲》:从AI-ISP,透视vivo的双芯之路

热门文章

  1. html鼠标手状态,css鼠标样式cursor介绍(鼠标手型)
  2. 大数据分析R语言RStudio使用教程
  3. 家居行业数字化建设解决方案
  4. 在浏览器中打开“只能用微信内置浏览器”打开的页面
  5. HTTP 错误 404.2 - Not Found 由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面。
  6. JAVA中多态的理解
  7. ENSP实验七——RIP的基本配置
  8. java 配置文件加密_Java在配置文件中加密密码?
  9. C++学生管理系统课程设计
  10. 有关java多态性的介绍