一直走,一直走……

直到世界尽头。


  • Home

  • Archives

  • Tags
一直走,一直走……

win10中Oracle数据库显示中文乱码

Posted on 2016-12-20 | In C#

win10安装oracle数据库显示中文乱码

win10中oracle数据库显示中文乱码,都是??。

小注:没有想到有生之年也会有机会用oracle数据库😝。

中文显示乱码,十有八九是编码有问题。

解决方法:

  1. 开始-运行-输入regedit-回车进入注册表,依次单击HKEY_LOCAL_MACHINE—>SOFTWARE
    —> ORACLE—>KEY_OraDb11g_home1(不同版本的Oracle显示的都不太一样,但都会包含home这个单词),找到“NLS_LANG”,查看数值数据是否为:“SIMPLIFIED CHINESE_CHINA.ZHS16GBK”,如果不是就将它设置为“SIMPLIFIED CHINESE_CHINA.ZHS16GBK”。
  2. 设置完注册表后,接下来设置我们的环境变量,计算机(右键)—>属性—>高级系统设置—>高级—>环境变量—>新建,个人建议新建用户变量,变量名输入:“NLS_LANG”,变量值输入:“SIMPLIFIED CHINESE_CHINA.ZHS16GBK”,再点击确定即可。
  3. 重新启动PL/SQL后,显示正常。

有时候重装系统(比如我)后发现,注册表中没有oracle文件夹,看看在Wow6432Node文件夹是否有,如果还没有,只能自己手动创建1和2的过程,问题同样解决。

一直走,一直走……

KMP算法

Posted on 2016-12-19 | In C

KMP算法是字符串算法中经典的算法之一,本文仅作记录理解之用,其中有参考《严书》和他人博客,建议先看《严书》。

1. KMP算法的由来

KMP算法是解决字符串匹配问题。

问题:字符串匹配,一个主串,一个模式串,模式串是否在主串中,如果在,求出第一个字符的下标。

正常解法: 一个字符一个字符比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//s是主串,p是模式串,返回模式串在主串中的起始下标,如果不存在,返回-1
int get_substring(char *s, int slen, char *p, int plen)
{

int i = 0;
int j = 0;
int index = -1;
for (; i <= slen - plen; i ++) {
int mov = 0;
while (mov < plen && s[i + mov] == p[j + mov])
++ mov;
if (mov == plen)
index = i;
}
return index;
}

严书的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//返回模式串P在主串S中第pos个字符之后的位置,若不存在,返回-1
//C中是没有string类型的,这里为了简便
int index_substring(char *s, char *p, int pos)
{

int i = pos;
int j = 0;
int slen = strlen(s);
int plen = strlen(p);
while (i < slen && j < plen) {
if (s[i] == p[j]) {
++ i;
++ j;
} else {
i = i - j + 1;
j = 0;
}
}
if (j == plen)
return i - j;
else
return -1;
}

这种方法太低效,时间复杂度接近O(n * m),所以,是否可以利用已经部分匹配的信息,减少回溯的次数,让模式串尽可能快速移动到合适的位置。

那么,问题来了, 当主串的指针i和模式串的指针j不匹配时,模式串的指针j应该移动到哪个位置?

于是,KMP算法就有了。

2. KMP算法

先介绍Next数组的含义。

2.1 next数组的含义

next[j] = k,当主串的指针i和模式串的指针j不匹配时,模式串的指针j应该移动到指针k,主串指针i不需要回溯。

先举个例子,明白next[j] = k等式的含义。

next[j] = k,k的含义指模式串的前k个字符和其最后的k个字符相同(下标从0开始)。

KMP图

2.2 理解next数组的正确

主串用T[i]表示,模式串用P[j]表示,下标从0开始。

从严谨角度来看,请参考《严书》的数学归纳法证明。

本文以理解为主。

1
2
3
4
5
当 T[i] != P[j]时,
有 T[i-j ~ i-1] == P[0 ~ j-1]
已知 P[0 ~ k-1] == P[j-k ~ j-1]
再把j修改为k,则有 T[i-k ~ i-1] == P[0 ~ k-1], 所以主串的指针i和模式串的指针k比较,
结果是:主串的指针i不需要回溯,模式串的指针j回溯到指针k,而不是回溯到第一个。

2.3 如何求出next数组

求出过程,是数学归纳法,也是递推过程。

当j=0时,即模式串中第一个不匹配时,有next[0] = 0; 我们先不管初始条件,否则容易乱。

假设当next[j] = k,next数组含义知有,P[0 ~ k-1] == P[j-k ~ j-1]。

那么next[j+1]是?:sweat_smile:

​ 分为两种情况:

  1. 当p[k] == p[j]时,有P[0 ~ k-1~k] == P[j-k ~ j-1~j],则有next[j+1] = k+1 = next[j] + 1;
  2. 当p[k] != p[j]时,这又是一个字符串匹配问题,整个模式串既是是主串又是模式串,应当将模式串中P[j]和P[next[k]]比较,由已知得,有next[k] = m,当p[j] == p[m],则有P[j-m+1 ~ j] = p[0 ~ m],即next[j+1] = m + 1 = next[k] + 1;当p[j] != p[m]时,依次类推,最后next[j+1] = 0(j >= 0);

最后,我们来看初始条件。有next[1] = 0,显然当模式串中第一个字符和主串的字符不匹配时,是应该从下标0开始比较。在求解next数组过程中,有公式next[j+1] = next[j] + 1,所以,next[0] = -1,也就是说,初始条件是,j = 0,k = -1。

根据求next数组的递推关系,求next数组的递归代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
//递归代码, arr是next数组
void next(int arr[], int index, char *p)
{

if (index == 0)
arr[index] = -1;
else {
int tmp = arr[index - 1];
if (p[index -1] == p[tmp])
arr[index] = tmp + 1;
else
next(arr, index - 1, p);
}
}

求next数组的非递归代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
//非递归代码
void get_next(int arr[], int len, char *p)
{

int j = 0;
int k = -1;
next[0] = -1;
while (j < len) {
if (k == -1 || p[j] == p[k])
arr[++ j] = ++ k;
else
k = next[k];
}
}

2.4 改进的next数组

2.3中求next数组存在另外的问题,比如主串s ‘aaabaaaab’和模式串p ‘aaaab’,next数组值如下,

j 0 1 2 3 4
模式 a a a a b
next[j] -1 0 1 2 3
nextval[j] 0 0 0 0 4

当i = 3,j = 3时,主串和模式串不匹配,根据求出的next数组,仍然会依次比较i = 3,j = 0、1、2,实际上因为p[0] == p[1] == p[2],是不需要再进行比较的,所以改进的next数组nextval。

求nextval数组的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void nextval(int arr[], int len, char *p)
{

int j = 0;
int k = -1;
arr[0] = -1;
while (j < len) {
if (k == -1 || p[j] == p[k]) {
if (p[j + 1] == p[k + 1])
nextval[++ j] = nextval[++ k];
else
nextval[++ j] = ++ k;
} else {
k = nextval[k];
}
}
}

【未完待续】

3. 参考

[1] http://www.cnblogs.com/tangzhengyue/p/4315393.html

[2] 严书《数据结构》

一直走,一直走……

MVC+C#+DevExpress

Posted on 2016-10-05 | In C#

主要是总结最近写过的代码和用过的工具。

  1. MVC
  2. C#
  3. DevExpress(gridview)

1. MVC

这里的MVC,特指ASP.net MVC

  1. Model:一组类,描述一组要处理的数据和处理规则,也就是操作对象;
  2. View:定义显示给用户的程序界面;
  3. Controller:一组类,响应用户的输入,读取Model中的数据,将对应的View返回给用户。

参考:

[1]《ASP.NET MVC5 高级编程 第五版》

[2] 快速了解mvchttps://www.asp.net/mvc/overview/getting-started/introduction/adding-a-view

1.1 MVC中Razor的语法

关键是@

参考:

[1] https://www.asp.net/web-pages/overview/getting-started/introducing-razor-syntax-c

1.2 viewdata

在controller和view之间传递数据

1.2 gethtml和render的用法

在Razor Views中使用DevExpress插件会用到。

You can declare DevExpress extensions within View pages by using either expression syntax (@ or @()) or code block syntax (@{}). (参考[在view中使用DevExpres][1])

参考:

[1]:Using Extensions in Razor Views

[2] https://www.devexpress.com/Support/Center/Question/Details/Q388623

1.3 Html.RenderPartial和Html.Partial

Partial辅助方法用于将部分视图渲染成字符串。

RenderPartial辅助方法与partial非常相似,但RenderPartial不是返回字符串,而是直接写入响应输出流。因此,必须把RenderPartial放入代码块中,而不能放在代码表达式中。

以下是用法的不同:

@{ Html.RenderPartial(“test”); }

@Html.Partial(“test”);

一般而言,选择partial,因为partial更方便,不需要大括号(参考书给出这样的解释也是醉了),另外RenderPartial效率高(何以见得?)。

Html.Action和Html.RendRenderAction的区别:

Html.Action:执行单独的控制器操作,将控件嵌入到View中;

Html.RendRenderAction:调用Controller中的Action方法,并将返回的结果直接显示在当前调用的view中。

参考:

[1] ASP.NET MVC5高级编程(第五版)

2. C#部分用法

2.1 泛型

类似于C++中的模板,常用的两种泛型:

  1. List
  2. Dictionary

2.2 反射

表示简单用过,获取一个类中的自定义特性

2.3 Linq(Language Integrated Query)

Linq查询表达式,必须以from子句开头,以select或group子句结束。

参考:

[1] 《C#入门经典 第六版》

[2] 《C#高级编程 第七版》

3. DevExpres

3.1 GridView和FormLayout

GridView使用,可参考官网的demo,DevExpress GridView的使用demo

GridView自带默认的表格显示方式

  1. 在controller中设置GridView的显示效果。
1
2
3
4
5
6
7
8
9
10
public override GridViewSettings GetGridViewSettings(HtmlHelper helper) {
//设置表格中每一列的显示
settings.Columns.Add(c =>
{
c.FieldName = "name";
c.Caption = "名字";
c.ColumnType = MVCxGridViewColumnType.TextBox;
c.CellStyle.HorizontalAlign = HorizontalAlign.Center;
});
}
  1. 在对应的View的cshtml文件中,使用FormLayout,设置添加、编辑时的显示效果。
1
2
3
4
5
6
7
8
9
@{Html.DevExpress().FormLayout(formLayoutSettings => {
formLayoutSettings.Items.Add(itemSettings =>
{
itemSettings.Caption = "名字";
itemSettings.FieldName = "name";
itemSettings.NestedExtensionType = FormLayoutNestedExtensionItemType.TextBox;
TextBoxSettings textBoxSettings = (TextBoxSettings)itemSettings.NestedExtensionSettings;
});
}
  1. GridView常用的几个方法

    新增行: grid.AddNewRow();

    获取行索引:grid.GetFocusedRowIndex();

    编辑行: grid.StartEditRow(index);

    获取行主键:grid.GetRowKey(grid.GetFocusedRowIndex());

    参考:http://www.cnblogs.com/allenlf/p/4171189.html

  2. 删除等操作执行后,用户可以看到反馈。

    ASPxGridView1.JSProperties.Remove(“cpMsg”);

    ASPxGridView1.JSProperties.Add(“cpMsg”, “删除成功”);

    注意:按Dev控件约定,此处添加JSProperties,只能以 cp为前缀。(再补充)

  3. ​

3.2 callback方法的使用

不局限于GridView,任何带有callback方法的控件,比如callbackpanel、comboBox等。

首先,callback什么时候用。

一个是高效显示或者更新控件内容(减少初始化时传递的数据),一个是执行需要较长时间的操作(如文件上传等)。

其次,callback怎么用。

一个控件以callback模式使用的要求:

  1. 这个控件定义在一个独立的部分视图中;
  2. 一个controller中定义一个方法处理该控件的callback,并返回一个包含该控件的部分视图,这样可以根据终端用户的不同操作改变控件提供的内容;
  3. Callback的执行路径应该用callbackroutes来定义,这个属性允许为该控件指定对应的controller和action。

参考:

[1] callbacks简介 https://documentation.devexpress.com/#AspNet/CustomDocument9052

[2] callbacks传递参数 https://documentation.devexpress.com/#AspNet/CustomDocument9941

[3] callbackpanel的使用 https://documentation.devexpress.com/#AspNet/CustomDocument9000

3.3 clientsideevents事件

控件自带客户端事件,比如combobox、textbox等都有,提供对用户操作的支持。

  1. 注册事件;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Html.DevExpress().Menu(
    settings =>
    {
    settings.Name = "menu1";
    settings.EnableClientSideAPI = true;
    settings.Items.Add("Visa");
    settings.Items.Add("MasterCard");
    settings.ClientSideEvents.ItemClick = "MenuItemClick";
    }).GetHtml()
  2. 用js方法来响应用户注册的事件;

    1
    2
    3
    4
    5
        <script type="text/javascript">
            function MenuItemClick(s, e) {
                textBox1.SetText(e.item.GetText());
            } 
    </script>

    js方法中两个参数,s是注册该事件的控件,e是该事件的参数。

  3. 控件的ClientInstanceName,这样就可以在前端操作对应的dev控件;

参考:

[1] https://documentation.devexpress.com/#AspNet/CustomDocument9150

[2] https://documentation.devexpress.com/#AspNet/CustomDocument9448

一直走,一直走……

C++的精髓 虚函数

Posted on 2016-06-10 | In C++

1. 虚函数的作用

为了实现多态,引入虚函数。
那什么是多态?
一言以蔽之:多态是指同一个方法在派生类和基类中的行为是不同。
或者说:多态是指使用相同的函数名来调用函数不同的实现方法,即“一种接口,多种方法”。

C++实现多态的方法有两种:

  • 编译时多态:通过函数重载实现(静态联编)
  • 运行时多态:通过虚函数实现(动态联编)

2. 虚函数的定义和使用

在基类中定义虚函数:

class Student 
{
    char name[50];
public:
    virtual void show_name();    /* virtual修饰的函数就是虚函数 */
}

使用虚函数:

当函数是通过引用或者指针而不是对象调用的,这时需要注意:

  • (1)如果该方法没有使用关键字virtual,程序将根据引用类型或指针类型选择函数;
  • (2)如果使用了virtual,程序将根据引用或指针指向的对象的类型来选择函数。

3. 虚函数的工作原理

编译器处理虚函数的方法是:
给每个对象添加一个隐藏成员(取该对象占的内存空间不确定是否会看到?),隐藏成员中保存了一个指向函数地址数组的指针。该函数地址数组成为虚函数表(virtual function table, vtbl)。虚函数表中保存着类对象声明的虚函数的地址。

一个基类对象,该对象包含一个指针,指向保存基类中所有虚函数地址的地址表vtbl1;
一个派生类对象,该对象包含一个指针,指向保存派生类中所有虚函数地址的地址表vtbl2;
如果派生类提供了虚函数的新定义,则虚函数地址表中保存新的地址;如果派生类定义了新的虚函数,则新函数的地址也要加入到vtbl2中。

调用虚函数时:
程序查看对象中vtbl地址,然后转向相应的函数地址表中,再找到调用的虚函数地址,执行该虚函数。
虚函数表中地址的顺序:

  • 虚函数按照其声明顺序放于表中
  • 父类的虚函数在子类的虚函数前面

最好能写程序验证一下。

4. 虚函数的代价

使用虚函数,在内存和执行速度方面有一定的成本:

  • (1)每个对象实际占的空间增大,增大量是存储地址的空间;
  • (2)对于每一个类,编译器都需要创建一个虚函数表;
  • (3)对于每个函数调用,都需要执行一项额外的操作,即表中查找地址。(主要是因为虚函数是动态联编,非虚函数是静态联编,则不要额外的操作)

5. 虚函数相关注意事项

5.1 构造函数

构造函数不能是虚函数.

5.2 析构函数

析构函数应该是虚函数,除非类不用做基类。
通常会给基类提供一个虚析构函数,即使它并不需要析构函数。

6. 虚函数与纯虚函数的区别

  • (1)虚函数可以被直接使用,也可以被子类重载以后以多态的形式调用,而纯虚函数必须在子类中实现该函数才可以使用,因为纯虚函数在基类只有声明而没有定义;
  • (2)虚函数和纯虚函数都可以在子类中被重载,以多态的形式被调用;
  • (3)定义不同
    • 虚函数定义:virtual func() {method body} ;
    • 纯虚函数定义:virtual func() = 0;
  • (4)含有纯虚函数的类才能称为抽象类。

参考资料

[1] 《C++ prime plus》第六版
[2] 《C++ prime plus》第五版
[3] http://blog.csdn.net/wuchuanpingstone/article/details/6742465
[4] http://www.cnblogs.com/bluestorm/archive/2012/08/29/2662350.html 虚函数和纯虚函数区别

一直走,一直走……

hexo+github搭建个人博客

Posted on 2016-06-08

1. 安装hexo

安装过程:

$sudo npm install -g hexo
$hexo init blog    /* blog指你自己命名的文件夹 */
$cd blog
$npm install    /* 安装依赖包 */
$hexo server 或者 hexo s    /* 启动hexo */

验证hexo启动成功

在浏览器地址栏输入localhost:4000,看到Hexo的hello world,编程初学一般都是hello world。
注意:hexo server现在不能control+c停止掉

2. 开始写一个post测试一下

现在hexo已经安装好,我们来测试一下吧。

$hexo new "博文的名字"

刷新http://localhost:4000/,可以发现已生成一篇新文章 “博文的名字”

3. 部署到github上

创建SSH key

查看是否有id_rsa.pub文件

ls -a ~/.ssh/

如果没有SSH key,参考[2]生成新的SSH key。

设置github SSH key

在github账号中添加key,登陆GitHub->Settings->SSH and GPG keys,然后,点“New SSH Key”,任意起一个Title,在Key文本框里粘贴id_rsa.pub文件的内容,点“Add Key”。
这里我遇到一个问题:

vim打开id_rsa.pub文件,粘贴复制,报错:
key is invalid. Ensure you've copied the file correctly.

解决方法是:

cat命令输出~/.ssh/id_rsa.pub内容到终端,再拷贝,添加成功。

参考 github add SHH key failed

创建github库

登录你的Github帐号,新建仓库,仓库名为用户名.github.io固定写法,一定要和用户名相同。

修改_config.yml文件

修改如下:

deploy:
 type: git
 repository: https://github.com/用户名/用户名.github.io.git
 branch: master

验证成功

在hexo init的目录下依次执行:

$hexo generate或者hexo g  
$hexo deploy或者hexo d

两步也可以合成:hexo d -g
再在浏览器输入:http://user_name.github.io,可以看到你的博文了。
如果hexo deploy报错,解决方法是:

$npm install hexo-deployer-git --save

4. 更换主题

参考[2]介绍更换主题的过程,并推荐了几种选择的主题。

$git clone https://github.com/iissnan/hexo-theme-next themes/next
修改_config.yml文件
$hexo clean
$hexo generate
$hexo deploy

就这么几步,主题就更换成功了。

5. 创建分类页面

发现没有分类页面,创建:

$hexo new page categories    /* create a new page */
$vim index.md        /* edit the tyep is categories */
编辑themes/next/_config.yml文件,添加categories

6. 参考博文

[1] https://hexo.io/docs/deployment.html
[2] http://www.jianshu.com/p/13e64c9e2295
[3] http://www.cnblogs.com/zhcncn/p/4097881.html
[4] http://blog.csdn.net/wwj_748/article/details/45896373
[5] http://jingyan.baidu.com/article/d8072ac47aca0fec95cefd2d.html

Xiangchao Zeng

Xiangchao Zeng

长亭外,古道边,送君千里,终有一别。

5 posts
3 categories
4 tags
© 2016 Xiangchao Zeng
Powered by Hexo
Theme - NexT.Muse