讲起RIP路由协议,难免会有轻视之心,因为他配置命令简单,容易上手,只要是学习过网络技术的朋友,几乎没有不会RIP协议的基本配置的。然而,当深入到RIP协议的一些关键问题的时候,却发现原来RIP也有很深的门道,比如说:RIPv1在什么情况下会携带子网掩码进行路由的更新?RIPv2又如何在汇总掩码小于主类网络的掩码的时候进行手工的汇总?
今天我却要对RIP协议解析进行深度的剖析,揭开RIP中v1和v2两个兄弟的神秘面纱。
首先,明确几个关键的问题:
一 RIP V1 V2分属有类网络和无类网络?他们的区别在哪里?
二 RIP属于距离矢量路由协议?它又和链路状态路由协议有和区别?
三 RIPv1在什么情况下会携带子网掩码进行路由的更新?(我将会以实验做验证)
四 RIPv2又如何在汇总掩码小于主类网络的掩码的时候进行手工的汇总?(同样的以实验作为验证)
注:所有的实验,我均会以TXT文本的方式提供下载,以方便大家交流学习。
问题一: RIP V1 V2分属有类网络和无类网络?他们的区别在哪里?
有类网络协议在路由信息的更新过程中仅发送网络地址,不发送子网掩码的信息不支持CIDR和VLSM
无类网络协议在路由信息的更新过程中既发送网络地址,又发送子网掩码的信息支持CIDR和VLSM
(VLSM技术对于有效的分配IP地址和缩减路由表的大小起着至关重要的作用;VLSM是CIDR的具体表现)
问题二:RIP属于距离矢量路由协议?它又和链路状态路由协议有和区别?
最大的区别在于:认识网络的方式不一样。
距离矢量路由协议从网络邻居的角度了解网络(复制完整的路由表:完整更新)
链路状态路由协议从自身的拓扑图了解网络(仅将链路变化部分传送到其他路由器:增量更新)
问题三: RIPv1在什么情况下会携带子网掩码进行路由的更新?(我将会以实验做验证)
首先,我们必须清楚,
RIP V1发送路由更新的原则:
a.要发送的子网信息和路由器更新接口所处的网络属于不同的主类网络,则发送主类网络汇总信息;
b.要发送的子网信息和路由器更新接口所处的网络属于相同的主类网络,而且网络掩码的长度相同,则发送明细路由。
RIP V1接受路由更新的原则:
a.如果收到的路由更新和其接受接口属于不同的主类网络,则以接受接口的子网掩码作为路由条目的掩码;
a.如果收到的路由更新和其接受接口属于相同的主类网络,则以该网络的主类掩码作为路由条目的掩码;
(以实例做说明)拓扑图如下:
我们以R2和R3为例来分别讲解RIP V1携带子网掩码和不携带子网掩码的不同情况。
R2上的RIP路由条目:
结论:R2上收到的都是明细路由的条目。
RIP V1是有类路由协议,而且R2处于主类网络的边缘,虽然默认开启自动汇总,但是不连续的网络是不能通过RIP V1 来收敛的。
2013年9月29日星期日
Android中使用SQLiteOpenHelper管理SD卡中的数据库 - esrixa
db = SQLiteDatabase.create(null);
}
else {
db = mContext.openOrCreateDatabase(mName, 0, mFactory);
}
分析上述代码发现,当数据库名字为非空时,创建数据库或打开由mContext完成,这个mContext由SQLiteOpenHelper的构造函数传入:SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)。那么我们对于传入的context,重载其openOrCreateDatabase函数,使其将数据库创建到SD卡中就可完成我们的目标了~。
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
/**
* 数据库管理和维护类
**/
public class SdCardDBHelper extends SQLiteOpenHelper{
public static final String TAG = "SdCardDBHelper";
/**
* 数据库名称
**/
public static String DATABASE_NAME = "sddb.db";
/**
* 数据库版本
**/
public static int DATABASE_VERSION = 1;
/**
* 构造函数
*
* @param context 上下文环境
**/
public SdCardDBHelper(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* 创建数据库时触发,创建离线存储所需要的数据库表
*
* @param db
**/
@Override
public void onCreate(SQLiteDatabase db) {
Log.e(TAG, "开始创建数据库表");
try{
//创建用户表(user)
db.execSQL("create table if not exists user" +
"(_id integer primary key autoincrement,name varchar(20),password varchar(20),role varchar(10),updateTime varchar(20))");
Log.e(TAG, "创建离线所需数据库表成功");
}
catch(SQLException se){
se.printStackTrace();
Log.e(TAG, "创建离线所需数据库表失败");
}
}
/** 更新数据库时触发,
*
* @param db
* @param oldVersion
* @param newVersion
**/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//db.execSQL("ALTER TABLE person ADD COLUMN other STRING");
}
}
重载的openOrCreateDatabase在sd卡上创建数据库的Context
import java.io.IOException;
import android.content.Context;
import android.content.ContextWrapper;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;
/**
* 用于支持对存储在SD卡上的数据库的访问
**/
public class DatabaseContext extends ContextWrapper {
/**
* 构造函数
* @param base 上下文环境
*/
public DatabaseContext(Context base){
super(base);
}
/**
* 获得数据库路径,如果不存在,则创建对象对象
* @param name
* @param mode
* @param factory
*/
@Override
public File getDatabasePath(String name) {
//判断是否存在sd卡
boolean sdExis
题目描述:
最长不重复子串(Longest No Repeat String,LNRS)就是从一个字符串中找到一个连续子串,该子串中任何两个字符都不能相同,且该子串的长度是最大的。
分析:
解法一:动态规划
动态规划就是用来解决这种最优化问题,关于字符串的很多有趣的问题如最长公共自序列,最长上升子序列等都可以用动态规划来解,这道题我的第一想法也是动态规划。
动态规划的核心在于寻找最优子结构,对于一个字符,如果他与他前面的最长不重复子串都没有相同的字符,那么他也可以加入这个子串中,构成一个新的子串。即对于字符数组a[],dp表示以a为结尾的最长不重复子串长度,dp[0] = 1,最后取dp中的最大值即可。代码如下:
2 #include <cstdlib>
3 #include <string.h>
4
5 using namespace std;
6 char in[10001];
7
8 int dp[10001];
9
10 int LNRS_dp(char *in)
11 {
12 int i, j;
13 int len = strlen(in);
14 int last = 0; // 上一次最长子串的起始位置
15 int maxlen,maxindex;
16 maxlen = maxindex = 0;
17
18 dp[0] = 1;
19 for(i = 1; i < len; ++i)
20 {
21 for(j = i-1; j >= last; --j) // 遍历到上一次最长子串起始位置
22 {
23 if(in[j] == in)
24 {
25 dp = i - j;
26 last = j+1; // 更新last_start
27 break;
28 }else if(j == last) // 无重复
29 {
30 dp = dp + 1;//长度+1
31 }
32 }
33 if(dp > maxlen)
34 {
35 maxlen = dp;
36 }
37 }
38 return maxlen;
39 }
40
41 int main()
42 {
43 freopen("1530.in","r",stdin);
44 freopen("1530.out","w",stdout);
45
46 while(scanf("%s",in)!=EOF)
47 {
48 printf("%d\n",LNRS_dp(in));
49 }
50 return 0;
51 }
显然这个方案是O(n2)的复杂度,且对字符种类没有限制。
解法二:Hash
很多情况下,在描述一个字符串时,都是英文字母组成的字符,因此可能出现的元素是有限的(26个),因此就有了第二种想法,Hash。
这种想法在于使用一个大小为26的数组visited[]记录每个字符是否出现,然后枚举最长不重复子串的起点。代码如下:
2 {
3 char visited[26];
4 int i, j;
5 int maxlen = 0;
6
2013年9月27日星期五
NAT地址转换原理全攻略
在NAT的应用中,可以仅需要转换内部地址(就是"内部本地址"转换成"内部全局地址"),这是最典型的应用,如内部网络用户通过NAT转换共享上网;也可以是仅需要转换外部地址(就是"外部全局地址"转换"外部本地地址"之间的转换),如外部用户要访问位于内部网络中的服务器;当然还可以同时转换内部地址和外部地址。
为了方便理解本节后面所介绍的一些配置,现简单介绍NAT的基本配置思路:
(1)使用ip nat inside source(定义内部本地地址到内部全局地址的映射),或者ip nat outside source(定义外部全局地址到外部本地地址的映射),或者ip nat pool(定义一个内部全局地址池,或者一个外部本地地址池)命令定义一个IP地址映射。具体要使用哪个命令,如何配置地址映射要视所就用的NAT类型和地址转换类型而定。可以是静态地址映射,也可以是动态地址映射,或者端口地址映射(PAT);可以是内部地址转换,也可以是外部地址转换,或者内、外部地址同时转换。
本节为了方便介绍,仅以静态NAT转换为例进行介绍,所以在下面各小节中仅使用了ip nat inside source static,或者ip nat outside source static命令。
(2)使用ip nat inside命令指定内部接口,使用ip nat outside命令指定外部网络接口。
总体来说,NAT进行地址转换的过程就是"本地地址"与"全局地址"之间的转换过程,无论数据包是从内部网络发往外部网络,还是从外部网络发往内部网络。不同的只是本地地址和全局地址所对应的网络不同,以及数据包重新封装的源和目的地址不同。具体如图6-8所示。这个过程是通过NAT中的本地址与全局地址映射条目来实现的,所以事先要在NAT路由器上配置这样的映射条目。
图6-8 NAT基本地址转换原理
当内部网络用户访问外部网络时,所进行的是"内部本地地址"和"内部全局地址"之间的转换。
在NAT路由器接收到来自内部网络主机发送的数据包时,其源IP地址(SA)为"内部本地地址",目的IP地址(DA)为"外部本地地址"。当数据包被转发到外部网络时,数据包的源IP地址(SA)就会转变为"内部全局地址",而目的IP地址(DA)被转变为"外部全局地址"。也就是把数据包的所有源IP地址(SA)和目的IP地址(DA)全部由本地地址转换为全局地址。如图6-9上部分数据包IP地址转换示意图。
相反,当外部网络用户访问内部网络时,所进行的是"外部本地地址"和"外部全局地址"之间的转换。
在NAT路由器接收到来自外部网络主机发送的数据包时,其源IP地址(SA)就是"外部全局地址",目的IP地址(DA)就是"内部全局地址"。相当于由内部网络向外部网络发送数据包时数据包中的源IP地址(SA)和目的IP地址(DA)的互换。而当数据包被路由器转发到本地网络时,源IP地址(SA)被转变为"外部本地地址",目的IP地址(DA)被转变为"内部本地地址",也相当于由内部网络向外部网络发送数据包时数据包中的源IP地址(SA)和目的IP地址(DA)的互换。如图6-9下部分数据包IP地址转换示意图。
图6-9 NAT基本IP地址转换原理
以上是从总体上介绍NAT的IP地址转换原理的,实际NAT应用有时并不需要对源IP地址和IP地址进行全面替换,仅需要对源IP地址或者仅需要对目的IP地址进行转换即可达到所需的目的。下面予以介绍。
多数情况下使用NAT的目的就是为了使内部网络中的多个用户能使用一个注册IP地址访问外部网络,所以仅需要配置内部地址NAT转换。即通过ip nat inside source命令实现"内部本地地址"到"内部全局地址"之间的转换(既可以采用静态NAT方式实现,也可以采取动态NAT方式实现),只需要定义内部本地址与内部本局地址的映射。
图是一个简单的NAT转换示例。要实现以下目的:当NAT路由器的内部网络s0接口上接收到一个源地址为内部本地地址10.10.10.1,目的IP地址为外部本地地址171.16.68.1的数据包时,在转发到s1接口时,原来数据包源地址的内部本地地址10.10.10.1被转换成内部全局地址171.16.68.5,但目的地址不变,然后继续发送。在这个过程中,所进行的只是数据包中源IP地址的转换,由内部本地地址向内部全局地址转换,且只是内部地址之间的转换。
图 简单的NAT转换示例
相反,当在NAT路由器的外部网络接口s1上接收源地址为172.16.68.1外部本地地址,目的地址为内部全局地址172.16.68.5的外部服务器响应数据包时,目的地址将被转换成10.10.10.1这个内部本地地址,然后继续发送。在这个过程中,所进行的只是数据包中目的IP地址的转换,由内部全局地址向内部本地地址转换,也只是内部地址之间的转换。
下面仅以静态NAT转换方式为例介绍内部地址转换的配置步骤,详细的NAT配置方法将在本章后面具体介绍。
(1)使用"ip nat inside source static"全局配置命令启用基于内部源IP地址的静态NAT IP地址转换。也就是定义内部本地地址和内部全局地址,使它们之间形成一一对应的映射关系。
Router(config)#ip nat inside source static 10.10.10.1 171.16.68.5 !--- 在内部本地地址10.10.10.1与内部全局地址171.16.68.5之间建立静态NAT映射关系,使内部网络主机知道要以171.16.68.5这个地址到达外部网络主机
(2)使用以下两条语句配置路由器的s0为NAT的内部网络接口。
Router(config)#interface 演示:EIGRP非等价负载均衡的故障分析与排除 故障背景:在如下图所示的网络环境,工程师完成了环境中所有路由器的接口地址配置有EIGRP动态路由协议的启动,目前每台EIGRP路由器邻居关系正常,路由学习正常,现在工程师想充分使用EIGRP的非等价负载均衡的特性,需要在路由器R1的路由表中产生两条非等价开销的到目标子网172.17.1.0/24的路由,当工程师准备在路由器R1上调整variance时,发现在路由器表中只有一条通过下一跳R2(192.168.1.2)到目标172.17.1.0/24的最佳路由如下图14.21所示,然后通过在路由器R1上执行Show ip eigrp 2013 topology查看EIGRP拓扑表中的备用路径开销时如下图所示,发现备用路径并没有被放入到EIGRP的拓扑表中,根据EIGRP的原则:在这种情况下你将无法按照正常的步骤完成variance值的计算,原因很简单,在R1的路由表中没有这条备用路径是正常的,它需要计算并配置variance值后才会出现在路由表中,但这个过程的前提是:如果这条备用路径没有被放入到EIGRP拓扑表中,那么工程师计算variance值的机会都没有。现在需要解决这个故障,首先分析为什么路由器R1通过R3最后经过R2到达172.16.1.0/24这个备用路径没有被放入到路由器R1的EIGRP拓扑中,然后解决这个问题,最终实现EIGRP的非等价负载均衡。 产生故障的原始配置:产生故障的原始配置如下所示,这方便读者在重构故障时看到当时的故障情境,方便更科学的分析故障。 路由器R1的原始配置: interfaceEthernet1/0 ip address 192.168.1.1 255.255.255.0 duplex half ! interfaceEthernet1/1 ip address 192.168.2.1 255.255.255.0 duplex half ! router eigrp 2013 network 192.168.1.0 network 192.168.2.0 路由器R2的原始配置: interfaceEthernet1/0 ip address 192.168.1.2 255.255.255.0 duplex half ! interfaceEthernet1/1 ip address 192.168.3.1 255.255.255.0 duplex half ! router eigrp 2013 network 172.16.0.0 network 192.168.1.0 network 192.168.3.0 路由器R3的原始配置: interfaceEthernet1/0 ip address 192.168.3.2 255.255.255.0 duplex half ! interfaceEthernet1/1 ip address 192.168.2.2 255.255.255.0 duplex half ! router eigrp 2013 network 192.168.2.0 network 192.168.3.0 故障分析:根据EIGRP在拓扑表中存放备用路径的原则:邻居路由器的通告距离AD必须要小于自己的可行距离FD,否则有可能存在路由环路。在如图14.20所示的故障环境中,路由器R1通过路由器R2到172.16.1.0/24的开销就是路由器R1的FD;路由器R1的邻居R3到172.16.1.0/24的开销就是路由器R1的AD(邻居通告距离);可以分别在路由器R1和R3上通过指令show ipeigrp 2013 topology查看FD和AD如下图14.23所示。可看出,此时的AD等于FD,所以备用路径不会被放入路由器R1的EIGRP拓扑表。 解决方案:上面分析了故障的原因,现在需要来解决这个故障,要让路由器R3为路由器R1到172.16.1.0/24的备用路径,就必须破除当前这个环境中AD等于FD这个现像,必须让AD小于FD。要达到这个目的,可以调整路由器R3的E1/0接口的延时,当然EIGRP路由度量值计算使用多种复合参数(带宽、延迟、负载、可靠度、MTU),但是建议调整延迟,将其调整得比预计的备用路径的AD更小的延迟,这样就让FD小于了AD,备用路径R3就会被放入到路由器R1的拓扑表中,调整路由器R3延迟的配置如下所示,默认10MB以太网接口的延时是1000微秒,现在通过指令delay 50将其改为500微秒,因为是10微秒为一个单位,所以这里配置50即可。延迟调整前后的变化如下图14.24所示。完成上述改变delay的配置后,再次在路由器R1上查看FD,到路由器R3上查看AD,如下图14.25所示,此时AD小于了FD,并且在路由器R1的拓扑表中出现了两条到目标子网172.16.1.0/24的路由。 改变EIGRP的延迟的配置: R3(config)#interface e1/0 R3(config-if)#delay 50 现在已经具备非等价负载均衡的条件了,使用AD409600除以FD396800取整再加1得到2,然后实现如下配置,当完成配置后,可以在路由器R1上查看路由表如下图所示,已经出现了两条非等价的路由。 配置variance值实现非等价负载均衡: R1(config)#router eigrp 2013 R1(config-router)#variance 2 R1(config-router)#exit 虽然最近几年javascript很火。但很多程序员对javascript重视程度不够,所以对javascript的高级应用不甚了解。认为javascript仅仅只是一门脚本语言,作用就是表单验证,网页特效,ajax处理,导致很多开发者对javascript没有足够多的学习时间的投入。javascript应用很多常见的有google Maps ,163email,网页版的游戏。 任何一门语言要精通都不是很容易,如果开发者们没有对JavaScript足够尊敬,是不大可能写出如此优秀的Web应用的。而且如今的javascript不仅仅只是Web应用了! JavaScript门槛很低,但门槛低并不意味着容易掌握。一定程度上,JavaScript的入门容易以及其极大的灵活性,使得要掌握 JavaScript变得很难。从纯语言上讲,我的经历从C/C++ ,java,C#。做过多个大型项目, 虽然都是C家族的语言。我认为JavaScript比学习C#/Java更具挑战性。我们大多习惯了传统的面向对象表述方式,一定程度上甚至会认为类、封装、继承等概念都得像Java、 C++那样,可能都从来没想过没有class, extend, override等概念也能面向对象。JavaScript的面向对象打破了这种思想上的禁锢:世界是多样性的,从设计的角度来看,javascript有时候一行代码就能体现出一种设计模式。夸张一点说,深入学习 JavaScript,更多的是一种思想上的挑战,能活跃思路,扩大视野,甚至改变对世界的看法,从思想上尊敬这门语言,在尊敬的基础上去学习,才有可能掌握这门语言的精髓,更好的驾驭它。 Javascript应用平台 Node.js node.js不仅仅支持web应用还支持桌面应用程序 TermKit图形化终端 开源地址 chrome 插件开发 现在的chrome已经不只是web浏览器了,完全可以跟网络操作系统相比。 window8应用程序开发 window8已经支持javascript开发桌面程序了。 window8应用商店javascript APP http://msdn.microsoft.com/library/windows/apps/hh770842.aspx Javascript的学习 开发工具 WebStorm是我认为最强大的webstorm而插件比较丰富缺点默认字体比较丑,可以设置,是收费的。价格不贵。如果有money建议购买,也有破解版的注册码。 sublime 比好用的开发工具。虽然是收费的。只有保存次数多了才提醒一下。相当于免费的。呵呵! ixedit 可视化开发工具 博客园阿一有介绍过 使用IPostBackEventHandler让JavaScript"调用"回传事件 - 色拉油 阅读原文» 在由ASP.NET所谓前台调用后台、后台调用前台想到HTTP——实践篇(二)通过自己模拟HTML标签事件与服务器交互,讲了ASP.NET的服务器控件是怎么render成HTML后市怎么“调用”后台方法的,有同学看了后问了我个问题:你讲的方式确实可以,但我遇到的问题时这样的,我想让自己写的DIV点击一下提交表单,我是自己写post好呢还是用页面上的__doPostBack方法好呢? 我想了一下,觉得都不好。若是用自己写隐藏域,然后赋值提交的方法,原理虽然正确,但我们需要做很多额外工作;如果调用页面上自动生成的__doPostBack,万一页面上没有服务器控件,那么页面页面上也就不会有这个方法了,而且并不是所有的服务器控件都生成这个方法,退一万步,要是微软改接口,方法名字变了怎么办? 废话了半天,我们因该怎么处理这种情况呢?正如预期,微软又替我们想好了,IPostBackEventHandler接口就是做这事儿的,看个例子 页面上有个DIV,点击的时候调用JavaScript clientPostBack方法,我们知道所谓JavaScript调用后台都是通过表单提交的方式实现的,在clientPostBack中有条奇怪的语句, setTimeout(postBackClientHandler.replace(/arg_placeholder/g,obj.id), 0); ,看看后台代码,就明白这是什么了 首先让类实现IPostBackEventHandler接口,实现RaisePostBackEvent方法,MSDN上市这么解释这个方法的:当由类实现时,使服务器控件能够处理将窗体发送到服务器时引发的事件。这个方法就是JavaScript 提交表单后.NET自动执行的方法,我们把页面传来的参数输出。 在页面的PreRender事件处理程序中,使用PostBackOptions对象创建并注册客户端提交表单所用的脚本,想看明白这段代码,首先得了解PostBackOptions对象。MSDN上这么解释PostBackOptions:指定如何生成客户端 JavaScript 以启动回发事件。看看这个对象构造函数的几个参数 参数 代码中 string clientScript = Page.ClientScript.GetPostBackEventReference(pbo); 是整个注册的核心,通过这条语句就可以获取注册到客户端的脚本语句,然后注册到页面。看看页面生成的代码 通过代码分歧可以看出string clientScript = Page.ClientScript.GetPostBackEventReference(pbo); 语句得到的结果是 __doPostBack('__Page','arg_placeholder')。我们通过string postBackClien 按客户的要求,需要把oracle库控制文件、数据文件、以及联机日志文件从本地磁盘移到存储上,为后续cluster工作做准备,为此,准备两套方案,模拟记录如下 方案一步骤如下: 1shutdownimmediate数据库 方案二步骤如下: 1生成重建控制文件的语句 SQL>selectnamefromv$datafile; NAME SQL>selectgroup#,memberfromv$logfile; GROUP#MEMBER SQL>shutdownimmediate; 3拷贝数据文件、日志文件、临时数据文件、控制文件到存储目录下: C:\Users\Administrator.ZX>copyG:\DATA\ERP\*.*E:\DATA\ERP\ C:\Users\Administrator.ZX>sqlplus/assysdba SQL*Plus:Release11.2.0.1.0Productionon星期五9月2017:29:492013 Copyright(c)1982,2010,Oracle.Allrightsreserved. 已连接到空闲例程。 SQL>startupnomount; TotalSystemGlobalArea430075904bytes SQL>showparametercontrol_files; NAMETYPEVALUE 系统已更改。 TotalSystemGlobalArea430075904bytes NAMETYPEVALUE 数据库已更改。 数据库已更改。 FILE#NAMESTATUS SQL>selectgroup#,memberfromv$logfile; GROUP#MEMBER SQL>selectname,statusfromv$tempfile; NAMESTATUS 第二种方案移库过程如下: 1生成重建控制文件的语句: SQL>selectopen_modefromv$database; OPEN_MODE 作者:寒小阳 题目是网上找的,答案博主自己做的,有不当之处或者有更好的方法欢迎留言! 一堆硬币,一个机器人,如果是反的就翻正,如果是正的就抛掷一次,无穷多次后,求正反的比例(哈尔滨站) 典型的数学概率题(好吧,说明数学还是很重要滴,大家去笔试面前还是巩固一下概率比较好,恩),这里假设无穷多次后正面朝上的比例为x,则反面朝上的比例为1-x;则再投递一次,根据题意,正面朝上的概率的就变成1-x+(1/2*x),,反面朝上的概率变为1/2*x.因为此时已经达到平衡的状态,则该次投递前后概率应该不变,即1-x=1/2*x。解得x为2/3 k链表翻转。给出一个链表和一个数k,比如链表1→2→3→4→5→6,k=2,则翻转后2→1→4→3→6→5,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→5→6,用程序实现。 #include<stdio.h> #include<stdlib.h> #include<iostream> usingnamespace std; struct Node{ int data; Node *next; }; void ReverseLinkList(Node *head,Node *end){ if(head==NULL||end==NULL) return; Node *pre=NULL,*cur=head,*stop=end->next; while(cur!=stop){ Node* nxt=cur->next; cur->next=pre; pre=cur; cur=nxt; } } Node* ReverseKLinkList(Node *head,int k){ if(head==NULL||k<=0) return NULL; Node *cur=head; for(int i=0;i<k-1;i++){ cur=cur->next; if(cur==NULL) break; } if(cur==NULL) return head; Node* begin=cur->next,*end=begin; Node* pre=head; ReverseLinkList(head,cur); while(begin!=NULL){ for(int i=0;i<k-1;i++){ end=end->next; if(end==NULL) break; } if(end==NULL){ pre->next=begin; break; } else{ Node *nextbegin=end->next; ReverseLinkList(begin,end); pre->next=end; pre=begin; begin=end=nextbegin; 来源地址: http://dmitrysoshnikov.com/ecmascript/the-quiz/#q1 另一篇帖子 看看国外的javascript题目,你能全部做对吗? http://www.cnblogs.com/aaronjs/p/3172112.html 答案都是自己总结的,毕竟是人肉解释器,解释不一定完全正确,如有不对欢迎大家指出! 题目1. 结果是什么? 题目2. 下面的检测是否等价? 题目3. 结果是什么? 这个估计好多人想不通了 JavaScript 中所有变量都是对象,除了两个例外 null 和 undefined 一个常见的误解是数字的字面值(literal)不是对象。这是因为 JavaScript 解析器的一个错误, 它试图将点操作符解析为浮点数字面值的一部分。 例如以下这种就OK true.toString()、false.toString()、02.toString()、 0x20.toString()都是可以的 我仔细查了下,网上大多给的解释 2.toString()出错是因为解释器读到“2. ”不知道这个“点”究竟该作为小数点还是“.”操作符, 或者也就是说在这里产生了一个“shift-shift conflit” 有很多变通方法可以让数字的字面值看起来像对象 访问100['toString']的length返回toString方法形参个数; 换个 有长度属性的函数,这个长度就是用来计算多个参数的, 可以分解为 由于toString是个方法,所以它length属性返回的是toString的形参个数,而toString方法可以接收一个radix(基数)作为形参(比如:toString(2),返回该数值的二进制,16则代表16进制),所以最终返回结果是1。 radix 可选项。为将数字值转换为字符串指定一个基数。此值仅用于数字。 所以当数字调用toString的时候,会有一个参数radix,其它的比如:Function、Array、String这些调用的话,结果会是 0 刚才上面的100['toString']['length']为什么不分解成100.toString.length? 这是是由于100后面的.是小数点之后是小数部分,从而导致语法错误 解决的方法也说了 红黑树并没有想象的那么难, 初学者觉得晦涩难读可能是因为情况太多. 红黑树的情况可以通过归结, 通过合并来得到更少的情况, 如此可以加深对红黑树的理解. 网络上的大部分红黑树的讲解因为没有「合并」. 红黑树的五个性质: 性质1. 节点是红色或黑色。 性质2. 根是黑色。 性质3. 所有叶子都是黑色(叶子是NIL节点)。 性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点) 性质5. 从任一节点到其每个叶子的所有简单路径 都包含相同数目的黑色节点。 红黑树的数据结构 摘自 sgi stl 红黑树数据结构定义: 二叉搜索树的插入删除操作 在展开红黑树之前, 首先来看看普通二叉搜索树的插入和删除. 插入很容易理解, 比当前值大就往右走, 比当前值小就往左走. 详细展开的是删除操作. 二叉树的删除操作有一个技巧, 即在查找到需要删除的节点 X; 接着我们找到要么在它的左子树中的最大元素节点 M、要么在它的右子树中的最小元素节点 M, 并交换(M,X). 此时, M 节点必然至多只有一个孩子; 最后一个步骤就是用 M 的子节点代替 M 节点就完成了. 所以, 所有的删除操作最后都会归结为删除一个至多只有一个孩子的节点, 而我们删除这个节点后, 用它的孩子替换就好了. 将会看到 sgi stl map 就是这样的策略. 在红黑树删除操作讲解中, 我们假设代替 M 的节点是 N(下面的讲述不再出现 M). 红黑树的插入 插入新节点总是红色节点, 因为不会破坏性质 5, 尽可能维持所有性质. 假设, 新插入的节点为 N, N 节点的父节点为 P, P 的兄弟(N 的叔父)节点为 U, P 的父亲(N 的爷爷)节点为 G. 所以有如下的印象图: 插入节点的关键是: 插入算法详解如下, 走一遍红黑树维持其性质的过程: 第 0.0 种情况, N 为根节点, 直接 N->黑. over 第 1 种情况, N,P,U 都红(G 肯定黑). 策略: G->红, N,P->黑. 此时, G 红, 如果 G 的父亲也是红, 性质又被破坏了, HACK: 可以将 GPUN 看成一个新的红色 N 节点, 如此递归调整下去; 特俗的, 如果碰巧将根节点染成了红色, 可以在算法的最后强制 root->红. 第 2 种情况, P 为红, N 为 P 右孩子, U 为黑或缺少. 策略: 旋转变换, 从而进入下一种情况: 第 3 种情况, 可能由第二种变化而来, 但不是一定: P 为红, N 为红. 策略: 旋转, 交换 P,G 颜色, 调整后, 因为 P 为黑色, 所以不怕 P 的父节点是红色的情况. over 红黑树的插入就为上面的三种情况. 你可以做镜像变换从而得到其他的情况. 红黑树的删除 假设 N 节点见上面普通二叉树删除中的定义, P 为 N 父节点, S 为 N 的兄弟节点, SL,SR 分别是 S 的左右子节点. 有如下印象图: 删除节点的关键是: 删除算法详解如下, 走一遍红黑树维持其性质的过程: 第 0.0 情况, N 为根节点. over 第 1 情况, N,P,S,SR,SL 都黑. 策略: S->红. 通过 PN,PS 的黑色节点数量相同了, 但会比其他路径多一个, 解决的方法是在 P 上从情况 0 开始继续调整. 为什么要这样呢? HANKS: 因为既然 PN,PS 路径上的黑节点数量相同而且比其他路径会少一个黑节点, 那何不将其整体看成了一个 N 节点! 这是递归原理. 第 2 情况, S 红, 根据红黑树性质 P,SL,SR 一定黑. 策略: 旋转, 交换 P,S 颜色. 处理后关注的范围缩小, 下面的情况对应下面的框图, 算法从框图重新开始, 进入下一个情况: 第 2.1 情况, S,SL,SR 都黑. 策略: P->黑. S->红, 因为通过 N 的路径多了一个黑节点, 通过 S 的黑节点个数不变, 所以维持了性质 5. over. 将看到, sgi stl map 源代码中将第 2.1 和第 1 情况合并成一种情况, 下节展开. 第 2.2.1 情况, S,SR 黑, SL 红. 策略: 旋转, 变换 SL,S 颜色. 从而又进入下一种情况: 上面情况标号 X.X.X 并不是说这些关系是嵌套的, 只是这样展开容易理解. 此时, 解释三个地方: 红黑树删除重新调整伪代码如下: 总结 所以, 插入的情况只有三种, 删除的情况只有两种. 上面的分析, 做镜像处理, 就能得到插入删除的全部算法, 脑补吧. 从上面的分析来看, 红黑树具有以下特性: 插入删除操作都是 0(lnN), 且最多旋转三次. 下节中会重点展开 sgi stl map 的源代码. 参考文档: wikipedia 捣乱 2013-9-25
最具有性价比的语言javascript - 贤达
<div id="divTest" onclick="clientPostback(this);">Click to Post Back</div>
<script type="text/javascript">
function clientPostback(obj) {
setTimeout(postBackClientHandler.replace(/arg_placeholder/g,obj.id), 0);
}
</script>
</form>
{
protected override void OnPreRender(EventArgs e)
{
PostBackOptions pbo = new PostBackOptions(this, "arg_placeholder", "", false, false, false, true, false, "");
string clientScript = Page.ClientScript.GetPostBackEventReference(pbo);
string postBackClientHandler = string.Format("\nvar postBackClientHandler=\"{0}\";\n", clientScript);
Page.ClientScript.RegisterStartupScript(typeof(Default), "postBackClientHandler", postBackClientHandler, true);
base.OnPreRender(e);
}
public void RaisePostBackEvent(string eventArgument)
{
Response.Write("Event argument is " + eventArgument);
}
}
用于接收回发事件的 Control
在回发事件期间传递的可选参数。
回发的目标。
如果需要响应用户操作而自动将窗体回发到服务器,则为 true;否则为 false。
如果 javascript: 前缀是必需的,则为 true;否则为 false。
如果回发事件应将页返回到当前的滚动位置并将焦点返回到目标控件,则为 true;否则为 false。
如果回发事件可以由客户端脚本引发,则为 true;否则为 false。
如果在回发事件发生之前要求在客户端进行验证,则为 true;否则为 false。
一个控件组,当该控件组回发到服务器时,PostBackOptions将引发对它的验证。
//<![CDATA[
var theForm = document.forms['form1'];
if (!theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
//]]>
</script>
//<![CDATA[
var postBackClientHandler="__doPostBack('__Page','arg_placeholder')";
//]]>
</script>2013年9月25日星期三
记一次windows下oracle的整库移动
2copydatafiles、logfiles、controlfiles、tempfiles到新的目录
3startupnomount数据库
4用命令altersystemsetcontrol_files指定控制文件新位置
5startupforcemount数据库
6指定datafiles、tempfiles新位置
7指定redo日志文件新位置
8alterdatabaseopen数据库
2shutdownimmediate数据库
3copydatafiles、logfiles、tempfiles、到新的位置
4用命令altersystemsetcontrol_files更改spfile文件中控制文件的指向
5重建控制文件
6为temp表空间的添加数据文件
方案1执行过程如下:
1查询当前数据文件和日志文件如下:
--------------------------------------------------
G:\DATA\ERP\SYSTEM01.DBF
G:\DATA\ERP\SYSAUX01.DBF
G:\DATA\ERP\UNDOTBS01.DBF
G:\DATA\ERP\USERS01.DBF
------------------------------------------------------------
2G:\DATA\ERP\REDO02.LOG
1G:\DATA\ERP\REDO01.LOG
3G:\DATA\ERP\REDO03.LOG
2一致性关闭数据库:
数据库已经关闭。
已经卸载数据库。
ORACLE例程已经关闭。
SQL>
G:\DATA\ERP\CONTROL01.CTL
G:\DATA\ERP\CONTROL02.CTL
G:\DATA\ERP\REDO01.LOG
G:\DATA\ERP\REDO02.LOG
G:\DATA\ERP\REDO03.LOG
G:\DATA\ERP\SYSAUX01.DBF
G:\DATA\ERP\SYSTEM01.DBF
G:\DATA\ERP\TEMP01.DBF
G:\DATA\ERP\UNDOTBS01.DBF
G:\DATA\ERP\USERS01.DBF
已复制10个文件。
4用命令altersystemsetcontrol_files指定控制文件新位置
ORACLE例程已经启动。
FixedSize2176448bytes
VariableSize301992512bytes
DatabaseBuffers117440512bytes
RedoBuffers8466432bytes
----------------------------------------------------------------------------------------
control_filesstringG:\DATA\ERP\CONTROL01.CTL,G:\
DATA\ERP\CONTROL02.CTL
SQL>altersystemsetcontrol_files='E:\DATA\ERP\CONTROL01.CTL','E:\DATA\ERP\CONTROL02.CTL'scope=spfile;
SQL>startupforcemount;
ORACLE例程已经启动。
FixedSize2176448bytes
VariableSize301992512bytes
DatabaseBuffers117440512bytes
RedoBuffers8466432bytes
数据库装载完毕。
SQL>showparametercontrol_files;
-----------------------------------------------------------------------------
control_filesstringE:\DATA\ERP\CONTROL01.CTL,E:\
DATA\ERP\CONTROL02.CTL
SQL>
5指定数据文件和临时数据文件新位置
SQL>alterdatabaserenamefile'G:\DATA\ERP\SYSAUX01.DBF',
2'G:\DATA\ERP\SYSTEM01.DBF',
3'G:\DATA\ERP\UNDOTBS01.DBF',
4'G:\DATA\ERP\USERS01.DBF',
5'G:\DATA\ERP\TEMP01.DBF'
6to'E:\DATA\ERP\SYSAUX01.DBF',
7'E:\DATA\ERP\SYSTEM01.DBF',
8'E:\DATA\ERP\UNDOTBS01.DBF',
9'E:\DATA\ERP\USERS01.DBF',
10'E:\DATA\ERP\TEMP01.DBF';
6指定日志文件新位置:
SQL>alterdatabaserenamefile'G:\DATA\ERP\REDO01.LOG',
2'G:\DATA\ERP\REDO02.LOG',
3'G:\DATA\ERP\REDO03.LOG'
4to'E:\DATA\ERP\REDO01.LOG',
5'E:\DATA\ERP\REDO02.LOG',
6'E:\DATA\ERP\REDO03.LOG';
SQL>selectfile#,name,statusfromv$datafile;
-----------------------------------------------------------------------------
1E:\DATA\ERP\SYSTEM01.DBFSYSTEM
2E:\DATA\ERP\SYSAUX01.DBFONLINE
3E:\DATA\ERP\UNDOTBS01.DBFONLINE
4E:\DATA\ERP\USERS01.DBFONLINE
------------------------------------------------------------
2E:\DATA\ERP\REDO02.LOG
1E:\DATA\ERP\REDO01.LOG
3E:\DATA\ERP\REDO03.LOG
-------------------------------------------------------------------
E:\DATA\ERP\TEMP01.DBFONLINE
时间:2013年9月。
出处:http://blog.csdn.net/han_xiaoyang/article/details/11924701
声明:版权所有,转载请注明出处,谢谢。
试试看 ? 离奇古怪的javascript题目 - Aaron.
[1, 2, 3].toString(); // '1,2,3'
Foo.bar = 1;
Foo.bar; // 1
"true"
false.toString()
"false"
01.toString()
"1"
0x20.toString()
"32"
2 .toString(); // 注意点号前面的空格
(2).toString(); // 2先被计算
//输出2
})['length']
f : function(a,b,c){
//3
}
};
fn.f['length']
const _Rb_tree_Color_type _S_rb_tree_red = false;
const _Rb_tree_Color_type _S_rb_tree_black = true;
struct _Rb_tree_node_base
{
typedef _Rb_tree_Color_type _Color_type;
typedef _Rb_tree_node_base* _Base_ptr;
_Color_type _M_color;
_Base_ptr _M_parent;
_Base_ptr _M_left;
_Base_ptr _M_right;
static _Base_ptr _S_minimum(_Base_ptr __x)
{
while (__x->_M_left != 0) __x = __x->_M_left;
return __x;
}
static _Base_ptr _S_maximum(_Base_ptr __x)
{
while (__x->_M_right != 0) __x = __x->_M_right;
return __x;
}
};
template <class _Value>
struct _Rb_tree_node : public _Rb_tree_node_base
{
typedef _Rb_tree_node<_Value>* _Link_type;
_Value _M_value_field;
};
第 0.1 种情况, N 的父节点为黑色, 这不违反红黑树的五种性质. over
第 0.1 情况, 删除的节点为红. over
第 0.2 情况, 删除节点为黑, N 为红. 策略: N->黑, 重新平衡. over
第 2.2.2 情况, S 黑, SR 红. 策略: 旋转, 交换 S,P 颜色, SR->黑色, 重新获得平衡.
if N.parent == NULL:
return;
// 第 0.1 情况, 删除的节点为红. over
if color == RED:
return;
// 第 0.2 情况, 删除节点为黑, N 为红, 简单变换: N->黑, 重新平衡. over
if color == BLACK && N.color == RED:
N.color = BLACK;
// 第 1 种情况, N,P,S,SR,SL 都黑. 策略: S->红. 通过 N,S 的黑色节点数量相同了, 但会比其他路径多一个, 解决的方法是在 P 上从情况 0 开始继续调整.
if N,P,S,SR,SL.color == BLACK:
S.color = RED;
// 调整节点关系
N = P
N.parent = P.parent
S = P.paernt.another_child
SL = S.left_child
SR = S.right_child
continue;
// 第 2 情况, S 红, 根据红黑树性质 P,SR,SL 一定黑. 旋转, 交换 P,S 颜色. 此时关注的范围缩小, 下面的情况对应下面的框图, 算法从框图重新开始.
if S.color == RED:
rotate(P);
swap(P.color,S.color);
// 调整节点关系
S = P.another_child
SL = S.left_child
SR = S.right_child
// 第 2.1 情况, S,SL,SR 都黑. 策略: P->黑. S->红, 因为通过 N 的路径多了一个黑节点, 通过 S 的黑节点个数不变, 所以维持了性质 5. over
if S,SL,SR.color == BLACK:
P.color = BLACK;
S.color = RED;
return
// 第 2.2.1 情况, S,SR 黑, SL 红. 策略: 旋转, 变换 SL,S 颜色. 从而又进入下一种情况:
if S,SR.color == BLACK && SL.color == RED:
rotate(P);
swap(S.color,SL.color);
// 调整节点关系
S = SL
SL = S.left_child
SR = S.right_child
// 第 2.2.2 情况, S 黑, SR 红. 策略: 旋转, 交换 S,P 颜色.
if S.color == BLACK && SR.color == RED:
rotate(P);
swap(P.color,S.color);
return;