x的幂函数求导过程
课程出处
P16 常用求导公式 -《高等数学》同济版 全程教学视频(宋浩老师)
视频中 22分钟处有一个关于 x的u次幂求导公式,其中证明步骤跳过了后面的步骤,当时看的时候有些疑问,经过一些尝试总算得出有效递推过程。
当时的疑问主要是 第二行的部分 h/x 既然趋向于0 那么 (1+0)的u次方 - 1 也趋向于零,所以结果应该是0
课程出处
P16 常用求导公式 -《高等数学》同济版 全程教学视频(宋浩老师)
视频中 22分钟处有一个关于 x的u次幂求导公式,其中证明步骤跳过了后面的步骤,当时看的时候有些疑问,经过一些尝试总算得出有效递推过程。
当时的疑问主要是 第二行的部分 h/x 既然趋向于0 那么 (1+0)的u次方 - 1 也趋向于零,所以结果应该是0
谭浩强 C++程序设计(第三版)P189 第16题
输入一个字符串,内有数字和非数字字符,如
a123x456_17960?302tab5876
将其中连续的数字作为一个整数,依次存放到一个数组a中。统计总共有多少个整数,并输出这些数。
这个问题是比较好解决的,主要是三步
开辟一个 int a[(n+1)/2]; 大小的整数数组a,(n+1)/2 是字符串中能够包含的至多个整数了。
初始化一个数字统计 int total = 0;,用来累计出现过的数字总数。
遍历字符串,比对是否是数字,如果是 压入栈中,如果不是,将栈逐步清空并将取出的若干个数字计算为十进制数,其中每次出栈,将进制+1,则可以顺利求出。
每次得出一个新整数,total++。
以total为终,遍历a并输出。
#include <iostream>
#include <stack>
using namespacing std;
int getNumberFromStack( stack &s ){ // 传递引用
int level = 1;
int number= 0;
while( !stack.empty() ){
number += stack.top() * level;
stack.pop();
level *= 10;
}
return number;
}
int main(){
string s;
cout << "请输入一个字符串,如a123x456_17960?302tab5876。\n";
cin >> s;
int a[ (s.size() + 1)/2 ];
int total = 0;
stack<int> numberStack;
for( unsigned int i =0; i< s.size(); i++ ){
if( s[i]<='9' && s[i]>='0' ){
numberStack.push( s[i]-0 );
}else if( !numberStack.empty() ){
a[total++] = getNumberFromStack( numberStack );
}
}
// 输出全部数字
for( int k=0; k < total; k++ ){
cout << a[k] << "\n";
}
return 0;
}
复杂度O(n)
template <class T>
void chain<T>::theSize( int n ){
chainNode<T> current = firstNode();
int i=0, max = _size < n ? _size : n;
// 由于不是双向链表,所以需要先到达n的极点
while( i < max ){
current = current->next();
i++;
}
chainNode<T> tmp;
// 如果有多余的
while( _size > n ){
tmp = current->next();
delete current; // 系统会执行element析构
current = tmp;
}
_size = n;
}
复杂度O(n) 在实际使用的时候,链表一般不用index表示法来获取或设置元素。因为每次都相当于O(n)的复杂度。
template <class T>
void chain<T>::checkIndex( int theIndex ){
if( theIndex <0 || theIndex >= _size ){
throw illegalIndex("Out of range");
}
}
template <class T>
void chain<T>::set( int theIndex, T& theElement ){
checkIndex(theIndex);
chainNode<T>* current = firstNode();
int i = 0;
while( i < _size ){
current = current->next();
}
current->element.~T(); // 析构
current->element = theElement;
}
复杂度O(n) 和上面的setSize类似,做一次遍历,之后将切割掉的部分接起来即可。
template <class T>
void chain<T>::setSize( int fromIndex, int toIndex ){
checkIndex(fromIndex);
checkIndex(toIndex);
chainNode<T>* current = firstNode();
int i=0;
// fromIndex的极点
while( i < fromIndex ){
current = current->next();
i++;
}
chainNode<T>* tmp;
while( i < toIndex ){
tmp = current->next();
delete current; // 系统会执行element析构
current = tmp;
}
_size -= toIndex-fromIndex +1; // 考虑左右闭区间
}
复杂度O(n) 遍历元素并比对,不即时返回。
template <class T>
int chain<T>::lastIndex( T& theElement ) const{
if( empty() ) return -1;
chainNode<T>* current = firstNode();
int i = 0, lastIndex = -1;
while( i< _size ){
if( current->element == theElement ){
lastIndex = i;
}
current = current->next();
i++;
}
return lastIndex;
}
复杂度O(n) 实际上重载应该包含两种,分别是提供左值,右值返回。
template <class T>
const T& chain<T>::operator[](int n) const{ } // 右值
T& chain<T>::operator[]( int n) const{ // 左值
int i = 0;
chainNode<T>* current = firstNode();
while( i < n ){
current = current->next();
}
return current->element;
}
复杂度O(n) 同步遍历两个链表元素,一旦发现不同元素返回false。
template <class T>
bool chain<T>::operator==( chain<T>& c) const{
if( size() != c.size() ) return false;
chainNode<T>* current = firstNode();
chainNode<T>* target = c.firstNode();
int i = 0;
while( i < size() ){
if( current->element !== target->element ) return false;
current = current->next();
target = target->next();
}
return true;
}
复杂度O(n)
template <class T>
bool chain<T>::operator!=( chain<T>& c) const{
return !*this == c;
}
复杂度O(n) 略微需要注意的是,除了最后一项的值完全相等以外,其他的相等 都不能判断非<。 所以在遍历的靠前阶段,== 都应该算成功,只有最后一项相等判断非小于。
template <class T>
bool chain<T>::operator<( chain<T>& c) const{
if( size() > c.size() ) return false;
chainNode<T>* current = firstNode();
chainNode<T>* target = c.firstNode();
int i = 0;
while( i < size() ){
if( current->element > target->element ){
return false;
}else{
current = current->next();
target = target->next();
}
}
if( current->element == target->element ) return false;
return true;
}
1### 2. L = (a,b,c,d,e) ... 做图
初始状态:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|
| a | b | c | d | e |
insert(0,f)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|
| f | a | b | c | d | e |
insert(3,g)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|
| f | a | b | g | c | d | e |
insert(7,h)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|
| f | a | b | g | c | d | e | h |
earse(0)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|
| a | b | g | c | d | e | h |
erase(4)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|
| a | b | g | c | e | h |
二维数组的话要基于Array设计一个矩阵类,其中的每一行都是一个Array对象。
template <class T>
class ArrayMatrix: public Array{
void changeLength2D( int x, int len );
}
template <class T>
void ArrayMatrix::changeLength2D( int rowIndex, int len ){
checkIndex(x);
get(rowIndex).changeLength(len);
}
好像题目描述有问题。 我自己写的是提供一个是否自动扩容的参数。如果配置为不自动扩容则在超出的时候抛出异常。
enum class ARRAY_AUTO_CAPACITY
{
DISABLED = 0,ENABLED = 1
};
template <class T>
class Array{
public:
Array(int initCapacity = ARRAY_DEFAULT_CAPACITY, ARRAY_AUTO_CAPACITY autoCapacity = ARRAY_AUTO_CAPACITY::DISABLED);
void checkMax();
private:
ARRAY_AUTO_CAPACITY _autoCapacity = ARRAY_AUTO_CAPACITY::DISABLED;
}
template<class T>
inline void Array<T>::checkMax()
{
if (_size >= _capacity) {
switch (_autoCapcity)
{
case ARRAY_AUTO_CAPACITY::ENABLED:
changeCapacityTo(_capacity << 1);
break;
case ARRAY_AUTO_CAPACITY::DISABLED:
throw illegalInputData("Array is full.");
break;
default:
break;
}
}
}
实际上就是改变数组长度, 长度为size或1。 这里我基于我改写的 changeCapacityTo()来实现,实际上是一回事。
复杂度是O(n)
void trimToSize(){
changeCapacityTo( _size>0 ? _size : 1 );
}
template<class T>
inline void Array<T>::changeCapacityTo(int newCapacity)
{
T* newElements = new T[newCapacity];
_capacity = newCapacity;
_size = newCapacity < _size ? newCapacity : _size;
for (int i = 0; i < _size; i++)
{
newElements[i] = _elements[i];
}
delete[] _elements;
_elements = newElements;
}
这一题,同样题目描述是有问题的。 见上一题changeCapacityTo()
T& operator[]( int n){
checkIndex(n);
return _elements[n];
}
template<class T>
bool operator==( const Array<T>& targetArray ) const{
if( size()!= targetArray.size() ){
return false;
}
for( int i=0; i<size();i++ ){
if( get(i) != target.get(i) ){
return false;
}
}
return true;
}
template<class T>
bool operator!=( const Array<T>& targetArray ){
return !*this == targetArray;
}
见8 . 其中!= 替换为>
C++在使用的时候莫名的会出一些编译错误,有时候只是语法的特定写法不一致,所以记录一下。
const ARRAY_DEFAULT_CAPACITY = 8;
template <class T>
class Array{
Array( int capacity ); // 有效
Array( int capacity = ARRAY_DEFAULT_CAPACITY ); // 有效
}
// 错误, 不允许使用默认参数
template<class T>
Array<T>::Array( int initCapacity = ARRAY_DEFAULT_CAPACITY ){
...
}
// 使用上述定义
Array<float> arr(10) // 正确 容量为10
Array<float> arr(); // 错误 容量为默认长度 无法实例化
Array<float> arr; // 正确 容量为默认长度 可以实例化 C++ 几乎可以重载全部的运算符,而且只能够重载C++中已经有的。
· 不能重载的运算符:“.”、“.*”、“::”、“?:” · 重载之后运算符的优先级和结合性都不会改变。
可以重载为类的非静态成员函数; 可以重载为非成员函数。
++ -- *= +=...而后置的单目运算符是需要提供参数来区别前置(为了重载)的。
class Even{
int number=0;
public:
A & operator ++ (){
number +=2;
return *this;
}
A operator ++ ( int ){
int old = number;
++(number);
return old;
}
}
前置++ 返回的是左值,而后置++ 返回的只是一个右值。
+ - * % /...class Matrix{
int ** elements;
int sizeX;
int sizeY;
public:
Matrix & operator + ( const Matrix & m ) const{
int newX = m.getX() > this.sizeX ? m.getX() : this.sizeX;
int newY = m.getY() > this.sizeY ? m.getY() : this.sizeY;
Matrix _new(newX,newY);
for( int i = 0; i< newX; i++ ){
for( int j =0; j< newY; j++ ){
_new[i][j] = m[i][j] + elements[i][j];
}
}
return _new;
}
}
当需要对当前程序没有权限的类型进行操作符重载的时候,或是将不同类型重载到一起运算,都需要进行非成员函数重载。
重载时需要从左至右依次声明参与预算的各个参数
这个时候可以理解为以重载的形式写的常规函数。
非成员函数的重载操作符参数,不能全为普通类型。
c++在进行实例化的时候通常需要使用构造函数,没有显示构造函数的时候,系统会默认一个所有参数为空的默认构造函数。
C++中的构造函数有很多细节,其中从语法上来说,定义在函数声明的部分,是会优先于构造函数本身执行。 譬如说以下的两种方式,会有不同的效果。
class A{
int X;int Y;
public:
A( int x, int y ){
std::cout << X << std::endl;
X = x; Y = y;
}
}
class B{
int X;int Y;
public:
B( int x, int y ): X(x),Y(y){
std::cout << X << std::endl;
}
}
A,B都能分别完成对象的构造,区别在于B由于是在声明阶段定义了两个形式参数将要被放置到的对象属性中,所以A的构造函数不能在函数体内的第一行输出我们期望的值。而B中,X属性已经完成了初始化,可以顺利的输出我们的期望值。 另外由于省略了建立、销毁局部参数的过程,这种声明式的构造函数效率更好。
在派生类中使用构造函数时,需要同时构造基类的构造函数,如果同时继承多个基类,则需要依次构造基类。 在没有进行基类构造的时候,c++会默认使用基类的默认构造函数进行构造,但如果不满足这样的条件,就会报错。
class A{
int a;
public:
A( int a ):a(a){}
}
class B{
char b;
public:
B( char b ):b(b){}
}
class C : public A, public B{
bool c;
C( int a, char b, bool c ):A(a),B(b),c(c){}
}
这是一个最基本的多继承构造函数的形式。
有些时候我们可能会需要一些变种构造函数,也就是重载。譬如说当我们基于Matrix设计一个九宫格类的时候,实际上matrix的行和列都是固定的3x3.我们并不需要这两个参数来初始化。 这样的话,我们就可以使用单参数的形式重载九宫格类的构造函数:
template <typename T>
class sMatrix : public Matrix<T>{
private:
int _sign;
public:
sMatrix( int sign ): Matrix<T>(3,3), _sign(sign){ cout<< _sign << endl; }
sMatrix( int x, int y, int s ):Matrix<T>( x, y ){
cout << _sign << endl;
_sign = s;
cout << _sign << endl;
}
};
在C++中创建数组的时候需要声明数组的长度,在声明一个二维数组的参数时,则至少需要确认第二维的长度,否则就无法完成编译。 为什么呢,我们可以用一张图来表示c++二维数组在内存中的表示就理解了。

实际上在创建数组的时候,c++是根据最低维,也就是最靠后的那个维度最大值来分配连续内存空间的。譬如int[2][5]就会分配10*4个字节空间出来,如果不知道最后一个维度,c++就不知道如何开辟内存空间了。
二维数组返回的就是整个数组的首元素地址。 而访问则是根据最后维的长度进行运算后得出:
/*
* c++ 二维数组
*
* hello@shezw.com 2020.07.03
*/
#include <iostream>
#include <string>
using namespace std;
int main()
{
int a[2][5] = {1,2,3,4,5,6,7,8,9,10};
for( auto e:a ){
printf( "%p : %d \n",e,*e );
}
printf( "%p : %d \n",&a[1][3],a[1][3] );
printf( "%p : %d \n",&a[0][8],a[0][8] );
}
输出:
0x7fffa508a870 : 1
0x7fffa508a884 : 6
0x7fffa508a890 : 9
0x7fffa508a890 : 9
可以看到 a[0][8] 其实是完全等价于 a[1][3] 的,实际上a[1][3] 就是从第一个空间开始往后数第3+1*5 = 8个。
为了调用和使用方便,我这里设计一个Matrix模板类,专门用于这样的动态二维数组的使用。
/*
* c++ 二维数组
*
* hello@shezw.com 2020.07.03
*/
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Matrix{
private:
T ** _elements;
int _colSize;
int _rowSize;
public:
Matrix( int rows, int cols ){
_colSize = cols;
_rowSize = rows;
_elements = new T * [rows];
for( int i=0;i<rows;i++ ){
_elements[i] = new T [cols]();
}
}
~Matrix(){
for( int i=0;i<_rowSize;i++ ){
delete [] _elements[i];
}
delete [] _elements;
}
int getSize(){ return _colSize * _rowSize; };
int colSize(){ return _colSize; };
int rowSize(){ return _rowSize; };
// 函数形式
const T & get( int row, int col ){
return _elements[row][col];
}
// 重载操作符形式
T* & operator[]( int row ){
return _elements[row];
}
// 重载操作符形式 只读
const T* & operator[]( int row) const{
return _elements[row];
}
void print(){
for( int i=0; i< _rowSize; i++ ){
printf( "\n row %p: \n", _elements[i] );
for( int j=0; j< _colSize; j++ ){
printf( " col %p - %d\n", &_elements[i][j], _elements[i][j] );
}
}
}
};
int main()
{
Matrix<int> m(3,5);
m[2][1] = 15;
m.print();
}
早在一年多以前就对flutter有所耳闻,但是还没有真正去了解和跑过,今天看了flutter创始人的介绍,实际上感觉这个框架应该是会有web的影子,在随后看官方对于widgets介绍的时候,其实本质上也有点类似于div。 所以如果本身有一些web开发经验的小伙伴,想要上手flutter应该是比较简单的了。
# https://flutter.cn/docs/development/ui/widgets-intro
import 'package:flutter/material.dart';
void main() {
runApp(
Center(
child: Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
),
);
}
如果是web来说的话,就是以下内容
<style>
.Center{
display: flex;
align-items: center;
justify-content: center;
}
</style>
<div class="Center">
<span>Hello, world</span>
</div>
7plus买回来之后,后置摄像头就一直处于一种不稳定的状态,时而会出现黑屏的现象。 而在一个多月前的某天,终于他辞职不干了。再也不工作了。
由于疫情的原因,我也只能掏出我的压箱SE来使用,因为没有相机的手机在中国太难用了(相机=二维码),但是太久没有用过小屏幕手机,突然用回来,即使是我这个曾经对大屏嗤之以鼻的人来说,也还是太不适应了。
最近快递也逐渐可以有了,所以盘算着通过淘宝买一个镜头组件自己换一下,就和之前换SE的电池一样。 就在今天,镜头总算到货了,迫不及待的想要恢复我的手机拍照功能!
换完之后果然好使了,结果才没合上盖几分钟,摄像头附近就发烫的不行,用了一会相机也和之前一样不能打开了。 震惊之余去淘宝问商家是什么情况,商家只是表示排线没接好,让我重装,但是重装之后依然是这样的问题,甚至发烫死机。继续询问商家,此时商家的奸商本质暴露无遗,重复说让我去维修店检查,言外之意就是肯定和他摄像头无关了。
那这时候商家已经没有意义了,还是自己排查一下问题吧。
我首先想到,如果后置摄像头坏了影响机器,那我不使用后置摄像头呢? 于是拆除后置摄像头排线,开机检测,正常。 相机可以切换到前置,微信扫一扫会自动调用前置摄像头,并且扫码,识别功能都是正常的。
如果单独前置没有问题,那么再测试一下单独后置摄像头吧,遂拆除前置摄像头组排线,开机测试,竟然一样正常。 到了这一步,我突然想到,如果刚才不能使用的后置摄像头恢复了使用,何不把我的原装摄像头单独放上去试一试呢?
结果出人意料,这个辞职了一个多月的摄像头竟然复工了! 考虑到不想在这件事上花费太多时间,于是将外壳装好,最后的最后,最让我惊讶的事情发生了。 拆除了前置摄像头组件排线的iPhone7plus 不再无端发热了!
目前单独后置摄像头功能一切正常。没有明显的无端发热情况。 等待后期继续考察。
``最早的时候博客是使用的WordPress搭建,基于一些原因( 使用Typecho搭建一个极简又好用的技术博客 ),去年选择了用typecho重做。
重构博客之后的很长一段时间都没有去看搜索引擎的收录状态,最近发现在百度、搜狗都只有一个首页收录,但是bing是有大量收录的。而这在以前WordPress搭建时不可能出现的,所以开始着手解决一下。
参考: 浅谈typecho百度收录问题
什么是循环?
循环就是反复的做一件事情,尽管每次都可能一模一样 也有可能略有差别。 无论是打扑克、还是打麻将,其实都是符合循环这个概念。
譬如说,打斗地主的时候我们每次都要不停的从牌堆中抓一张牌,大家分别取一张,直到牌堆里的牌只剩3张。
每一次的抓牌就是循环的一个过程。
那么for循环和while循环的差别是什么呢?
如果用女人可以理解的方式来说的话,那么
for循环是 曾经有一份真诚的爱情放在我的面前....... 我希望是 10000年
while循环是 山无棱、天地合,乃敢与君绝
正则表达式的重要性不言而喻,平时写的时候都是拼拼凑凑感觉还是不太好,趁着今天做一个梳理,要让正则的用法深入血液才好。
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
创建一个正则表达式节
你可以使用以下两种方法之一构建一个正则表达式:
使用一个正则表达式字面量,其由包含在斜杠之间的模式组成,如下所示:
var re = /ab+c/;
使用正则表达式字面量为正则表达式提供了脚本加载后的编译。当正则表达式保持不变时,使用此方法可获得更好的性能。
或者调用RegExp对象的构造函数,如下所示:
var re = new RegExp("ab+c");
使用构造函数为正则表达式提供了运行时的编译。使用构造函数的方式,当你知道正则表达式的模式将会改变,或者你不知道模式,并且从其他来源获取它,如用户输入。
最近回复