一.昨日回顾
静态成员,必须在类外以 类名::成员名 定义
静态成员函数(无this)
const成员函数:this为const指针,仅能调用const成员函数
二.04作业
1.单例模式
class sp{
static sp* _sp;
sp(){};
public:
int data=0;
static sp* get_one_sp(){
if(!_sp)_sp=new sp();
return _sp;
}
};
sp* sp::_sp=nullptr;
int main()
{
std::cout << "Hello world" << std::endl;
sp* sp1=sp::get_one_sp();
sp* sp2=sp::get_one_sp();
cout<<sp1<<" kaichong "<<sp2<<" data="<<sp1->data<<endl;
return 0;
}
2.重温栈/队列/带头节点循环链表
带头结点循环链表比较繁琐:
#include <iostream>
using namespace std;
struct Node
{
int data=0;
Node * pre=nullptr;
Node * next=nullptr;
};
class List
{
Node * _head;
Node * _tail;
int _size;
Node * find(Node * p) //如果存在,就返回该节点;不存在,就返回空指针
{
if(!_size){
cout<<"empty list"<<endl;
return nullptr;
}else{
auto first=_head->next,cur=_head->next;
while(cur!=p){
cur=cur->next;
if(cur==first){
cout<<"no matching Node"<<endl;
return nullptr;
}
}
cout<<"data first address="<<cur<<endl;
return cur;
}
}
Node * insert(Node *p)
//确定节点存在时,在该节点前一位置直接插入元素
{
auto tmp=new Node;
if(p==_head->next){
tmp->next=_head->next;
_head->next=tmp;
_tail->next=tmp;
tmp->pre=_tail;
}else{
tmp->pre=p->pre;
tmp->next=p;
p->pre->next=tmp;
p->pre=tmp;
}
_size++;
return tmp;
}
void erase(Node *p) //删除一个指定的节点
{
if(_size==1){
_head->next=nullptr;
_tail=nullptr;
}else if(p==_head->next){
_tail->next=p->next;
p->next->pre=_tail;
_head->next=p->next;
}else if(p==_tail){
_tail=p->pre;
_tail->next=p->next;
p->next->pre=_tail;
}else{
p->next->pre=p->pre;
p->pre->next=p->next;
}
delete p;
_size--;
}
public:
List():_head(new Node()),_tail(nullptr),_size(0){}
~List(){
if(_size){
Node* first=_head->next,*tmp=nullptr;
while(first!=_tail){
tmp=first->next;
delete first;
first=tmp;
}
delete _tail;
}
}
void push_back(int value)//在尾部添加数据
{
if(!_tail){
_head->next=new Node;
_tail=_head->next;
_tail->data=value;
_tail->pre=_tail;
_tail->next=_tail;
_size++;
}else{
auto tmp=new Node;
tmp->pre=_tail;
tmp->next=_head->next;
tmp->data=value;
_tail->next=tmp;
_head->next->pre=tmp;
_tail=tmp;
_size++;
}
}
void push_front(int value)//在头部添加数据
{
if(!_tail){
_head->next=new Node;
_tail=_head->next;
_tail->data=value;
_tail->pre=_tail;
_tail->next=_tail;
_size++;
}else{
auto tmp=new Node;
tmp->pre=_tail;
tmp->next=_head->next;
tmp->data=value;
_tail->next=tmp;
_head->next->pre=tmp;
_head->next=tmp;
_size++;
}
}
void pop_back()//在尾部删除一个数据
{
if(!_size){
cout<<"empty list"<<endl;
}else if(_size==1){
delete _tail;
_tail=nullptr;
_head->next=nullptr;
_size--;
}else{
auto tmp=_tail;
_tail=tmp->pre;
_head->next->pre=_tail;
_tail->next=_head->next;
delete tmp;
_size--;
}
}
void pop_front()//在头部删除一个数据
{
if(!_size){
cout<<"empty list"<<endl;
}else if(_size==1){
delete _tail;
_tail=nullptr;
_head->next=nullptr;
_size--;
}else{
auto tmp=_head->next;
tmp->next->pre=_tail;
_tail->next=tmp->next;
_head->next=tmp->next;
delete tmp;
_size--;
}
}
void insert(Node *p, int value)//在某个节点之前添加数据, 还需要判断该节点在不在链表之中
{
auto tmp=find(p);
if(!tmp){
cout<<"insert fail"<<endl;
}else{
insert(tmp)->data=value;
}
}
void erase(int data)//需要判断该节点在不在链表之中
{
auto tmp=find(data);
if(!tmp){
cout<<"insert fail"<<endl;
}else{
erase(tmp);
}
}
void display() const//打印链表
{
if(!_size){
cout<<"empty list"<<endl;
return;
}else{
auto first=_head->next,cur=_head->next;
while(1){
cout<<cur->data<<endl;
cur=cur->next;
if(cur==first){
cout<<"end of list"<<endl;
break;
}
}
return;
}
}
Node* find(int data){
if(!_size){
cout<<"empty list"<<endl;
return nullptr;
}else{
auto first=_head->next,cur=_head->next;
while(cur->data!=data){
cur=cur->next;
if(cur==first){
cout<<"no matching data"<<endl;
return nullptr;
}
}
cout<<"data first address="<<cur<<endl;
return cur;
}
}
};
int main()
{
std::cout << "Hello world" << std::endl;
List l;
l.push_back(111);
l.push_back(112);
l.push_back(113);
l.push_back(114);
l.pop_front();
l.display();
l.insert(l.find(113),8882);
l.pop_front();
l.display();
return 0;
}
三.机器学习
回顾:正规方程解法与多元梯度下降法均有价值,使用正规方程的变量数量上限经验值为10000个features
4.7 矩阵不可逆时使用正规方程解法
octave内包含pinv(伪逆函数)与inv,而pinv即使对不可逆矩阵仍能得出正确解
不可逆的原因:
1.包含多余特征(线性相关)
2.包含过多特征(相对于样本数量),如10个样本/100个特征
需要删除某些特征或正规化
6.1 logistic regression algorithm
一种classification算法,并不是回归问题算法,约等于sigmoid function
6.3 决策边界
g(z)即为sigmoid function
决策边界概念:
6.4 选择与拟合cost function中的参数θ
目的:使J(θ)成为一个凹函数(convex),从何可通过梯度下降求极值
通过y不同值时的不同代价函数,使其为凸函数
6.5 简化代价函数与梯度下降
y=0/1两种情况合为一个表达式
极大似然法得到
同样的表达式,但属于不同算法,但用于监测梯度下降的方法一样可以应用:迭代次数与J(θ)大小的图像等
6.6 高级优化
共轭梯度法:不需要指定α,智能内循环:线搜索算法
6.7 多元分类/一对多
三元分类问题->三个独立的二元分类问题->每个伪训练集,只有两个类
选择三个分类器中输出结果概率最高/最可靠的结果作为输出
7.1 正则化:过拟合
虽然高度拟合training set,但有过高方差,泛化差,并非合适的模型
方法:去除部分变量->减少可能有用的信息
正则化/改变θ量级->保护信息完整性
7.2 正则化:代价函数
使部分θ数量级很小/惩罚部分参数增大带来的效果
代价函数中添加正则化项使除theta0以外的参数被放缩,正则化参数的选择很重要
7.4正则化的梯度下降法与正规方程法
对梯度下降法,theta0不变,其余theta参数有所变化
对正规方程法只要λ>0;则必有矩阵可逆
7.4 正规方程法及其高级优化方法的正则化
正则化逻辑回归
正则化的优化算法/仍需提供代价函数,再次强调octave中theta下标从1开始到n+1