
位运算是把数字用二进制表示之后,对每一位上0或者1的运算。 理解位运算的第一步是理解二进制。二进制是指数字的每一位都是0或者1.比如十进制的2转化为二进制之后就是10。在程序员的圈子里有一个流传了很久的笑话,说世界上有10种人,一种人知道二进制,而另一种人不知道二进制。。。。。。 其实二进制的运算并不是很难掌握,因为位运算总共只有5种运算:与、或、异或、左移、右移。如下表: 与(&) 0 & 0 = 0 1 & 0 = 0 0 & 1 = 0 1 & 1 = 1 或(|) 0 | 0 = 0 1 | 0 = 1 0 | 1 = 1 1 | 1 = 1 异或(^) 0 ^ 0 = 0 1 ^ 0 = 1 0 ^ 1 = 1 1 ^ 1 = 0 左移运算: 左移运算符m<<n表示吧m左移n位。左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0.比如: 00001010 << 2 = 00101000 10001010 << 3 = 01010000 右移运算: 右移运算符m>>n表示把m右移n位。右移n位的时候,最右边的n位将被丢弃。但右移时处理最左边位的情形要稍微复杂一点。这里要特别注意,如果数字是一个无符号数值,则用0填补最左边的n位。如果数字是一个有符号数值,则用数字的符号位填补最左边的n位。也就是说如果数字原先是一个正数,则右移之后再最左边补n个0;如果数字原先是负数,则右移之后在最左边补n个1.下面是堆两个8位有符号数作右移的例子: 00001010 >> 2 = 00000010 10001010 >> 3 = 11110001 补充: 右移运算x>>k的行为有点微妙。一般而言,及其支持两种形式的右移:逻辑右移和算术右移。逻辑右移在左端补k个0;算术右移是在左端补k个最高有效位的值。 c语言标准并没有明确定义应该使用哪种类型的右移。对于无符号数据(也就是以限定词unsigned声明的整型对象),右移必须是逻辑的。而对于有符号数据(默认的声明的整型对象),算术的或者逻辑的右移都可以。但是,这也意味着任何假设一种或者另一种右移形式的代码都存在潜在着可移植性问题。实际上,几乎所有的编译器/机器组合都对有符号数据使用算术右移,并且我们一般都假设机器会使用这种右移(算术右移)。 关于移位的运算有这样的等价关系:把整数右移一位和把整数除以2在数学上是等价的。 a << = 1 ; //a左移一位等效于a = a * 2; a << = 2 ; //a左移2位等效于a = a * 2的2次方(4); 计算机内部只识别1、0,十进制需变成二进制才能使用移位运算符<<,>> 。 int j = 8; p = j << 1; cout<<p<<endl; 在这里,8左移一位就是8*2的结果16 。 移位运算是最有效的计算乘/除乘法的运算之一。 按位与(&)其功能是参与运算的两数各对应的二进制位相与。只有对应的两个二进制位均为1时,结果位才为1,否则为0 。参与运算的数以补码方式出现。 先举一个例子如下: 题目:请实现一个函数,输入一个正数,输出该数二进制表示中1的个数。 1 int count(BYTE n) 2 { 3 int num = 0; 4 while(n){ 5 n &= (n - 1); 6 num++; 7 } 8 return num; 9 } 这里用到了这样一个知识点:把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0 。 那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。 总结:把一个整数减去1之后再和原来的整数做位与运算,得到的结果相当于是把整数的二进制表示中的最右边一个1变成0 。 位运算的应用可以运用于很多场合: 清零特定位(mask中特定位置0,其它位为1 , s = s & mask)。 取某数中指定位(mask中特定位置,其它位为0, s = s & mask)。 举例:输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。 解决方法:第一步,求这两个数的异或;第二步,统计异或结果中1的位数。 1 #include<iostream> 2 using namespace std; 3 4 int main() 5 { 6 int a = 10 , b =13 , count = 0; 7 int c; 8 c = a ^ b; 9 while(c){ 10 c &= (c - 1); 11 count++; 12 } 13 cout<<count<<endl; 14 15 return 0; 16 } 接下来我们再举一例,就可以更好的说明移位运算了:用一条语句判断一个整数是不是2的整数次方。 解决方法:一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,而其它所有位都是0 。 根据前面的分析,把这个整数减去1后再和它自己做与运算,这个整数中唯一的1就变成0了。 解答:!(x & (x - 1)) 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3311128.html,如需转载请自行联系原作者
来源:http://blog.sina.com.cn/s/blog_493309600100clrw.html TCP与UDP区别 TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。 UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快 Overview TCP (Transmission Control Protocol) is the most commonly used protocol on the Internet. The reason for this is because TCP offers error correction. When the TCP protocol is used there is a "guaranteed delivery." This is due largely in part to a method called "flow control." Flow control determines when data needs to be re-sent, and stops the flow of data until previous packets are successfully transferred. This works because if a packet of data is sent, a collision may occur. When this happens, the client re-requests the packet from the server until the whole packet is complete and is identical to its original. UDP (User Datagram Protocol) is anther commonly used protocol on the Internet. However, UDP is never used to send important data such as webpages, database information, etc; UDP is commonly used for streaming audio and video. Streaming media such as Windows Media audio files (.WMA) , Real Player (.RM), and others use UDP because it offers speed! The reason UDP is faster than TCP is because there is no form of flow control or error correction. The data sent over the Internet is affected by collisions, and errors will be present. Remember that UDP is only concerned with speed. This is the main reason why streaming media is not high quality. On the contrary, UDP has been implemented among some trojan horse viruses. Hackers develop scripts and trojans to run over UDP in order to mask their activities. UDP packets are also used in DoS (Denial of Service) attacks. It is important to know the difference between TCP port 80 and UDP port 80. If you don't know what ports are go here. Frame Structure As data moves along a network, various attributes are added to the file to create a frame. This process is called encapsulation. There are different methods of encapsulation depending on which protocol and topology are being used. As a result, the frame structure of these packets differ as well. The images below show both the TCP and UDP frame structures. TCP FRAME STRUCTURE UDP FRAME STRUCTURE The payload field contains the actually data. Notice that TCP has a more complex frame structure. This is largely due to the fact the TCP is a connection-oriented protocol. The extra fields are need to ensure the "guaranteed delivery" offered by TCP. UDP UDP 与 TCP 的主要区别在于 UDP 不一定提供可靠的数据传输。事实上,该协议不能保证数据准确无误地到达目的地。UDP 在许多方面非常有效。当某个程序的目标是尽快地传输尽可能多的信息时(其中任意给定数据的重要性相对较低),可使用 UDP。ICQ 短消息使用 UDP 协议发送消息。 许多程序将使用单独的TCP连接和单独的UDP连接。重要的状态信息随可靠的TCP连接发送,而主数据流通过UDP发送。 TCP TCP的目的是提供可靠的数据传输,并在相互进行通信的设备或服务之间保持一个虚拟连接。TCP在数据 包接收无序、丢失或在交付期间被破坏时,负责数据恢复。它通过为其发送的每个数据包提供一个序号来完成此恢复。记住,较低的网络层会将每个数据包视为一个 独立的单元,因此,数据包可以沿完全不同的路径发送,即使它们都是同一消息的组成部分。这种路由与网络层处理分段和重新组装数据包的方式非常相似,只是级 别更高而已。 为确保正确地接收数据,TCP要求在目标计算机成功收到数据时发回一个确认(即 ACK)。如果在某个时限内未收到相应的 ACK,将重新传送数据包。如果网络拥塞,这种重新传送将导致发送的数据包重复。但是,接收计算机可使用数据包的序号来确定它是否为重复数据包,并在必要时丢弃它。TCP与UDP的选择 如果比较UDP包和TCP包的结构,很明显UDP包不具备TCP包复杂的可靠性与控制机制。与TCP协 议相同,UDP的源端口数和目的端口数也都支持一台主机上的多个应用。一个16位的UDP包包含了一个字节长的头部和数据的长度,校验码域使其可以进行整 体校验。(许多应用只支持UDP,如:多媒体数据流,不产生任何额外的数据,即使知道有破坏的包也不进行重发。) 很明显,当数据传输的性能必须让位于数据传输的完整性、可控制性和可靠性时,TCP协议是当然的选择。当强调传输性能而不是传输的完整性时,如:音频和多媒体应用,UDP是最好的选择。在数据传输时间很短,以至于此前的连接过程成为整个流量主体的情况下,UDP也是一个好的选择,如:DNS交换。把SNMP建立在UDP上的部分原因是设计者认为当发生网络阻塞时,UDP较低的开销使其有更好的机会去传送管理数据。TCP丰富的功能有时会导致不可预料的性能低下,但是我们相信在不远的将来,TCP可靠的点对点连接将会用于绝大多数的网络应用。 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/03/08/2950096.html,如需转载请自行联系原作者
最近在项目中用到了手势操作,键盘回收时还是挺常用的,现在总结下,多谢网络上大神们的分享。 先分享下我在项目中用的代码: 1 UITapGestureRecognizer * mytap=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap_gestureRecognizer:)]; 2 [self addGestureRecognizer:mytap]; 3 [mytap release]; 4 5 6 //收回键盘 7 -(void)tap_gestureRecognizer:(UITapGestureRecognizer *)tap_gest 8 { 9 [self.scv_stockPriceTextField resignFirstResponder]; 10 [self.scv_stockAmoutTextField resignFirstResponder]; 11 12 } //单指单击 2: UITapGestureRecognizer *singleFingerOne = [[UITapGestureRecognizer alloc] initWithTarget:self 3: action:@selector(handleSingleFingerEvent:)]; 4: singleFingerOne.numberOfTouchesRequired = 1; //手指数 5: singleFingerOne.numberOfTapsRequired = 1; //tap次数 6: singleFingerOne.delegate = self; 7: 8: //单指双击 9: UITapGestureRecognizer *singleFingerTwo = [[UITapGestureRecognizer alloc] initWithTarget:self 10: action:@selector(handleSingleFingerEvent:)]; 11: singleFingerTwo.numberOfTouchesRequired = 1; 12: singleFingerTwo.numberOfTapsRequired = 2; 13: singleFingerTwo.delegate = self; 14: 15: //双指单击 16: UITapGestureRecognizer *doubleFingerOne = [[UITapGestureRecognizer alloc] initWithTarget:self 17: action:@selector(handleDoubleFingerEvent:)]; 18: doubleFingerOne.numberOfTouchesRequired = 2; 19: doubleFingerOne.numberOfTapsRequired = 1; 20: doubleFingerOne.delegate = self; 21: 22: UITapGestureRecognizer *doubleFingerTwo = [[UITapGestureRecognizer alloc] initWithTarget:self 23: action:@selector(handleDoubleFingerEvent:)]; 24: doubleFingerTwo.numberOfTouchesRequired = 2; 25: doubleFingerTwo.numberOfTapsRequired = 2; 26: doubleFingerTwo.delegate = self; 27: 28: //如果不加下面的话,当单指双击时,会先调用单指单击中的处理,再调用单指双击中的处理 29: [singleFingerOne requireGestureRecognizerToFail:singleFingerTwo]; 30: //同理双指亦是如此 31: [doubleFingerOne requireGestureRecognizerToFail:doubleFingerTwo]; 32: 33: [self.view addGestureRecognizer:singleFingerOne]; 34: [self.view addGestureRecognizer:singleFingerTwo]; 35: [self.view addGestureRecognizer:doubleFingerOne]; 36: [self.view addGestureRecognizer:doubleFingerTwo]; 37: 38: [singleFingerOne release]; 39: [singleFingerTwo release]; 40: [doubleFingerOne release]; 41: [doubleFingerTwo release]; 处理事件的方法,代码: 1: //处理单指事件 2: - (void)handleSingleFingerEvent:(UITapGestureRecognizer *)sender 3: { 4: if (sender.numberOfTapsRequired == 1) { 5: //单指单击 6: NSLog(@"单指单击"); 7: }else if(sender.numberOfTapsRequired == 2){ 8: //单指双击 9: NSLog(@"单指双击"); 10: } 11: } 12: //处理双指事件 13: - (void)handleDoubleFingerEvent:(UITapGestureRecognizer *)sender 14: { 15: if (sender.numberOfTapsRequired == 1) { 16: //双指单击 17: NSLog(@"双指单击"); 18: }else if(sender.numberOfTapsRequired == 2){ 19: //双指双击 20: NSLog(@"双指双击"); 21: } 22: } 将相应代码复制到你的工程中即可使用,由于代码中已经有详细的解释说明,这里就不在重复解释了。 代码中只是列举了单指与双指对于单击或多击的处理,同理多指的操作需修改numberOfTouchesRequired属性,对点击的次数需修改numberOfTapsRequired属性。 对于其他手势例如UISwipeGestureRecognizer,UILongPressGestureRecognizer,UILongPressGestureRecognizer的操作使用类似处理。 UIKit中包含了UIGestureRecognizer类,用于检测发生在设备中的手势。UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,它有下面一些子类用于处理具体的手势: 1、拍击UITapGestureRecognizer (任意次数的拍击) 2、向里或向外捏UIPinchGestureRecognizer (用于缩放) 3、摇动或者拖拽UIPanGestureRecognizer 4、擦碰UISwipeGestureRecognizer (以任意方向) 5、旋转UIRotationGestureRecognizer (手指朝相反方向移动) 6、长按UILongPressGestureRecognizer 对于不同类型的手势识别器,具有不同的配置属性。比如UITapGestureRecognizer,可以配置拍击次数。界面接收到手势之后,可以发送一 个消息,用于处理响应手势动作后的任务。当然,不同的手势识别器,发送的消息方法也会有所不同。下面列举几个具体示例代码: http://www.ctolive.com/space-1023-do-blog-id-2107.html 标签: Objective-C iOS 代码片段(5) [代码] 一个手指,拍击两次手势 01 // 创建一个手势识别器 02 UITapGestureRecognizer *oneFingerTwoTaps = 03 [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(oneFingerTwoTaps)] autorelease]; 04 05 // Set required taps and number of touches 06 [oneFingerTwoTaps setNumberOfTapsRequired:2]; 07 [oneFingerTwoTaps setNumberOfTouchesRequired:1]; 08 09 // Add the gesture to the view 10 [[self view] addGestureRecognizer:oneFingerTwoTaps]; 11 12 消息方法oneFingerTwoTaps 13 - (void)oneFingerTwoTaps 14 { 15 NSLog(@"Action: One finger, two taps"); 16 } [代码] 两个手指,拍击两次手势 01 UITapGestureRecognizer *twoFingersTwoTaps = 02 [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersTwoTaps)] autorelease]; 03 [twoFingersTwoTaps setNumberOfTapsRequired:2]; 04 [twoFingersTwoTaps setNumberOfTouchesRequired:2]; 05 [[self view] addGestureRecognizer:twoFingersTwoTaps]; 06 07 消息方法twoFingersTwoTaps 08 - (void)twoFingersTwoTaps { 09 NSLog(@"Action: Two fingers, two taps"); 10 } [代码] 一个手指向上、向下擦碰手势 01 // 向上擦碰 02 UISwipeGestureRecognizer *oneFingerSwipeUp = 03 [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(oneFingerSwipeUp:)] autorelease]; 04 [oneFingerSwipeUp setDirection:UISwipeGestureRecognizerDirectionUp]; 05 [[self view] addGestureRecognizer:oneFingerSwipeUp]; 06 07 - (void)oneFingerSwipeUp:(UISwipeGestureRecognizer *)recognizer 08 { 09 CGPoint point = [recognizer locationInView:[self view]]; 10 NSLog(@"Swipe up - start location: %f,%f", point.x, point.y); 11 } 12 13 // 向下擦碰 14 UISwipeGestureRecognizer *oneFingerSwipeDown = 15 [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(oneFingerSwipeDown:)] autorelease]; 16 [oneFingerSwipeDown setDirection:UISwipeGestureRecognizerDirectionDown]; 17 [[self view] addGestureRecognizer:oneFingerSwipeDown]; 18 19 - (void)oneFingerSwipeDown:(UISwipeGestureRecognizer *)recognizer 20 { 21 CGPoint point = [recognizer locationInView:[self view]]; 22 NSLog(@"Swipe down - start location: %f,%f", point.x, point.y); 23 } [代码] 旋转手势 1 UIRotationGestureRecognizer *twoFingersRotate = 2 [[[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersRotate:)] autorelease]; 3 [[self view] addGestureRecognizer:twoFingersRotate]; 4 5 - (void)twoFingersRotate:(UIRotationGestureRecognizer *)recognizer 6 { 7 // Convert the radian value to show the degree of rotation 8 NSLog(@"Rotation in degrees since last change: %f", [recognizer rotation] * (180 / M_PI)); 9 } [代码] 向里或向外捏的手势 view source print? 1 UIPinchGestureRecognizer *twoFingerPinch = 2 [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingerPinch:)] autorelease]; 3 [[self view] addGestureRecognizer:twoFingerPinch]; 4 5 - (void)twoFingerPinch:(UIPinchGestureRecognizer *)recognizer 6 { 7 NSLog(@"Pinch scale: %f", recognizer.scale); } 在 iPhone 或 iPad 的开发中,除了用 touchesBegan / touchesMoved / touchesEnded 这组方法来控制使用者的手指触控外,也可以用 UIGestureRecognizer 的衍生类別来进行判断。用 UIGestureRecognizer 的好处在于有现成的手势,开发者不用自己计算手指移动轨迹。UIGestureRecognizer的衍生类別有以下几种: UITapGestureRecognizer UIPinchGestureRecognizer UIRotationGestureRecognizer UISwipeGestureRecognizer UIPanGestureRecognizer UILongPressGestureRecognizer 从命名上不难了解這些类別所对应代表的手势,分別是 Tap(点一下)、Pinch(二指往內或往外拨动)、Rotation(旋转)、Swipe(滑动,快速移动)、Pan (拖移,慢速移动)以及 LongPress(长按)。這些手势別在使用上也很简单,只要在使用前定义并添加到对应的视图上即可。 // 定义一个 recognizer, 并加到需要偵測该手势的 UIView 元件上- (void)viewDidLoad { UISwipeGestureRecognizer* recognizer;// handleSwipeFrom 是偵測到手势,所要呼叫的方法 recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:selfaction:@selector(handleSwipeFrom)];// 不同的 Recognizer 有不同的实体变数// 例如 SwipeGesture 可以指定方向// 而 TapGesture 則可以指定次數 recognizer.direction = UISwipeGestureRecognizerDirectionUp [self.view addGestureRecognizer:recognizer]; [recognizer release]; } - (void)handleSwipeFrom:(UISwipeGestureRecognizer*)recognizer {// 触发手勢事件后,在这里作些事情// 底下是刪除手势的方法 [self.view removeGestureRecognizer:recognizer]; } 问题來了。有些手势其实是互相关联的,例如 Tap 与 LongPress、Swipe与 Pan,或是 Tap 一次与Tap 兩次。当一個 UIView 同时添加兩个相关联的手势时,到底我这一下手指头按的要算是 Tap 还是 LongPress?如果照預设作法来看,只要「先滿足条件」的就会跳出并呼叫对应方法,举例来说,如果同时注册了 Pan 和 Swipe,只要手指头一移动就会触发 Pan 然后跳出,因而永远都不會发生 Swipe;单点与双点的情形也是一样,永远都只会触发单点,不會有双点。 那么这个问题有解吗?答案是肯定的,UIGestureRecognizer 有个方法叫做requireGestureRecognizerToFail,他可以指定某一个 recognizer,即便自己已经滿足條件了,也不會立刻触发,会等到该指定的 recognizer 确定失败之后才触发。以同时支持单点与双点的手势为例,代码如下: - (void)viewDidLoad {// 单击的 Recognizer UITapGestureRecognizer* singleRecognizer; singleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(handleSingleTapFrom)]; singleTapRecognizer.numberOfTapsRequired = 1; // 单击 [self.view addGestureRecognizer:singleRecognizer];// 双击的 Recognizer UITapGestureRecognizer* double; doubleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(handleDoubleTapFrom)]; doubleTapRecognizer.numberOfTapsRequired = 2; // 双击 [self.view addGestureRecognizer:doubleRecognizer];// 关键在这一行,如果双击确定偵測失败才會触发单击 [singleRecognizer requireGestureRecognizerToFail:doubleRecognizer]; [singleRecognizer release]; [doubleRecognizer release]; } 来源:http://blog.csdn.net/xiaoxuan415315/article/details/7788239 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3469857.html,如需转载请自行联系原作者
iOS 程序打包,安装流程 一、发布测试,是指将你的程序给 * 你的测试人员,因为程序总归是要测试的 * 你的客户,在正式发布之前,客户肯定是要先看(验收)的 在他们的iOS设备(iphone,ipod, ipad)安装,运行。 二,阅读前提:你自己已经完成了真机测试,意味着: 1、你已经加入了苹果的"iOS developer program",标志事件是付了$99。 2、在iOS Provisioning Portal生成了开发证书 3、在xcode完成了证书的安装。菜单:window->Organizer,然后选择Devices 三,发布流程。 图:发布流程 1、3个角色:Tester,就是上述测试人员或者你的客户;Developer,就是你了;Program Portal,苹果官方网站,登录你的“Member Center”,就能看到了, 2、3个主要步骤,见图发布步骤, 1)获取Tester设备udid 2)到Program Portal生成ad hoc发布证书 3)在xcode中使用该证书打包(Archive)程序 以上3个步骤后续会详细说。 假设你的Tester(团队里的测试人员、你的客户)有一定iOS设备使用经验,至少大致会用itunes。 要获取你的Tester的iOS设备UDID:1、将iOS设备插到安装了itunes的pc/mac,itunes会弹出显示设备概要信息界面,如下图, 这里我们可以看到设备的12位序列号,这不是我们想要的。2、点击序列号,设备概要界面显示设备udid,如下图, CTRL-C(mac下为Command-C)拷贝下来,然后QQ或者邮件发给你。 注:1)虽然点击udid,界面什么变化也没有,但是确实是可以拷贝 2)千万不要让人家一个个字符抄,你不可惜人家辛苦,也得想想抄40左右得字符很容易出错。 UDID拿到了,得在iOS provisioning portal上将它加Device列表上,以下是具体步骤: 1、登录会员中心(Member Center) 到苹果开发者官方网站(developer.apple.com),选择Member Center,如上图。 2、使用你的Apple ID登录,如下图 (是写得有点罗嗦)\ 3、在会员中心,选择iOS Provisioning Portal,如下图, 4、进入Provisioning Portal主界面,如下图, 5、选择“Devices”,然后选择“Add Devices”, 出现下图界面, 一个地方填名称,一个地方填你从Tester那里拿到的udid。 iOS证书分2种,1种是开发证书,用来给你(开发人员)做真机测试的;1种是发布证书,发布证书又分发布到app store的(这里不提及)和发布测试的ad hoc证书。 那ad hoc证书和开发证书区别在哪里?如果你的tester(团队测试人员、客户)都能将测试设备拿到你面前,直接插到你的mac开发机上,你可以直接将程序“灌”进去,那有开发证书就够了,不需要ad hoc证书。 如果tester的iOS设备不能直接让你灌程序,那怎么办?你必须打包(Archive)你的程序,然后发给你的tester,让他通过itunes进行安装,那就需要ad hoc证书了。 具体的区别,我们先看看ad hoc证书生成过程,和开发证书生成非常类似,1、进入Provisioning Portal主界面,如下图, 如何进入Provisioning Portal主界面,可以参考“iOS程序发布测试2-获取Tester设备UDID”)2、选择Provisioning,然后选择Distribution,如下图 这是开发证书和发布证书生成时的一个区别,在文章“iOS程序发布测试4-打包(Archive)发布(share)”中会说到使用的区别。3、选择“New Profile”,出现新建发布证书界面,如下图, 选择“Ad Hoc”,然后选择Tester的设备ID(如何获取和添加Tester设备ID,见“iOS程序发布测试3-获取Tester设备UDID”)。 4、下载证书到本地, 点击“Download”,将证书下到本地。 注:如果status是“pending”,刷新一下就成“Active”了。 5、导入证书。双击,出现Xcode(我这里是4.0)provisioning界面,如下图, 证书生成好,而且导入了,接下来就是打包(Archive)和发布(share)了。 发布测试的最后一步打包(Archive),前面几个步骤:Xcode4 真机程序发布测试1-准备Xcode4 真机程序发布测试2-获取UDIDXcode4 真机程序发布测试3-生成ad hoc证书Xcode4帮助文档有比较详细介绍,但是居然是错的,这里说明一下。1、设置“Build Settings”,下图是官方文档截图,留意那个红框,居然说反了。 "Skip install"一定要选NO,否则在下面的打包步骤后,Organizer看不到你的程序,就为这折腾我好些时间,国外论坛一堆问题,说我按照官方文档做了,怎么Organizer看不到程序。 1.1 选择ad hoc证书.在“Code Signing”栏,选择你在文章(“iOS程序发布测试3-生成ad hoc证书”)生成的发布证书(ad hoc),如下图, 这里要选择“iPhone Distribution”,而不是“iPhone Development”,否则会在下面打包(Archive)步骤报证书错误。2、编辑“Scheme”,选择菜单:Product -> Edit Scheme,如下图, 红色框部分要选对,注意要分别选iOS Device和Release。3、打包(Archive),选择菜单:Product->Archive,在organizer窗口可以看到你的程序, 然后点击“share”按钮,进行发布(share)4、Share 选第一个“iOS App Store Package”,生成.ipa文件,你的Tester使用itunes即可安装。 如果选择了最后一个,“Archive”,需要对方安装xcode。 来源:http://blog.csdn.net/xiaoxuan415315/article/details/8191109 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3469897.html,如需转载请自行联系原作者
同步首发:http://www.yuanrengu.com/index.php/20171112.html 一.GitLab简介 GitLab是利用Ruby On Rails开发的一个开源版本管理系统,实现了一个自托管的Git项目仓库,是集代码托管,测试,部署于一体的开源git仓库管理软件,可通过web界面来进行访问公开的或私人项目。与Github类似,GitLab能够浏览代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本,并提供一个文件历史库。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后需要的时候查找。 Git的家族成员: Git:是一种版本控制系统,是一个命令,是一种工具。 Gitlib:是用于实现Git功能的开发库。 Github:是一个基于Git实现的在线代码托管仓库,公开项目是免费的,也可以付费创建私人项目。 GitLab:是一个基于Git实现的在线代码仓库托管软件,可以用GitLab搭建一套类似Github的系统。 GitLab对硬件还是有一定要求的,1核心的CPU基本上可以满足需求,大概支撑100个左右的用户,不过在运行GitLab网站的同时还需要运行多个后台job,就会显得有点捉襟见肘了。需要至少4GB的可寻址内存(RAM交换)来安装和使用GitLab,操作系统和任何其他正在运行的应用程序也将使用内存,因此请记住,在运行GitLab之前,您至少需要4GB的可用空间。如果使用更少的内存,GitLab将在重新配置运行期间给出奇怪的错误,我用虚拟机来分别新建1G,2G内存的CentOS系统来装GitLab,确实非常捉襟见肘啊,伤不起。 二.GitLab的安装 1.在CentOS系统上,下面的命令将会打开系统防火墙HTTP和SSH访问。 1 2 3 4 5 6 7 8 sudo yum install curl policycoreutils openssh-server openssh-clients sudo systemctl enable sshd sudo systemctl start sshd sudo yum install postfix sudo systemctl enable postfix sudo systemctl start postfix sudo firewall-cmd --permanent --add-service=http sudo systemctl reload firewalld 2.添加GitLab镜像源并安装 1 curl -sS http://packages.gitlab.com.cn/install/gitlab-ce/script.rpm.sh | sudo bash 这是官方的yum源,安装速度会比较慢,可以使用国内源,修改如下文件即可: 1 vim /etc/yum.repos.d/gitlab_gitlab-ce.repo 修改内容如下: 1 2 3 4 5 6 7 [gitlab-ce] name=gitlab-ce baseurl=http://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7 repo_gpgcheck=0 gpgcheck=0 enabled=1 gpgkey=https://packages.gitlab.com/gpg.key 然后执行: sudo yum install gitlab-ce #配置并启动 GitLab sudo gitlab-ctl reconfigure 安装成功会有如下提示: 3.第一次访问GitLab,系统会重定向页面到重定向到重置密码页面,你需要输入初始化管理员账号的密码,管理员的用户名为root,初始密码为5iveL!fe。重置密码后,新密码即为刚输入的密码。 三.GitLab的汉化 成功安装GitLab后,很多朋友会想到汉化,当然如果团队里英文水平都不错的话,是没必要汉化的。 GitLab中文社区的项目,v7-v8.8是由Larry Li发起的“GitLab中文社区版项目”(https://gitlab.com/larryli/gitlab),从v8.9之后由@xhang开始继续汉化项目(https://gitlab.com/xhang/gitlab)。 mkdir /home/local/gitlab cd /home/local/gitlab 如没安装git,需提前安装: yum install -y git 下载最新的汉化包: git clone https://gitlab.com/xhang/gitlab.git 如果是要下载老版本的汉化包,需要加上老版本的分支,如果想下载10.0.2,可以运行如下语句: git clone https://gitlab.com/xhang/gitlab.git -b v10.0.2-zh 停止GitLab并执行如下语句: gitlab-ctl stop cp /home/local/gitlab/* /opt/gitlab/embedded/service/gitlab-rails/ -rf 复制时可能不断提示是否要覆盖,这时可能是系统每次执行cp命令时,其实是执行了cp -i命令的别名。出现这种情况可以修改~/.bashrc,在“alias cp=’cp-i’”前加#注释即可。 复制可能出现如下提示,可以不用理会。 注释后记得执行: source ~/.bashrc 或者重启即可。 接下来可以重新配置和启动: sudo gitlab-ctl reconfigure sudo gitlab-ctl restart 成功汉化后的界面如下: 四.GitLab的命令 语法: gitlab-ctl command (subcommand) Service Management Commands start 启动所有服务 stop 关闭所有服务 restart 重启所有服务 status 查看所有服务状态 tail 查看日志信息 service-list 列举所有启动服务 graceful-kill 平稳停止一个服务 例子: 1 2 3 4 5 6 7 8 9 10 11 #启动所有服务 [root@gitlab ~]# gitlab-ctl start #启动单独一个服务 [root@gitlab ~]# gitlab-ctl start nginx #查看日志,查看所有日志 [root@gitlab ~]# gitlab-ctl tail #查看具体一个日志,类似tail -f [root@gitlab ~]# gitlab-ctl tail nginx General Commands help 帮助 reconfigure 修改配置文件之后,需要重新加载下 show-config 查看所有服务配置文件信息 uninstall 卸载这个软件 cleanse 删除gitlab数据,重新白手起家 例子: #显示所有服务配置文件 [root@gitlab ~]#gitlab-ctl show-config #卸载gitlab [root@gitlab ~]#gitlab-ctl uninstall 五.QQ邮箱配置 默认情况下,GitLab用qq邮箱注册是发不出确认邮件的。查看了网上很多邮箱配置的教程,大部分都是误导的。 像这类软件,归根到底总结为一句话:一切以官网文档为准。 qq邮箱最好用企业邮箱,本人用个人邮箱进行测试是有些小问题的。 正确配置如下: 1 2 3 4 5 6 7 8 9 10 11 # vim /etc/gitlab/gitlab.rb gitlab_rails['smtp_enable'] = true gitlab_rails['smtp_address'] = "smtp.exmail.qq.com" gitlab_rails['smtp_port'] = 465 gitlab_rails['smtp_user_name'] = "xxxx@xx.com" gitlab_rails['smtp_password'] = "password" gitlab_rails['smtp_authentication'] = "login" gitlab_rails['smtp_enable_starttls_auto'] = true gitlab_rails['smtp_tls'] = true gitlab_rails['gitlab_email_from'] = 'xxxx@xx.com' 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/7778203.html,如需转载请自行联系原作者
来源:http://www.open-open.com/lib/view/open1341882439838.html 1. UITouch 的主要方法: C代码 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); 2. 触摸时,图片移动 (实例) C代码 - (void)viewDidLoad { UIImageView *image = [[UIImageView alloc] initWithFrame:CGRectMake(20.0, 50.0, 45.0, 45.0)]; image.image = [UIImage imageNamed:@"baby.png"]; image.tag = 100; [self.view addSubview:image]; [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; UIImageView *view1 = (UIImageView*)[self.view viewWithTag:100]; CGPoint point = [touch locationInView:self.view]; CGRect frame = view1.frame; frame.origin = point; view1.frame = frame; } iphone/ipad无键盘的设计是为屏幕争取更多的显示空间,大屏幕在观看图片、文字、视频等方面为用户带来了更好的用户体验。而触摸屏幕是iOS设备接受用户输入的主要方式,包括单击、双击、拨动以及多点触摸等,这些操作都会产生触摸事件。 在Cocoa中,代表触摸对象的类是UITouch。当用户触摸屏幕后,就会产生相应的事件,所有相关的UITouch对象都被包装在事件中,被程序交由特定的对象来处理。UITouch对象直接包括触摸的详细信息。 UITouch类中包含5个属性: window:触摸产生时所处的窗口。由于窗口可能发生变化,当前所在的窗口不一定是最开始的窗口。 view:触摸产生时所处的视图。由于视图可能发生变化,当前视图也不一定时最初的视图。 tapCount:轻击(Tap)操作和鼠标的单击操作类似,tapCount表示短时间内轻击屏幕的次数。因此可以根据tapCount判断单击、双击或更多的轻击。 timestamp:时间戳记录了触摸事件产生或变化时的时间。单位是秒。 phase:触摸事件在屏幕上有一个周期,即触摸开始、触摸点移动、触摸结束,还有中途取消。而通过phase可以查看当前触摸事件在一个周期中所处的状态。phase是UITouchPhase类型的,这是一个枚举配型,包含了 · UITouchPhaseBegan(触摸开始) · UITouchPhaseMoved(接触点移动) · UITouchPhaseStationary(接触点无移动) · UITouchPhaseEnded(触摸结束) · UITouchPhaseCancelled(触摸取消) UITouch类中包含如下成员函数: - (CGPoint)locationInView:(UIView *)view:函数返回一个CGPoint类型的值,表示触摸在view这个视图上的位置,这里返回的位置是针对view的坐标系的。调用时传入的view参数为空的话,返回的时触摸点在整个窗口的位置。 - (CGPoint)previousLocationInView:(UIView *)view:该方法记录了前一个坐标值,函数返回也是一个CGPoint类型的值, 表示触摸在view这个视图上的位置,这里返回的位置是针对view的坐标系的。调用时传入的view参数为空的话,返回的时触摸点在整个窗口的位置。 当手指接触到屏幕,不管是单点触摸还是多点触摸,事件都会开始,直到用户所有的手指都离开屏幕。期间所有的UITouch对象都被包含在UIEvent事件对象中,由程序分发给处理者。事件记录了这个周期中所有触摸对象状态的变化。 只要屏幕被触摸,系统就会报若干个触摸的信息封装到UIEvent对象中发送给程序,由管理程序UIApplication对象将事件分发。一般来说,事件将被发给主窗口,然后传给第一响应者对象(FirstResponder)处理。 关于响应者的概念,通过以下几点说明: 响应者对象(Response object) 响应者对象就是可以响应事件并对事件作出处理。在iOS中,存在UIResponder类,它定义了响应者对象的所有方法。 UIApplication、UIView等类都继承了UIResponder类,UIWindow和UIKit中的控件因为继承了UIView,所以也 间接继承了UIResponder类,这些类的实例都可以当作响应者。 第一响应者(First responder) 当前接受触摸的响应者对象被称为第一响应者,即表示当前该对象正在与用户交互,它是响应者链的开端。 响应者链(Responder chain) 响应者链表示一系列的响应者对象。事件被交由第一响应者对象处理,如果第一响应者不处理,事件被沿着响应者链向上传递,交给下一个响应者(next responder)。一般来说,第一响应者是个视图对象或者其子类对象,当其被触摸后事件被交由它处理,如果它不处理,事件就会被传递给它的视图控制器 对象(如果存在),然后是它的父视图(superview)对象(如果存在),以此类推,直到顶层视图。接下来会沿着顶层视图(top view)到窗口(UIWindow对象)再到程序(UIApplication对象)。如果整个过程都没有响应这个事件,该事件就被丢弃。一般情况下, 在响应者链中只要由对象处理事件,事件就停止传递。但有时候可以在视图的响应方法中根据一些条件判断来决定是否需要继续传递事件。 管理事件分发 视图对触摸事件是否需要作处回应可以通过设置视图的userInteractionEnabled属性。默认状态为YES,如果设置为NO,可以阻 止视图接收和分发触摸事件。除此之外,当视图被隐藏(setHidden:YES)或者透明(alpha值为0)也不会收事件。不过这个属性只对视图有 效,如果想要整个程序都步响应事件,可以调用UIApplication的beginIngnoringInteractionEvents方法来完全停 止事件接收和分发。通过endIngnoringInteractionEvents方法来恢复让程序接收和分发事件。 如果要让视图接收多点触摸,需要设置它的multipleTouchEnabled属性为YES,默认状态下这个属性值为NO,即视图默认不接收多点触摸。 首先触摸的对象是视图,而视图的类UIView继承了UIRespnder类,但是要对事件作出处理,还需要重写UIResponder类中定义的事件处理函数。根据不通的触摸状态,程序会调用相应的处理函数,这些函数包括以下几个: -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; 当手指接触屏幕时,就会调用touchesBegan:withEvent方法; 当手指在屏幕上移时,动就会调用touchesMoved:withEvent方法; 当手指离开屏幕时,就会调用touchesEnded:withEvent方法; 当触摸被取消(比如触摸过程中被来电打断),就会调用touchesCancelled:withEvent方法。而这几个方法被调用时,正好对应了UITouch类中phase属性的4个枚举值。 上面的四个事件方法,在开发过程中并不要求全部实现,可以根据需要重写特定的方法。对于这4个方法,都有两个相同的参数:NSSet类型的touches 和UIEvent类型的event。其中touches表示触摸产生的所有UITouch对象,而event表示特定的事件。因为UIEvent包含了整 个触摸过程中所有的触摸对象,因此可以调用allTouches方法获取该事件内所有的触摸对象,也可以调用touchesForVIew:或者 touchesForWindows:取出特定视图或者窗口上的触摸对象。在这几个事件中,都可以拿到触摸对象,然后根据其位置,状态,时间属性做逻辑处 理。 例如: C代码 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; if(touch.tapCount == 2) { self.view.backgroundColor = [UIColor redColor]; } } 上面的例子说明在触摸手指离开后,根据tapCount点击的次数来设置当前视图的背景色。不管时一个手指还是多个手指,轻击操作都会使每个触摸对象的 tapCount加1,由于上面的例子不需要知道具体触摸对象的位置或时间等,因此可以直接调用touches的anyObject方法来获取任意一个触 摸对象然后判断其tapCount的值即可。 检测tapCount可以放在touchesBegan也可以touchesEnded,不过一般后者跟准确,因为touchesEnded可以保证所有的手指都已经离开屏幕,这样就不会把轻击动作和按下拖动等动作混淆。 轻击操作很容易引起歧义,比如当用户点了一次之后,并不知道用户是想单击还是只是双击的一部分,或者点了两次之后并不知道用户是想双击还是继续点击。为了解决这个问题,一般可以使用“延迟调用”函数。 例如: C代码 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; if(touch.tapCount == 1) { [self performSelector:@selector(setBackground:) withObject:[UIColor blueColor] afterDelay:2]; self.view.backgroundColor = [UIColor redColor]; } } 上面代码表示在第一次轻击之后,没有直接更改视图的背景属性,而是通过performSelector:withObject:afterDelay:方法设置2秒中后更改。 C代码 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; if(touch.tapCount == 2) { [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setBackground:) object:[UIColor redColor]]; self.view.backgroundColor = [UIColor redColor]; } } 双击就是两次单击的组合,因此在第一次点击的时候,设置背景色的方法已经启动,在检测到双击的时候先要把先前对应的方法取消掉,可以通过调用 NSObject类的cancelPreviousPerformRequestWithTarget:selector:object方法取消指定对象 的方法调用,然后调用双击对应的方法设置背景色为红色。 下面举个例子创建可以拖动的视图,这个主要通过触摸对象的位置坐标来实现。因此调用触摸对象的locationInView:方法即可。 例如: C代码 CGPoint originalLocation; -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; originalLocation = [touch locationInView:self.view]; } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint currentLocation = [touch locationInView:self.view]; CGRect frame = self.view.frame; frame.origin.x += currentLocation.x-originalLocation.x; frame.origin.y += currentLocation.y-originalLocation.y; self.view.frame = frame; } 这里先在touchesBegan中通过[touch locationInView:self.view]获取手指触摸在当前视图上的位置,用CGPoint变量记录,然后在手指移动事件 touchesMoved方法中获取触摸对象当前位置,并通过于与原始位置的差值计算出移动偏移量,再设置当前视图的位置。 部分来源: http://www.cnblogs.com/spiritstudio/archive/2011/05/24/2054907.html 实例: C代码 //对画面进行单次点击时所触发的函式 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //宣告一个UITouch的指标来存放事件触发时所撷取到的状态 UITouch *touch = [[event allTouches] anyObject]; //将XY轴的座标资讯正规化后输出 touchX.text = [NSString stringWithFormat:@"%0.0f", [touch locationInView:touch.view].x]; touchY.text = [NSString stringWithFormat:@"%0.0f", [touch locationInView:touch.view].y]; } C代码 //对画面进行拖曳动做时所触发的函式 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { //宣告一个UITouch的指标来存放事件触发时所撷取到的状态 UITouch *touch = [[event allTouches] anyObject]; //将XY轴的座标资讯正规化后输出 moveX.text = [NSString stringWithFormat:@"%0.0f", [touch locationInView:touch.view].x]; moveY.text = [NSString stringWithFormat:@"%0.0f", [touch locationInView:touch.view].y]; } C代码 //手指离开画面(结束操作)时所触发的函式 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { //宣告一个UITouch的指标来存放事件触发时所撷取到的状态 UITouch *touch = [[event allTouches] anyObject]; //取得并输出连点资讯,tapCount可保留一定时间内的连点次数 tapCountLabel.text = [NSString stringWithFormat:@"%d", [touch tapCount]]; } 来源:http://furnacedigital.blogspot.com/2010/12/touch-panel.html 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3465415.html,如需转载请自行联系原作者
来源:http://blog.csdn.net/duxinfeng2010/article/details/8120960 在iPhone开发协议和委托是常接触到的东西,到底什么是协议什么是委托,他们什么关系? 一 协议 (1)协议相当于没有与类相关联的接口,他申明一组方法,列出他的参数和返回值,共享给其他类使用,然后不进行实现,让用它的类来实现这些方法 (2)在任何一个类中,只有声明了协议,都可以实现协议里的方法。 (3)协议不是一个类,更没有父类了。 (3)协议里面的方法经常都是一些委托方法, 二 委托 委托,故名思议就是托别人办事。打个比方: 张三迫切需要一分工作,但是不知道去哪找。于是他就拜托(委托)李四给帮找一份合适工 作,但是托人办事得给被人好处啊,于是张三给李四塞了一个红包(协议),于是李四通过自己关系在某公司找了一份文秘的工作(实现协议里面委托方法),于然 后他把文秘这份工作给了张三,张三就找到工作了; 三 我们来看一个比较常用的表格单元实现委托和协议 UITableViewDataSource协议和他的委托方法 [cpp] view plaincopy @protocol UITableViewDataSource<NSObject> @required - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; // Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier: // Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls) - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; @optional - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; // fixed font style. use custom view (UILabel) if you want something different - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; // Editing // Individual rows can opt out of having the -editing property set for them. If not implemented, all rows are assumed to be editable. - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath; // Moving/reordering // Allows the reorder accessory view to optionally be shown for a particular row. By default, the reorder control will be shown only if the datasource implements -tableView:moveRowAtIndexPath:toIndexPath: - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath; // Index - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView; // return list of section titles to display in section index view (e.g. "ABCD...Z#") - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index; // tell table which section corresponds to section title/index (e.g. "B",1)) // Data manipulation - insert and delete support // After a row has the minus or plus button invoked (based on the UITableViewCellEditingStyle for the cell), the dataSource must commit the change - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath; // Data manipulation - reorder / moving support - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath; @end 这是一个完整协议定义 @protocol 协议名 声明方法 @end 但是我们还看到两个特殊关键字 @required 和 @optional @required 表示我们用到这个协议的时候必须实现这个协议的方法 @optional 表示我们可选择性实现这些方法,看那个需要我们就去实现,不需要的就不实现 UITableViewDelegate协议和委托方法 [cpp] view plaincopy @protocol UITableViewDelegate<NSObject, UIScrollViewDelegate> @optional // Display customization - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath; // Variable height support - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section; - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section; // Section header & footer information. Views are preferred over title should you decide to provide both - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; // custom view for header. will be adjusted to default or specified header height - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section; // custom view for footer. will be adjusted to default or specified footer height // Accessories (disclosures). - (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_3_0); - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath; // Selection // Called before the user changes the selection. Return a new indexPath, or nil, to change the proposed selection. - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath; - (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); // Called after the user changes the selection. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); // Editing // Allows customization of the editingStyle for a particular cell located at 'indexPath'. If not implemented, all editable cells will have UITableViewCellEditingStyleDelete set for them when the table has editing property set to YES. - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath; - (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); // Controls whether the background is indented while editing. If not implemented, the default is YES. This is unrelated to the indentation level below. This method only applies to grouped style table views. - (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath; // The willBegin/didEnd methods are called whenever the 'editing' property is automatically changed by the table (allowing insert/delete/move). This is done by a swipe activating a single row - (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath; - (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath; // Moving/reordering // Allows customization of the target row for a particular row as it is being moved/reordered - (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath; // Indentation - (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath; // return 'depth' of row for hierarchies // Copy/Paste. All three methods must be implemented by the delegate. - (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0); - (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0); - (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0); @end 在用的时候,我们现在声明协议 [cpp] view plaincopy #import <UIKit/UIKit.h> @interface BIDViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> @property (strong, nonatomic) NSDictionary *names; @property (strong, nonatomic) NSArray *keys; @end 实现UITableViewDataSource UITableViewDelegate协议里面的委托方法 [cpp] view plaincopy #pragma mark - #pragma mark Table View Data Source Methods - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [keys count]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSString *key = [keys objectAtIndex:section]; NSArray *nameSection = [names objectForKey:key]; return [nameSection count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSUInteger section = [indexPath section]; NSUInteger row = [indexPath row]; NSString *key = [keys objectAtIndex:section]; NSArray *nameSection = [names objectForKey:key]; static NSString *SectionsTableIdentifier = @"SectionsTableIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SectionsTableIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SectionsTableIdentifier]; } cell.textLabel.text = [nameSection objectAtIndex:row]; return cell; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { NSString *key = [keys objectAtIndex:section]; return key; } - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { return keys; } 这就就是实现一些里面的委托方法过程运行改程序运行结果 该程序源码http://download.csdn.net/detail/duxinfeng2010/4695666 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3471071.html,如需转载请自行联系原作者
同步首发:http://www.yuanrengu.com/index.php/20171130.html 项目开发接近尾声,开始着手在生产环境部署项目,开发阶段部署项目都没用nginx。项目是采用SOA架构,多系统开发,主要包括服务系统、中台系统、后台系统、金融系统、接口系统、调度系统、报表系统等。这类分布式的系统,一般也都会用到nginx来做负载均衡。 从公司刚成立就进来,赶鸭子上架来做架构师,负责公司的所有研发事情,搭建公司的整个技术架构,起初的所有核心业务代码基本都由自己亲自把关来进行编码。系统也从最初的只有一个pc端,发展到如今pc中台、后台、android端3个app、iOS端3个app,产品越做越多,亲自负责招聘面试、培训。之前很多时候都有过无助和苦恼,因为负责公司整个架构,又要负责核心业务的编码,技术难点的攻克,新员工的招聘及培训,现在团队已经都发展到16个人,而且这全是研发人员。 回想这一路,觉得之前看似爬不过去的山也不过如此,也许这就是成长吧,成长总是会伴随些许汗水与泪水吧。由于是负责团队的所有事情,所以数据库的维护、迁移数据、建索引等性能优化,项目部署等所有事情必须得一肩挑,不要问我为什么公司没有DBA?为什么没有运维?我真的只能给你一个眼神,让你慢慢去体会。 话不多说,直接开始技术干货分享。 nginx做负载均衡的优势网上有很多介绍资料,这里我不再多做介绍。因为有很多系统要部署,涉及到域名、二级域名、多个域名等的部署。在实际的部署由于对nginx的不够熟悉,遇到过很多坑,其中这种多域名的配置,xxxx.com转发到www.xxxx.com、访问域名转发到tomcat里的项目等,现在先总结一部坑的解决办法。 如将xxxx.com这个域名指向8082端口里的tomcat项目,在做这个介绍前先讲个插曲,如访问xxxx.com需转向到www.xxxx.com,这一点很多人都会忽略。 现在如果要部署中台、后台、金融系统,找到nginx/conf/nginx.conf,修改配置: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 upstream web{ server localhost:8082; } upstream admin{ server localhost:8083; } upstream finance{ server localhost:8084; } server { listen 80; server_name finance.xxxx.com; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://finance; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 80; server_name www.xxx.com; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://web; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } server { server_name xxxx.com; rewrite ^(.*) http://www.xxxx.com$1 permanent; } server { listen 80; server_name admin.xxxx.com; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://admin; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } 上面的配置还包括了访问xxxx.com转向www.xxxx.com的配置,如下: 1 2 3 4 server { server_name xxxx.com; rewrite ^(.*) http://www.xxxx.com$1 permanent; } nginx的基本配置大致就是这样,如果绑定多个域名(不管是一级域名还是二级域名),需配置多个server,你会发现这几个server配置都差不多,主要是更改server_name及proxy_pass指向即可。upstream节点其实就是代理服务的访问路径。 如果此时访问域名,你会发现nginx的配置生效了,只是目前显示的是tomcat的默认界面。nginx的配置基本就这样了,接下来对tomcat做些配置的修改。找到tomcat里的conf/server.xml,注释掉默认的Host配置,添加如下Host配置: 1 2 3 4 5 6 <Host name="localhost" appBase="E:\tomcat\apache-tomcat-8.0.35-8082\webapps\web" deployOnStartup ="false" autoDeploy="false" unpackWARs="true"> <Context path="/" docBase="E:\tomcat\apache-tomcat-8.0.35-8082\webapps\web" /> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> 以上是windows服务器下的配置,如为linux,只需更改appBase和docBase,指向项目的路径。tomcat的配置也已经完成,重启tomcat,访问域名就指向了tomcat里的项目。 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/7941099.html,如需转载请自行联系原作者
NBC剧集《我们这一天》宣布一次性续订2、3季,这部Dan Fogelman打造的大热剧是这个秋季档收视人数第二的广播网剧情剧。新续订的两季还是每季18集。 NBC的叫好叫座剧《我们这一天 This Is Us》宣布把Alexandra Breckenridge及Jon Huertas提升为第二季的常规演员。Alexandra Breckenridge在剧中饰演儿子Kevin(Justin Hartley饰)的青梅竹马兼前妻Sophie,现正再续前缘;Jon Huertas饰演Miguel,他是已逝父亲Jack(Milo Ventimiglia饰)的好友,后来与Jack的妻子Rebecca(Mandy Moore饰)结婚,成了三个孩子的继父。至于饰演儿童版Randall的Lonnie Chavis会在次季继续演出,但不会是常规演员。(他在Showtime新剧《白闻名 White Famous》当常规) 类型:喜剧 播出:NBC 地区:美国 主演:曼迪·摩尔 / 米洛·文堤米利亚 语言:英语 首播日期:2017-09-26 英文:This Is Us 别名:我们在一起 播出时间:每周三/1集 类似推荐《橘子郡男孩》 分类: 美剧电影 本文转自快乐就好博客园博客,原文链接:http://www.cnblogs.com/happyday56/p/7348356.html如需转载请自行联系原作者
来源:http://www.cppblog.com/mythit/archive/2009/04/19/80492.aspx 在看下面这篇文章之前,先介绍几个理论知识,有助于理解A*算法。 启发式搜索:启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无畏的搜索路径,提到了效率。在启发式搜索中,对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。 估价函数:从当前节点移动到目标节点的预估费用;这个估计就是启发式的。在寻路问题和迷宫问题中,我们通常用曼哈顿(manhattan)估价函数(下文有介绍)预估费用。 A*算法与BFS:可以这样说,BFS是A*算法的一个特例。对于一个BFS算法,从当前节点扩展出来的每一个节点(如果没有被访问过的话)都要放进队列进行进一步扩展。也就是说BFS的估计函数h永远等于0,没有一点启发式的信息,可以认为BFS是“最烂的”A*算法。 选取最小估价:如果学过数据结构的话,应该可以知道,对于每次都要选取最小估价的节点,应该用到最小优先级队列(也叫最小二叉堆)。在C++的STL里有现成的数据结构priority_queue,可以直接使用。当然不要忘了重载自定义节点的比较操作符。 A*算法的特点:A*算法在理论上是时间最优的,但是也有缺点:它的空间增长是指数级别的。 IDA*算法:这种算法被称为迭代加深A*算法,可以有效的解决A*空间增长带来的问题,甚至可以不用到优先级队列。如果要知道详细:google一下。 A*寻路初探(转载) 作者:Patrick Lester 译者:Panic2005年 译者序:很久以前就知道了A*算法,但是从未认真读过相关的文章,也没有看过代码,只是脑子里有个模糊的概念。这次决定从头开始,研究一下这个被人推崇备至的简单方法,作为学习人工智能的开始。 这篇文章非常知名,国内应该有不少人翻译过它,我没有查找,觉得翻译本身也是对自身英文水平的锻炼。经过努力,终于完成了文档,也明白的A*算法的原理。毫无疑问,作者用形象的描述,简洁诙谐的语言由浅入深的讲述了这一神奇的算法,相信每个读过的人都会对此有所认识(如果没有,那就是偶的翻译太差了--b)。 现在是年月日的版本,应原作者要求,对文中的某些算法细节做了修改。 原文链接:http://www.gamedev.net/reference/articles/article2003.asp 原作者文章链接:http://www.policyalmanac.org/games/aStarTutorial.htm 以下是翻译的正文 会者不难,A*(念作A星)算 法对初学者来说的确有些难度。这篇文章并不试图对这个话题作权威的陈述。取而代之的是,它只是描述算法的原理,使你可以在进一步的阅读中理解其他相关的资 料。最后,这篇文章没有程序细节。你尽可以用任意的计算机程序语言实现它。如你所愿,我在文章的末尾包含了一个指向例子程序的链接。压缩包包括C++和Blitz Basic两个语言的版本,如果你只是想看看它的运行效果,里面还包含了可执行文件。我们正在提高自己。让我们从头开始。。。 序:搜索区域 假设有人想从A点移动到一墙之隔的B点,如下图,绿色的是起点A,红色是终点B,蓝色方块是中间的墙。 [图-1] 你首先注意到,搜索区域被我们划分成了方形网格。像这样,简化搜索区域,是寻路的第一步。这一方法把搜索区域简化成了一个二维数组。数组的每一个元素是网格的一个方块,方块被标记为可通过的和不可通过的。路径被描述为从A到B我们经过的方块的集合。一旦路径被找到,我们的人就从一个方格的中心走向另一个,直到到达目的地。 这些中点被称为“节点”。 当你阅读其他的寻路资料时,你将经常会看到人们讨论节点。为什么不把他们描述为方格呢?因为有可能你的路径被分割成其他不是方格的结构。他们完全可以是矩 形,六角形,或者其他任意形状。节点能够被放置在形状的任意位置-可以在中心,或者沿着边界,或其他什么地方。我们使用这种系统,无论如何,因为它是最简 单的。 开始搜索 正如我们处理上图网格的方法,一旦搜索区域被转化为容易处理的节点,下一步就是去引导一次找到最短路径的搜索。在A*寻路算法中,我们通过从点A开始,检查相邻方格的方式,向外扩展直到找到目标。 我们做如下操作开始搜索: 1,从点A开始,并且把它作为待处理点存入一个“开启列表”。开启列表就像一张购物清单。尽管现在列表里只有一个元素,但以后就会多起来。你的路径可能会通过它包含的方格,也可能不会。基本上,这是一个待检查方格的列表。 2,寻找起点周围所有可到达或者可通过的方格,跳过有墙,水,或其他无法通过地形的方格。也把他们加入开启列表。为所有这些方格保存点A作为“父方格”。当我们想描述路径的时候,父方格的资料是十分重要的。后面会解释它的具体用途。 3,从开启列表中删除点A,把它加入到一个“关闭列表”, 列表中保存所有不需要再次检查的方格。在这一点,你应该形成如图的结构。在图中,暗绿色方格是你起始方格的中心。它被用浅蓝色描边,以表示它被加入到关闭 列表中了。所有的相邻格现在都在开启列表中,它们被用浅绿色描边。每个方格都有一个灰色指针反指他们的父方格,也就是开始的方格。 [图-2] 接着,我们选择开启列表中的临近方格,大致重复前面的过程,如下。但是,哪个方格是我们要选择的呢?是那个F值最低的。 路径评分 选择路径中经过哪个方格的关键是下面这个等式:F = G + H 这里: * G = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费。 * H = 从网格上那个方格移动到终点B的预估移动耗费。这经常被称为启发式的,可能会让你有点迷惑。这样叫的原因是因为它只是个猜测。我们没办法事先知道路径的长度,因为路上可能存在各种障碍(墙,水,等等)。虽然本文只提供了一种计算H的方法,但是你可以在网上找到很多其他的方法。 我们的路径是通过反复遍历开启列表并且选择具有最低F值的方格来生成的。文章将对这个过程做更详细的描述。首先,我们更深入的看看如何计算这个方程。 正如上面所说,G表示沿路径从起点到当前点的移动耗费。在这个例子里,我们令水平或者垂直移动的耗费为,对角线方向耗费为。我们取这些值是因为沿对角线的距离是沿水平或垂直移动耗费的的根号(别怕),或者约.414倍。为了简化,我们用和近似。比例基本正确,同时我们避免了求根运算和小数。这不是只因为我们怕麻烦或者不喜欢数学。使用这样的整数对计算机来说也更快捷。你不就就会发现,如果你不使用这些简化方法,寻路会变得很慢。 既然我们在计算沿特定路径通往某个方格的G值,求值的方法就是取它父节点的G值,然后依照它相对父节点是对角线方向或者直角方向(非对角线),分别增加和。例子中这个方法的需求会变得更多,因为我们从起点方格以外获取了不止一个方格。 H值可以用不同的方法估算。我们这里使用的方法被称为曼哈顿方法,它计算从当前格到目的格之间水平和垂直的方格的数量总和,忽略对角线方向,然后把结果乘以10。 这被称为曼哈顿方法是因为它看起来像计算城市中从一个地方到另外一个地方的街区数,在那里你不能沿对角线方向穿过街区。很重要的一点,我们忽略了一切障碍 物。这是对剩余距离的一个估算,而非实际值,这也是这一方法被称为启发式的原因。想知道更多?你可以在这里找到方程和额外的注解。 F的值是G和H的和。第一步搜索的结果可以在下面的图表中看到。F,G和H的评分被写在每个方格里。正如在紧挨起始格右侧的方格所表示的,F被打印在左上角,G在左下角,H则在右下角。 [图-3] 现在我们来看看这些方格。写字母的方格里,G = 10。这是因为它只在水平方向偏离起始格一个格距。紧邻起始格的上方,下方和左边的方格的G值都等于。对角线方向的G值是。 H值通过求解到红色目标格的曼哈顿距离得到,其中只在水平和垂直方向移动,并且忽略中间的墙。用这种方法,起点右侧紧邻的方格离红色方格有格距离,H值就是。这块方格上方的方格有格距离(记住,只能在水平和垂直方向移动),H值是。你大致应该知道如何计算其他方格的H值了~。每个格子的F值,还是简单的由G和H相加得到 继续搜索 为了继续搜索,我们简单的从开启列表中选择F值最低的方格。然后,对选中的方格做如下处理: 4,把它从开启列表中删除,然后添加到关闭列表中。 5,检查所有相邻格子。跳过那些已经在关闭列表中的或者不可通过的(有墙,水的地形,或者其他无法通过的地形),把他们添加进开启列表,如果他们还不在里面的话。把选中的方格作为新的方格的父节点。 6,如果某个相邻格已经在开启列表里了,检查现在的这条路径是否更好。换句话说,检查如果我们用新的路径到达它的话,G值是否会更低一些。如果不是,那就什么都不做。 另一方面,如果新的G值更低,那就把相邻方格的父节点改为目前选中的方格(在上面的图表中,把箭头的方向改为指向这个方格)。最后,重新计算F和G的值。如果这看起来不够清晰,你可以看下面的图示。 好了,让我们看看它是怎么运作的。我们最初的格方格中,在起点被切换到关闭列表中后,还剩格留在开启列表中。这里面,F值最低的那个是起始格右侧紧邻的格子,它的F值是。因此我们选择这一格作为下一个要处理的方格。在紧随的图中,它被用蓝色突出显示。 [图-4] 首先,我们把它从开启列表中取出,放入关闭列表(这就是他被蓝色突出显示的原因)。然后我们检查相邻的格子。哦,右侧的格子是墙,所以我们略过。左侧的格子是起始格。它在关闭列表里,所以我们也跳过它。 其他格已经在开启列表里了,于是我们检查G值来判定,如果通过这一格到达那里,路径是否更好。我们来看选中格子下面的方格。它的G值是。如果我们从当前格移动到那里,G值就会等于(到达当前格的G值是,移动到上面的格子将使得G值增加)。因为G值大于,所以这不是更好的路径。如果你看图,就能理解。与其通过先水平移动一格,再垂直移动一格,还不如直接沿对角线方向移动一格来得简单。 当我们对已经存在于开启列表中的个临近格重复这一过程的时候,我们发现没有一条路径可以通过使用当前格子得到改善,所以我们不做任何改变。既然我们已经检查过了所有邻近格,那么就可以移动到下一格了。 于是我们检索开启列表,现在里面只有7格了,我们仍然选择其中F值最低的。有趣的是,这次,有两个格子的数值都是。我们如何选择?这并不麻烦。从速度上考虑,选择最后添加进列表的格子会更快捷。这种导致了寻路过程中,在靠近目标的时候,优先使用新找到的格子的偏好。但这无关紧要。(对相同数值的不同对待,导致不同版本的A*算法找到等长的不同路径)那我们就选择起始格右下方的格子,如图: [图-5] 这次,当我们检查相邻格的时候,发现右侧是墙,于是略过。上面一格也被略过。我们也略过了墙下面的格子。为什么呢?因为你不能在不穿越墙角的情况下直接到达那个格子。你的确需要先往下走然后到达那一格,按部就班的走过那个拐角。(注解:穿越拐角的规则是可选的。它取决于你的节点是如何放置的。) 这样一来,就剩下了其他格。当前格下面的另外两个格子目前不在开启列表中,于是我们添加他们,并且把当前格指定为他们的父节点。其余格,两个已经在关闭列表中(起始格,和当前格上方的格子,在表格中蓝色高亮显示),于是我们略过它们。最后一格,在当前格的左侧,将被检查通过这条路径,G值是否更低。不必担心,我们已经准备好检查开启列表中的下一格了。 我们重复这个过程,直到目标格被添加进关闭列表(注解),就如在下面的图中所看到的。 [图-6] 注意,起始格下方格子的父节点已经和前面不同的。之前它的G值是,并且指向右上方的格子。现在它的G值是,指向它上方的格子。这在寻路过程中的某处发生,当应用新路径时,G值经过检查变得低了-于是父节点被重新指定,G和F值被重新计算。尽管这一变化在这个例子中并不重要,在很多场合,这种变化会导致寻路结果的巨大变化。 那么,我们怎么确定这条路径呢?很简单,从红色的目标格开始,按箭头的方向朝父节点移动。这最终会引导你回到起始格,这就是你的路径!看起来应该像图中那样。从起始格A移动到目标格B只是简单的从每个格子(节点)的中点沿路径移动到下一个,直到你到达目标点。就这么简单。 [图-7] A*方法总结 好,现在你已经看完了整个说明,让我们把每一步的操作写在一起: 1,把起始格添加到开启列表。 2,重复如下的工作: a) 寻找开启列表中F值最低的格子。我们称它为当前格。 b) 把它切换到关闭列表。 c) 对相邻的格中的每一个? * 如果它不可通过或者已经在关闭列表中,略过它。反之如下。 * 如果它不在开启列表中,把它添加进去。把当前格作为这一格的父节点。记录这一格的F,G,和H值。 * 如果它已经在开启列表中,用G值为参考检查新的路径是否更好。更低的G值意味着更好的路径。如果是这样,就把这一格的父节点改成当前格,并且重新计算这一格的G和F值。如果你保持你的开启列表按F值排序,改变之后你可能需要重新对开启列表排序。 d) 停止,当你 * 把目标格添加进了关闭列表(注解),这时候路径被找到,或者 * 没有找到目标格,开启列表已经空了。这时候,路径不存在。 3.保存路径。从目标格开始,沿着每一格的父节点移动直到回到起始格。这就是你的路径。 (注解:在这篇文章的较早版本中,建议的做法是当目 标格(或节点)被加入到开启列表,而不是关闭列表的时候停止寻路。这么做会更迅速,而且几乎总是能找到最短的路径,但不是绝对的。当从倒数第二个节点到最 后一个(目标节点)之间的移动耗费悬殊很大时-例如刚好有一条河穿越两个节点中间,这时候旧的做法和新的做法就会有显著不同。) 题外话 离题一下,见谅,值得一提的是,当你在网上或者相关论坛看到关于A*的不同的探讨,你有时会看到一些被当作A*算法的代码而实际上他们不是。要使用A*,你必须包含上面讨论的所有元素--特定的开启和关闭列表,用F,G和H作路径评价。有很多其他的寻路算法,但他们并不是A*,A*被认为是他们当中最好的。Bryan Stout在这篇文章后面的参考文档中论述了一部分,包括他们的一些优点和缺点。有时候特定的场合其他算法会更好,但你必须很明确你在作什么。好了,够多的了。回到文章。 实现的注解 现在你已经明白了基本原理,写你的程序的时候还得考虑一些额外的东西。下面这些材料中的一些引用了我用C++和Blitz Basic写的程序,但对其他语言写的代码同样有效。 1.其他单位(避免碰撞): 如果你恰好看了我的例子代码,你会发现它完全忽略了其他单位。我的寻路者事实上可以相互穿越。取决于具体的游戏,这也许可以,也许不行。如果你打算考虑其 他单位,希望他们能互相绕过,我建议你只考虑静止或那些在计算路径时临近当前单位的单位,把它们当前的位置标志为可通过的。对于临近的运动着的单位,你可 以通过惩罚它们各自路径上的节点,来鼓励这些寻路者找到不同的路径(更多的描述见#2). 如果你选择了把其他正在移动并且远离当前寻路单位的那些单位考虑在内,你将需要实现一种方法及时预测在何时何地碰撞可能会发生,以便恰当的避免。否则你极有可能得到一条怪异的路径,单位突然转弯试图避免和一个已经不存在的单位发生碰撞。 当然,你也需要写一些碰撞检测的代码,因为无论计算的时候路径有多完美,它也会因时间而改变。当碰撞发生时,一个单位必须寻找一条新路径,或者,如果另一个单位正在移动并且不是正面碰撞,在继续沿当前路径移动之前,等待那个单位离开。 这些提示大概可以让你开始了。如果你想了解更多,这里有些你可能会觉得有用的链接: *自治角色的指导行为:Craig Reynold在指导能力上的工作和寻路有些不同,但是它可以和寻路整合从而形成更完整的移动和碰撞检测系统。 *电脑游戏中的长短距指导:指导和寻路方面著作的一个有趣的考察。这是一个pdf文件。 *协同单位移动:一个两部分系列文章的第一篇,内容是关于编队和基于分组的移动,作者是帝国时代(Age of Empires)的设计者Dave Pottinger. *实现协同移动:Dave Pottinger文章系列的第二篇。 2. 不同的地形损耗:在这个教程和我附带的程序中,地形只能是二者之-可通过 的和不可通过的。但是你可能会需要一些可通过的地形,但是移动耗费更高-沼泽,小山,地牢的楼梯,等等。这些都是可通过但是比平坦的开阔地移动耗费更高的 地形。类似的,道路应该比自然地形移动耗费更低。 这个问题很容易解决,只要在计算任何地形的G值的时候增加地形损耗就可以了。简单的给它增加一些额外的损耗就可以了。由于A*算法已经按照寻找最低耗费的路径来设计,所以很容易处理这种情况。在我提供的这个简单的例子里,地形只有可通过和不可通过两种,A*会找到最短,最直接的路径。但是在地形耗费不同的场合,耗费最低的路径也许会包含很长的移动距离-就像沿着路绕过沼泽而不是直接穿过它。 一种需额外考虑的情况是被专家称之为“influence mapping”的东西(暂译为影响映射图)。就像上面描述的不同地形耗费一样,你可以创建一格额外的分数系统,并把它应用到寻路的AI中。假设你有一张有大批寻路者的地图,他们都要通过某个山区。每次电脑生成一条通过那个关口的路径,它就会变得更拥挤。如果你愿意,你可以创建一个影响映射图对有大量屠杀事件的格子施以不利影响。这会让计算机更倾向安全些的路径,并且帮助它避免总是仅仅因为路径短(但可能更危险)而持续把队伍和寻路者送到某一特定路径。 另一个可能得应用是惩罚周围移动单位路径上得节点。A*的一个底限是,当一群单位同时试图寻路到接近的地点,这通常会导致路径交叠。以为一个或者多个单位都试图走相同或者近似的路径到达目的地。对其他单位已经“认领”了 的节点增加一些惩罚会有助于你在一定程度上分离路径,降低碰撞的可能性。然而,如果有必要,不要把那些节点看成不可通过的,因为你仍然希望多个单位能够一 字纵队通过拥挤的出口。同时,你只能惩罚那些临近单位的路径,而不是所有路径,否则你就会得到奇怪的躲避行为例如单位躲避路径上其他已经不在那里的单位。 还有,你应该只惩罚路径当前节点和随后的节点,而不应处理已经走过并甩在身后的节点。 3. 处理未知区域:你是否玩过这样的PC游戏,电脑总是知道哪条路是正确的,即使它还没有侦察过地图?对于游戏,寻路太好会显得不真实。幸运的是,这是一格可以轻易解决的问题。 答案就是为每个不同的玩家和电脑(每个玩家,而不是每个单位--那样的话会耗费大量的内存)创建一个独立的“knownWalkability”数组,每个数组包含玩家已经探索过的区域,以及被当作可通过区域的其他区域,直到被证实。用这种方法,单位会在路的死端徘徊并且导致错误的选择直到他们在周围找到路。一旦地图被探索了,寻路就像往常那样进行。 4. 平滑路径:尽管A*提供了最短,最低代价的路径,它无法自动提供看起来平滑的路径。看一下我们的例子最终形成的路径(在图)。最初的一步是起始格的右下方,如果这一步是直接往下的话,路径不是会更平滑一些吗?有几种方法来解决这个问题。当计算路径的时候可以对改变方向的格子施加不利影响,对G值增加额外的数值。也可以换种方法,你可以在路径计算完之后沿着它跑一遍,找那些用相邻格替换会让路径看起来更平滑的地方。想知道完整的结果,查看Toward More Realistic Pathfinding,一篇(免费,但是需要注册)Marco Pinter发表在Gamasutra.com的文章 5. 非方形搜索区域:在我们的例子里,我们使用简单的D方形图。你可以不使用这种方式。你可以使用不规则形状的区域。想想冒险棋的游戏,和游戏中那些国家。你可以设计一个像那样的寻路关卡。为此,你可能需要建立一个国家相邻关系的表格,和从一个国家移动到另一个的G值。你也需要估算H值的方法。其他的事情就和例子中完全一样了。当你需要向开启列表中添加新元素的时候,不需使用相邻的格子,取而代之的是从表格中寻找相邻的国家。 类似的,你可以为一张确定的地形图创建路径点系统,路径点一般是路上,或者地牢通道的转折点。作为游戏设计 者,你可以预设这些路径点。两个路径点被认为是相邻的如果他们之间的直线上没有障碍的话。在冒险棋的例子里,你可以保存这些相邻信息在某个表格里,当需要 在开启列表中添加元素的时候使用它。然后你就可以记录关联的G值(可能使用两点间的直线距离),H值(可以使用到目标点的直线距离),其他都按原先的做就可以了。Amit Patel 写了其他方法的摘要。另一个在非方形区域搜索RPG地图的例子,查看我的文章Two-Tiered A* Pathfinding。(译者注:译文: A*分层寻路) 6. 一些速度方面的提示:当你开发你自己的A*程序,或者改写我的,你会发现寻路占据了大量的CPU时间,尤其是在大地图上有大量对象在寻路的时候。如果你阅读过网上的其他材料,你会明白,即使是开发了星际争霸或帝国时代的专家,这也无可奈何。如果你觉得寻路太过缓慢,这里有一些建议也许有效: * 使用更小的地图或者更少的寻路者。 * 不要同时给多个对象寻路。取而代之的是把他们加入一个队列,把寻路过程分散在几个游戏周期中。如果你的游戏以周期每秒的速度运行,没人能察觉。但是当大量寻路者计算自己路径的时候,他们会发觉游戏速度突然变慢。 * 尽量使用更大的地图网格。这降低了寻路中搜索的总网格数。如果你有志气,你可以设计两个或者更多寻路系统以便使用在不同场合,取决于路径的长度。这也正是专业人士的做法,用大的区域计算长的路径,然后在接近目标的时候切换到使用小格子/区域的精细寻路。如果你对这个观点感兴趣,查阅我的文章Two-Tiered A* Pathfinding。(译者注:译文:A*分层寻路) * 使用路径点系统计算长路径,或者预先计算好路径并加入到游戏中。 * 预处理你的地图,表明地图中哪些区域是不可到达的。我把这些区域称作“孤岛”。事实上,他们可以是岛屿或其他被墙壁包围等无法到达的任意区域。A*的下限是,当你告诉它要寻找通往那些区域的路径时,它会搜索整个地图,直到所有可到达的方格/节点都被通过开启列表和关闭列表的计算。这会浪费大量的CPU时间。可以通过预先确定这些区域(比如通过flood-fill或类似的方法)来避免这种情况的发生,用某些种类的数组记录这些信息,在开始寻路前检查它。 * 在一个拥挤的类似迷宫的场合,把不能连 通的节点看作死端。这些区域可以在地图编辑器中预先手动指定,或者如果你有雄心壮志,开发一个自动识别这些区域的算法。给定死端的所有节点可以被赋予一个 唯一的标志数字。然后你就可以在寻路过程中安全的忽略所有死端,只有当起点或者终点恰好在死端的某个节点的时候才需要考虑它们。 7. 维护开启列表:这是A*寻路算法最重要的组成部分。每次你访问开启列表,你都需要寻找F值最低的方格。有几种不同的方法实现这一点。你可以把路径元素随意保存,当需要寻找F值最低的元素的时候,遍历开启列表。这很简单,但是太慢了,尤其是对长路径来说。这可以通过维护一格排好序的列表来改善,每次寻找F值最低的方格只需要选取列表的首元素。当我自己实现的时候,这种方法是我的首选。 在小地图。这种方法工作的很好,但它并不是最快的解决方案。更苛求速度的A*程序员使用叫做二叉堆的方法,这也是我在代码中使用的方法。凭我的经验,这种方法在大多数场合会快~倍,并且在长路经上速度呈几何级数提升(10倍以上速度)。如果你想了解更多关于二叉堆的内容,查阅我的文章,Using Binary Heaps in A* Pathfinding。(译者注:译文:在A*寻路中使用二叉堆) 另一个可能的瓶颈是你在多次寻路之间清除和保存你的数据结构的方法。我个人更倾向把所有东西都存储在数组里 面。虽然节点可以以面向对象的风格被动态的产生,记录和保存,我发现创建和删除对象所增加的大量时间,以及多余的管理层次减慢的整个过程的速度。但是,如 果你使用数组,你需要在调用之间清理数据。这中情形你想做的最后一件事就是在寻路调用之后花点时间把一切归零,尤其是你的地图很大的时候。 我通过使用一个叫做whichList(x,y)的二维数组避免这种开销,数组的每个元素表明了节点在开启列表还是在关闭列表中。尝试寻路之后,我没有清零这个数组。取而代之的是,我在新的寻路中重置onClosedList和onOpenList的数值,每次寻路两个都+5或者类似其他数值。这种方法,算法可以安全的跳过前面寻路留下的脏数据。我还在数组中储存了诸如F,G和H的值。这样一来,我只需简单的重写任何已经存在的值而无需被清除数组的操作干扰。将数据存储在多维数组中需要更多内存,所以这里需要权衡利弊。最后,你应该使用你最得心应手的方法。 8. Dijkstra的算法:尽管A*被认为是通常最好的寻路算法(看前面的“题外话”),还是有一种另外的算法有它的可取之处-Dijkstra算法。Dijkstra算法和A*本质是相同的,只有一点不同,就是Dijkstra算法没有启发式(H值总是)。由于没有启发式,它在各个方向上平均搜索。正如你所预料,由于Dijkstra算法在找到目标前通常会探索更大的区域,所以一般会比A*更慢一些。 那么为什么要使用这种算法呢?因为有时候我们并不知道目标的位置。比如说你有一个资源采集单位,需要获取某种类型的资源若干。它可能知道几个资源区域,但是它想去最近的那个。这种情况,Dijkstra算法就比A*更适合,因为我们不知道哪个更近。用A*,我们唯一的选择是依次对每个目标许路并计算距离,然后选择最近的路径。我们寻找的目标可能会有不计其数的位置,我们只想找其中最近的,而我们并不知道它在哪里,或者不知道哪个是最近的。 看完上面的介绍,再来看一个比较经典的题目:knight moves。貌似也叫汉密尔顿路径,具体的我也不记得了。对这个问题我用A*算法来求解,正所谓光说不练是没有用的 http://acm.pku.edu.cn/JudgeOnline/problem?id=2243 problem statement A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy. Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part. Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b. Input Specification The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard. Output Specification For each test case, print one line saying "To get from xx to yy takes n knight moves.". Sample Input e2 e4 a1 b2 b2 c3 a1 h8 a1 h7 h8 a1 b1 c3 f6 f6 Sample Output To get from e2 to e4 takes 2 knight moves. To get from a1 to b2 takes 4 knight moves. To get from b2 to c3 takes 2 knight moves. To get from a1 to h8 takes 6 knight moves. To get from a1 to h7 takes 5 knight moves. To get from h8 to a1 takes 6 knight moves. To get from b1 to c3 takes 1 knight moves. To get from f6 to f6 takes 0 knight moves.题目的意思大概是说:在国际象棋的棋盘上,一匹马共有8个可能的跳跃方向,求从起点到目标点之间的最少跳跃次数。 A* code: 1 #include <iostream> 2 #include <queue> 3 using namespace std; 4 5 struct knight{ 6 int x,y,step; 7 int g,h,f; 8 bool operator < (const knight & k) const{ //重载比较运算符 9 return f > k.f;10 }11 }k;12 bool visited[8][8]; //已访问标记(关闭列表)13 int x1,y1,x2,y2,ans; //起点(x1,y1),终点(x2,y2),最少移动次数ans14 int dirs[8][2]={{-2,-1},{-2,1},{2,-1},{2,1},{-1,-2},{-1,2},{1,-2},{1,2}};//8个移动方向15 priority_queue<knight> que; //最小优先级队列(开启列表)16 17 bool in(const knight & a){ //判断knight是否在棋盘内18 if(a.x<0 || a.y<0 || a.x>=8 || a.y>=8)19 return false;20 return true;21 }22 int Heuristic(const knight &a){ //manhattan估价函数23 return (abs(a.x-x2)+abs(a.y-y2))*10;24 }25 void Astar(){ //A*算法26 knight t,s;27 while(!que.empty()){28 t=que.top(),que.pop(),visited[t.x][t.y]=true;29 if(t.x==x2 && t.y==y2){30 ans=t.step;31 break;32 }33 for(int i=0;i<8;i++){34 s.x=t.x+dirs[i][0],s.y=t.y+dirs[i][1];35 if(in(s) && !visited[s.x][s.y]){36 s.g = t.g + 23; //23表示根号5乘以10再取其ceil37 s.h = Heuristic(s);38 s.f = s.g + s.h;39 s.step = t.step + 1;40 que.push(s);41 }42 }43 }44 }45 int main(){46 char line[5];47 while(gets(line)){48 x1=line[0]-'a',y1=line[1]-'1',x2=line[3]-'a',y2=line[4]-'1';49 memset(visited,false,sizeof(visited));50 k.x=x1,k.y=y1,k.g=k.step=0,k.h=Heuristic(k),k.f=k.g+k.h;51 while(!que.empty()) que.pop();52 que.push(k);53 Astar();54 printf("To get from %c%c to %c%c takes %d knight moves.\n",line[0],line[1],line[3],line[4],ans);55 }56 return 0;57 }58 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3660540.html,如需转载请自行联系原作者
同步首发:http://www.yuanrengu.com/index.php/20171226.html 在实际的项目开发中有时会有对数据库某字段截取部分的需求,这种场景有时直接通过数据库操作来实现比通过代码实现要更方便快捷些,mysql有很多字符串函数可以用来处理这些需求,如Mysql字符串截取总结:left()、right()、substring()、substring_index()。 一.从左开始截取字符串 用法:left(str, length),即:left(被截取字符串, 截取长度) SELECT LEFT('www.yuanrengu.com',8) 结果为:www.yuan 二.从右开始截取字符串 用法:right(str, length),即:right(被截取字符串, 截取长度) SELECT RIGHT('www.yuanrengu.com',6) 结果为:gu.com 三.截取特定长度的字符串 用法: substring(str, pos),即:substring(被截取字符串, 从第几位开始截取) substring(str, pos, length),即:substring(被截取字符串,从第几位开始截取,截取长度) 1.从字符串的第9个字符开始读取直至结束 SELECT SUBSTRING('www.yuanrengu.com', 9) 结果为:rengu.com 2.从字符串的第9个字符开始,只取3个字符 SELECT SUBSTRING('www.yuanrengu.com', 9, 3) 结果为:ren 3.从字符串的倒数第6个字符开始读取直至结束 SELECT SUBSTRING('www.yuanrengu.com', -6) 结果为:gu.com 4.从字符串的倒数第6个字符开始读取,只取2个字符 SELECT SUBSTRING('www.yuanrengu.com', -6, 2) 结果为:gu 四.按关键字进行读取 用法:substring_index(str, delim, count),即:substring_index(被截取字符串,关键字,关键字出现的次数) 1.截取第二个“.”之前的所有字符 SELECT SUBSTRING_INDEX('www.yuanrengu.com', '.', 2); 结果为:www.yuanrengu 2.截取倒数第二个“.”之后的所有字符 SELECT SUBSTRING_INDEX('www.yuanrengu.com', '.', -2); 结果为:yuanrengu.com 3.如果关键字不存在,则返回整个字符串 SELECT SUBSTRING_INDEX('www.yuanrengu.com', 'sprite', 1); 结果为:www.yuanrengu.com 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/8117754.html,如需转载请自行联系原作者
1 /* 模块名 : 树 2 /* 文件名 : btree.cpp 3 /* 功能描述 : 二叉树的递归遍历 4 5 /* 备注 : 输入示例与输出结果 6 /* e.g. input : ABD###CE#F### 7 /* bi-tree : 8 /* A 9 /* / \ 10 /* B C 11 /* / / 12 /* D E 13 /* \ 14 /* F 15 /* 16 /* pre-order traverse: A B D C E F 17 /* in-order traverse: D B A E F C 18 /* post-order traverse: D B F E C A 19 *******************************************************************************/ 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string> 23 24 /****************************************************************************** 25 /* 数据类型和常量定义 26 /******************************************************************************/ 27 #define OK 1 28 #define ERROR 0 29 #define OVERFLOW -2 30 31 typedef int Status; 32 typedef int TElemType; 33 34 35 /****************************************************************************** 36 /* 数据结构声明 37 /******************************************************************************/ 38 /* 二叉树的链式存储结构 */ 39 typedef struct BiTNode { 40 TElemType data; 41 struct BiTNode *lchild, *rchild; /* 左右孩子指针 */ 42 } BiTNode, *BiTree; 43 44 45 /****************************************************************************** 46 /* 函数原型声明 47 /******************************************************************************/ 48 Status Visit(TElemType e); 49 Status PreOrderTraverse(BiTree T, Status (*Visit)(TElemType)); 50 Status InOrderTraverse(BiTree T, Status (*Visit)(TElemType)); 51 Status PostOrderTraverse(BiTree T, Status (*Visit)(TElemType)); 52 53 54 //功能 : 打印节点数据 55 Status Visit(TElemType e) 56 { 57 printf("%c", e); 58 return OK; 59 } 60 61 //功能 : 前序遍历二叉树 62 Status PreOrderTraverse(BiTree T, Status (*Visit)(TElemType)) 63 { 64 if(T){ 65 if(Visit(T->data)) 66 if(PreOrderTraverse(T->lchild, Visit)) 67 if(PreOrderTraverse(T->rchild, Visit)) 68 return OK; 69 return ERROR; 70 } 71 else 72 return OK; 73 } 74 75 76 //功能 : 中序遍历二叉树 77 Status InOrderTraverse(BiTree T, Status (*Visit)(TElemType)) 78 { 79 if(T){ 80 if(InOrderTraverse(T->lchild, Visit)) 81 if(Visit(T->data)) 82 if(InOrderTraverse(T->rchild, Visit)) 83 return OK; 84 return ERROR; 85 } 86 else 87 return OK; 88 } 89 90 //功能 : 后序遍历二叉树 91 Status PostOrderTraverse(BiTree T, Status (*Visit)(TElemType)) 92 { 93 if(T){ 94 if(PostOrderTraverse(T->lchild, Visit)) 95 if(PostOrderTraverse(T->rchild, Visit)) 96 if(Visit(T->data)) 97 return OK; 98 return ERROR; 99 } 100 else 101 return OK; 102 } 103 104 105 //功能 : 创建二叉树 106 //备注 : 前序方式创建 107 Status CreateBiTree(BiTree &T) 108 { 109 char ch = getchar(); 110 if('#' == ch) T = NULL; 111 else { 112 if(!(T = (BiTNode *)malloc(sizeof(BiTNode)))) exit(OVERFLOW); 113 T->data = ch; //生成根结点 114 CreateBiTree(T->lchild); //构造左子树 115 CreateBiTree(T->rchild); //构造右子树 116 } 117 return OK; 118 } 119 120 void main() 121 { 122 BiTree T; 123 CreateBiTree(T); 124 125 printf("Pre Order Traverse: "); 126 PreOrderTraverse(T, Visit); //前序方式遍历二叉树 127 128 printf("\nIn Order Traverse: "); 129 InOrderTraverse(T, Visit); //中序方式遍历二叉树 130 131 printf("\nPost Order Traverse: "); 132 PostOrderTraverse(T, Visit); //后序方式遍历二叉树 133 } 来源:http://www.cnblogs.com/JCSU/articles/2005904.html 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3292436.html,如需转载请自行联系原作者
最近面试总遇到这种根据给出的两类序遍历,然后求按另一种形式序的遍历。看来有必要好好总结下这个知识点,省的每次笔试时都得花不少时间推导。 首先,我们看看前序、中序、后序遍历的特性: 前序遍历:(根—>左—>右) 1.访问根节点 2.前序遍历左子树 3.前序遍历右子树 中序遍历:(左—>根—>右) 1.中序遍历左子树 2.访问根节点 3.中序遍历右子树 后序遍历:(左—>右—>根) 1.后序遍历左子树 2.后序遍历右子树 3.访问根节点 三序中知道其中两个就可以推出第三个,但前提是我们必须知道中序(这里是针对二叉树的,不包括二叉搜索树).因为:先序和后序给我们提供的信息是一样的--告诉我们谁是根节点,中序则告诉我们左右子树在哪儿。 例:已知先序为eacbdgf,中序为abcdefg,求后序。 由先序我们知道e为根节点,我们在中序中把左右子树括起来 --(abcd)e(fg) 同样对左子树abcd进行分析,先序为acbd,中序为abcd.--a(bcd) 递归下去就可以了 后序为bdcafge 扩展: 在2014年阿里实习生招聘试题中就有一个问题: 下面关于二叉搜索树的是否正确? 给定一棵二叉搜索树的前序和后序遍历结果,无法确定这棵二叉搜索树。 这个说法是错误的。 二叉树(不是搜索二叉树),必须是中根加上先根或者后根就能构造出树,但是,这里面说了是二叉搜索树,已经暗含中根了 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3366417.html,如需转载请自行联系原作者
来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情。其实学习IOS开发无外乎平时的积累与总结。下面为大家整理了一部分的iOS学习笔记总结整理,希望对大家有所帮助。 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象。当用户的代码运行告一段 落,开始等待用户的操作,自动释放池就会被释放掉(调用dealloc),池中的对象都会收到一个release,有可能会因此被销毁。2-成员属性: readonly:不指定readonly,默认合成getter和setter方法。外界毫不关心的成员,则不要设置任何属性,这样封装能增加代码的独立性和安全性。相当于私有成员? assign:表示只进行简单的赋值,不会发送retain消息。 retain:会向旧值发送release消息,向新值发送retain消息。 copy:向旧值发release消息,向新值发送copy消息。3-引用计数特殊情况: NSArray:当把一个对象添加到NSArray时,对象的引用计数会加1,移除时会减1。 UIView:addGestureRecognizer会对手势识别器的引用计数加1,removeGestureRecognizer会减1。二 .图形API 这个讲的好,清晰明确:http://www.cocoachina.com/bbs/read.php?tid=77731&page=11-Quartz2D,的绘图总是发生在图形环境(Graphics Context)中。视图会在调用drawRect:方法进行绘图之前,创建好图形环境, 通过UIGraphicsGetCurrentContext函数来获得这个图形环境。 如果直接在图像或者PDF上绘图,需要调用CGBitmapContextCreate或者CGPDFContextCreate函数来创建图形环境。 Quartz2D绘图的基础元素是路径。路径可以是一些基础几何形状,也可以是这些几何形状的组合。 当需要创建一条路径时,应当调用CGContextBeginPath函数; 当需要将路径绘制的起点移动到一个位置时,应当调用CGContextMoveToPoint函数; 当想绘制一条线段时,应当调用CGContextAddLineToPoint。 CTM(当前变换矩阵)将绘图从用户空间映射到设备控件。 当图形环境刚刚创建时,CTM初始化为一个单位矩阵。 对CTM进行平移变换应当调用CGContextTranslateCTM函数,进行旋转变换应当调用CGContextRotateCTM函数,进行缩放变换应当调用CGContextScaleCTM函数。2-UIBezierPath 使用UIBezierPath绘图的好处: -采用系统坐标系 -在Core Graphics的基础上封装,具有Core Graphics的主要功能,无需考虑图形环境。 UIBezierPath* pathLines = [UIBezierPath bezierPath]; [pathLines moveToPoint:point1]; // 移动到point1位置 [pathLines addLineToPoint:point2]; // 画一条从point1到point2的线 pathLines.lineWidth = 5.0; // 线宽 [UIColor redColor] set]; // 颜色设置 [pathLines stroke]; // 开始描绘 在同一UIBazierPath中,只能采用相同的颜色和线宽。 可以调用closePath,从当前点画一条直线到当前子路径的初始点。如果要填充路径,应当使用fill方法,此方法会填充路径中得所有封闭子路径。三.容器 -NSArray和NSMutableArray +array:创建一个空数组 +arrayWithArray:从另一个数组创建新的数组 +arrayWithContentsOfFile:读文件创建数组 +arrayWithObject:创建一个数组,其中包含一个给定对象 +arrayWithObjects +arrayWithObjects:count: 从C数组创建 -containsObject:是否包含一个元素 -count:数量 -lastObject:返回最后一个 -objectAtIndex:返回某一个 -objectsAtIndexes:返回一组,类型为NSArray -indexOfObject:返回对象索引 -arrayByAddingObject:原数组最后加一个对象,产生一个新的数组 -arrayByAddingObjectsFromArray:在原数组的最后添加另一个数组中的所有对象,产生一个新数组 -subarrayWithRange:抽取原数组中得一部分,产生一个新的数组 -isEqualToArray:比较两个数组是否相同 -writeToFile:atomically:保存数组至一个文件 -writeToURL:atomically:保存数组至一个URL -addObject:在数组最后添加一个对象 -addObjectsFromArray:在原数组最后添加另一个数组的全部对象 -insertObject:atIndex:向原数组制定位置添加一个对象 -insertObjects:atIndexes:向原数组中一系列位置添加一系列对象 -removeAllObjects:移除数组中的全部对象 -removeLastObject:移除数组中最后一个对象 -removeObject:移除一个对象 -removeObjectAtIndex:移除位于指定位置的对象 -removeObjectsAtIndexes:移除位于一系列位置的对象 -replaceObjectAtIndex:withObject用给定对象替换位于指定位置的对象 -replaceObjectsAtIndexes:withObjects:多对象,多位置版本 -setArray:用另一个数组中的所有对象来替换当前数组中的所有对象 -NSDictionary与NSMutableDictionary +dictionary +dictionaryWithContentsOfFile +dictionaryWithContentsOfURL +dictionaryWithDictionary +dictionaryWithObject:forKey +dictionaryWithObjects:forKeys +dictionaryWithObjectsAndKeys -count:数量 -allKeys:返回一个数组,包含字典中的所有关键字。 -allKeysForObject:返回一个数组,包含所有对应到给定对象的关键字。 -valueForKey:通过字符串查找数值。 -writeToFile:atomically -writeToURL:atomically -setValue:forKey: 加键-值对 -addEntriesFromDictionary: 添加另一个字典中得所有条目 -setDictionary:将原字典中条目设置为另一个字典中得所有条目 -removeObjectForKey:移除一个关键字的对应条目 -removeAllObjects:移除所有条目 -removeObjectsForKeys:移除一系列关键字的对应条目四.文件系统1- 概述 bundle(沙盒):一个应用只能在自己的沙盒中读取或存储文件,而不能操作其他沙盒中的文件。好处:保护应用的隐私不受侵犯,保护系统文件的安排,应用删除后相关文件也能被全部清除。 每个应用都有自己的沙盒,沙盒的根目录的获取方法是NSHomeDirectory()。 根目录下的内容: -.app文件,实际上是一个文件夹,包含了可执行文件、Nib文件、图片资源、plist等。XCode中能看到的资源,及编译后的可执行文件,都封装在app中。 -Documents文件夹,用于存放你的应用所产生的数据,该文件夹可通过iTunes备份,可以存储游戏进度等。 -Library文件夹,用于存放用户偏好和临时文件。 -tmp文件夹是系统的中转站。2-文件管理器 NSFileManager,defaultManager()返回一个文件管理器的单例(多线程下不安全)。init(),在多线程编程中应尽量使用init()。 代理方法:-fileManager:shouldRemoveItemAtPath和-fileManager:shouldRemoveItemAtURL在移除操作之前被调用。 -removeItemAtPath:error:删除位于指定路径的文件、连接、目录(及其所有子目录、文件)。 -removeItemAtURL:error:同上。 -contentOfDirectoryAtPath:查找所有位于给定路径的子路径和文件。返回值为一个数组,其中包含了NSString对象。查找只在当前目录进行,不会进入下一层目录。 -subpathsAtPath:查找给定路径下的所有子路径。深度查找,不限于当前层,也会查找package的内容。 -fileExistsAtPath:判断文件是否位于一个路径下面。 -isReadableFileAtPath:查询文件的可读性 -isWritableFileAtPath:可写性 -isExecutableFileAtPath:查询文件的可执行性 -isDeletableFileAtPath:可删除性3-NSString的路径功能 -pathWithComponent:参数是一堆components构成的数组,返回的路径是由这些components连接而成的路径字符串,相邻components之间用/隔开。 -pathComponents:返回一个数组,包含路径中的components。 -fileSystemRepresentation:返回C字符串 -isAbsolutePath:判断是否为绝对路径 -pathExtension:返回文件的扩展名,没有的就返回空字符串 -stringByAppendingPathComponents :向现有路径添加一个component。斜杠/会被自动加上 -stringByAppendingPathExtension:向现有路径加上文件的扩展名 -stringByDeletingLastPathComponent:移除最后一个路径component -stringByDeletingPathExtension:删除路径扩展名 -stringByAppendingPaths:参数为一个数组,此方法将数组中的字符串对象作为路径一次添加到源字符串后面。 例子: NSString *homePath = NSHomeDirectory(); NSString *docPath = [homePath stringByAppendingFormat:@"/Documents"]; 五.UIActionSheet 按钮列表六.旋转 1- interfaceOrientation属性查询当前的界面方向。 2- rotatingHeaderView方法来查询当前导航视图。 3- rotatingFooterView来查询当前的标签条。七.快速拨打电话接口 openURL能帮助你运行Maps,SMS,Browser,Phone甚至其他的应用程序。这是Iphone开发中我经常需要用到的一段代码,它仅仅只有一行而已。 [UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://8004664411"]; 这个程序通过基础的协议支持拨打电话的功能。 摘自:http://blog.csdn.net/smilelance/article/details/6213125八.区分设备类型的方法 打电话功能只有iPhone支持,对于其他设备对应按钮应该禁用。1. 用[UIDevice currentDevice].model,这个返回的是一个NSString,你可以做如下判断就能知道设备是iPad还是iPhone. if ([UIDevice currentDevice].model rangeOfString:@"iPad"].location != NSNotFound) { NSLog(@"This is an iPad!"); } 2. 用UI_USER_INTERFACE_IDIOM()方法,这是系统定义的一条宏。使用方法也很简单。 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { NSLog(@"This is an iPad!"); } 摘自:http://blog.sina.com.cn/s/blog_3f88614f0100sdcm.html九.并发编程 1-GCD-Grand Central Dispatch,GCD使用队列来管理多个任务,而每个任务是 以块(其定义类似于函数)来描述的。GCD从队列中读取这些要完成的任务,然后其多核执行 引擎负责将这些任务分配给它所管理的线程。和手动线程管理相比,GCD能极大地优化线程管理,并极大地减少创建和销毁线程所带来的额外开销。除了在多核系 统上得性能改进之外,GCD还能帮助提高应用的响应速度,并让代码更为干净,易于维护。 2-NSOperationQueue-操作队列,可以极大地减少开发者在并发编程中的负担,并且操作队列有一套Objective-C的API,使用起来方便。 基本操作单位-NSOperation,操作。 操作是封装了一个与任务有关的代码与数据的抽象类,需要继承NSOperation,并且描述相关的任务。操作对象是一次性的,它只能执行一次,下一次,需要创建一个新的实例。 可以通过addDependency:方法为操作添加相互依赖性。假设操作A依赖于操作B,如果操作B没有结束,操作A就不会开始执行。完成是指 执行完,或者取消了操作。有时需要对操作是否成功作出判断。通过removeDependency:方法来移除操作的相互依赖性。 操作的一个属性是isConcurrent。当使用操作队列来管理这些操作时,isConcurrent应当设置为NO,这时应当重载 NSOperation的main函数(在类中保存controller对象-weak,并在main中调用controller的方法)。 isReady属性用于描述操作是否已经可以开始执行,isExecuting属性表示操作是否正在执行当中,isFinished属性表示操作是否顺利 完成,isCancelled属性则表示操作已经取消。 可以在操作运行中取消它的运行,只需要给它发送cancel消息即可。在继承NSOperation类时,也需要支持cancel方法。 如果只需要简单的操作,不想继承NSOperation类,可以使用NSInvocationOperation类,这个类中的-initWithTarget:selector:object:方法能帮助你方便地选择人物的对象和相应的功能。 操作的执行顺序取决于各自的优先级和相互之间的依赖性。 操作队列有两种方式来执行其中的操作。第一种是开辟新线程来运行这些操作,第二种则是通过GCD来运行这些操作。但是无论如何,都不需要手动管理 线程。尽量使用操作队列,只有在操作队列的效率明显不足时才转向GCD。因为操作队列是封装在GCD的基础之上的,虽然增加了一些额外开销,但是也具有更 加完善的功能。例子是TestNSOperation。 下页内容更加精彩实用 十.忙碌指示器 UIActivityIndicator。 UIActivityIndicatorView *activityIndicatior = [UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge]; activityIndicator.center = CGPointMake(512, 384); [self.view addSubview: activityIndicator]; [activityIndicator startAnimating]; [activityIndicator stopAnimating]; [activityIndicator removeFromSuperView]; 十一.媒体播放1- 音频 [1] 音乐往往是存储在iPod曲库(注意位置)中的,可以通过媒体选择器(media picker)或者媒体查询(media query)读取,然后用音乐播放器MPMusicPlayerController播放。 MPMusicPlayerController *musicPlayer = [MPMusicPlayerController applicationMusicPlayer]; [musicPlayer setShufleMode: MPMusicShuffleModeSongs]; [musicPlayer setRepeatMode: MPMusicRepeatModeAll]; [musicPlayer setQueueWithQuery: [MPMediaQuery songsQuery]; [musicPlayer play]; applicationMusicPlayer返回的播放器,在你的应用中播放音乐。它不会影响到iPod播放器,也不能从iPod播放器重获取信息。 iPodMusicPlayer返回的是iPod播放器,在你推出应用后,所有的设置都会影响到之后设备上的iPod播放器。 获得音乐播放器后,需要为它设置一个播放队列。可以用setQueueWithQuery:放方法,通过媒体查询MPMediaQuery来设置 播放队列,也可以用setQueueWithItemCollection:方法,通过MPMdiaItemCollection来设置播放队列。 重复模式repeatMode可以设置为不重复、重复当前曲目、或整个播放列表;乱序播放shuffleMode可以设置为不乱序、乱序播放曲目或乱序播放专辑;音量volume的设置与音频播放器一样。 skipToNextItem跳到下一首,skipToPreviousItem跳到上一首,skipToBegin跳到第一首。 对应的宏都是以MPMusic开头。 [2] 利用系统声音服务来播放短暂音效(时长30秒以内),并震动: AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); 播放指定音效: NSURL *fileURL = [NSURL fileURLWithPath: path isDirectory: NO]; // 创建音效ID SystemSoundID soundID; AudioServiceCreateSystemSoundID((CFURLRef) fileURL, &soundID); // 播放声音 AudioServicesPlaySystemSound(soundID); [3] 音频播放器 没有时长限制 NSURL *fileURL = [NSURL fileURLWithPath: path isDirectory: NO]; // 用URL来初始化音频播放器-播放的不是iPod曲库中的音乐 AVAudioPlayer* player = [AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: NO]; // 准备播放 [player prepareToPlay]; // 设置代理 [player setDelegate: self]; 方法:play、pause、stop。可以通过playing属性查询播放器是否正在播放当中,可以通过volume属性来修改和查询播放器的播放增益(从0.0到1.0),可通过setting属性查询播放器其他设置。 duration表示音频的时间长度, currentTime表示当前播放到的时间。播放结束后可以通过代理方法audioPlayerDidFinishPlaying:来处理播放后设置。 2- 视频 视频播放可以采用网页视图(UIWebView)进行嵌入式播放(能播放YouTube视频),或者采用电影播放器(MPMoviePlayerController)进行播放。 [1] 电影播放器 MPMoviePlayerController *player = [MPMoviePlayerController alloc]initWithContentURL: url]; // 设置播放器的大小,并将其加入视图中 [player.view setFrame: rectFrame]; [self.view addSubView: player.view]; 播放器的背景视图backgroundView。 全屏[player setFullscreen: YES animated: YES]; 播放另一个影片[player setContentURL: newURL]; [player requestThumbnailImagesAtTimes:arrayTimes timeOption:MPMovieTimeOptionNearestKeyFrame]; // 表示播放器不会在你所指定的时间去截取预览,而是在绝对时间的附近几帧中寻找效果最好的帧做为预览。 scalingMode规定了影片的缩放模式。 initialPlaybackTime用来控制视频开始播放的时间,单位是秒。 如果视频源在网络上,那么需要正确设置服务器端的mimeType。十二.运行环-runloop 运行环作用于一个iOS应用的整个生命周期。它负责监视各种输入事件,并且在合适的时候对这些输入进行分配。应用的每一个线程都有且仅有一个运行环。你自己不需要创建也不需要销毁运行环,但是可以通过currentRunLoop方法来获取当前的运行环。十三.定时器 由于运行环机制,定时器的精度不高,只能用于一般性延时。 例子:拼图游戏,DeskViewController.m。 NSObject类的定时方法。 performSelector: withObject: afterDelay: 运行方法,参数,时间(秒)。 performSelectorOnMainThread: withObject: waitUntilDone: 在主线程中,运行参数selector所指定的方法,如果waitUntilDone参数为YES,那么当前线程会被阻拦,直到selector运行完。 performSelector: onThread: withObject: waitUntilDone:同上,但不一定在主线程中运行。 performSelectorInBackground: withObject: 开启一个新线程,用于运行selector方法,selector方法应负责线程的初始化。 cancelPreviousPerformRequestsWithTarget:取消与一个目标相关的所有计划好的动作。 cancelPreviousPerformRequestsWithTraget: selector: object只取消特定的计划动作。十四.随机数 0~1之间随机数 CG_INLINE float genRandomNum() { return (float)arc4random/ARCRANDOM_MAX; } 十五.加速度传感器 获得加速度传感器读数: UIAccelerometer *accelerometer = [UIAccelerometer shareAccelerometer]; // 单例 accelerometer.delegate = self; accelerometer.updateInterval = 1.0f / 10.0f; // 传感器更新频率,普通游戏10~30HZ,虚拟现实类游戏,30~60HZ accelerometer.x, accelerometer.y, accelerometer.z // 传感器读数 若不想再接受传感器读数,可将代理设置为nil [UIAccelerometer shareAccelerometer].delegate = nil; #define alpha 0.05 // 获得重力引起的加速度读数: - (void)accelerometer: (UIAccelerometer *)accelerometer didAccelerate: (UIAcceleration *)acceleration { // 简单低通滤波器 accelX = (acceleration.x * alpha) + (accelX) * (1.0 - alpha); accelY = (acceleration.y * alpha) + (accelY) * (1.0 - alpha); accelZ = (acceleration.z * alpha) + (accelZ) * (1.0 - alpha); } // 获得动作引起的加速度读数: - (void)accelerometer: (UIAccelerometer *)accelerometer didAccelerate: (UIAcceleration *)acceleration { // 减去低通滤波输出,得到高通滤波输出 accelX = acceleration.x - ((acceleration.x * alpha) + (accelX) * (1.0 - alpha)); accelY = acceleration.y - ((acceleration.y * alpha) + (accelY) * (1.0 - alpha)); accelZ = acceleration.z - ((acceleration.z * alpha) + (accelZ) * (1.0 - alpha)); } 十六.地图与连接服务器[1] 添加框架MapKit.framework。使用MKMapView来呈现地图。注意应当直接使用此类,而不是继承之。如果希望在MKMapView类之上添加功能,可以使用MKMapViewDelegate协议。 初始化: MKMapView *mapView = [MKMapView alloc] initWithFrame: rect]; 初始化之后并不直接显示,还需要指定显示的地图区域: CLLocationCoordinate2D coordinate; coordinate.latitude = latitudeValue; // 纬度 coordinate.longtitude = longtitudeValue; // 精度 mapView.region = MKCoordinateRegionMakeWithDistance(coordinate, width, height); // 指定显示区域,width和height单位都是米 之后可以通过addSubview添加地图。 属性:showsUserLocation-为YES,系统会持续跟踪用户的位置 userLocationVisible-为YES,将显示用户所在位置 显示地图之后,常常希望在地图上添加标注,这需要创建一个类,并实现MKAnnotation协议,这个类叫做标注对象。标注对象往往实现 setCoordinate:方法来设置其坐标。在地图视图上,可以设置标注对象的坐标,然后添加进去,这样地图上就会出现一个标注。代理方法title 和subtitle能够在标注上显示标题和副标题。 // 初始化 mapView = [MKMapView alloc] initWithFrame: CGRectMake(100, 100, 550, 700)]; mapView.showsUserLocation = TRUE; mapView.mapType = MKMapTypeStandard; mapView.delegate = self; // 设置坐标 CLLocationCoordinate2D coordinate; coordinate.latitude = 37.31; coordinate.longtitude = -122.03; mapView.region = MKCoordinateRegionMakeWithDistance(coordinate, 4000, 6000); // 4000米宽,6000米高的区域 [self.view insertSubview: mapView atIndex: 0]; 十七.通过storyboard来初始化一个controller CBigDesignImageViewController *imageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"BigImageController"]; BigImageController是要在storyboard中设置的Identifier属性。十八.给UIView子类设置阴影,包括各种控件 1 导入QuartzCore framework 2 #import <QuartzCore/QuartzCore.h> 3 编码: [imgView layer] setShadowOffset:CGSizeMake(5, 5)]; // 阴影的范围 [imgView layer] setShadowRadius:2]; // 阴影扩散的范围控制 [imgView layer] setShadowOpacity:1]; // 阴影透明度 [imgView layer] setShadowColor:[UIColor brownColor].CGColor]; // 阴影的颜色 十九.设置UIScrollView滚动速度 // 自动滚动太快,效果不好,这里把动画设置慢点,注意下面要直接赋值contentOffset,不要用带animated参数的函数,否则动画会出问题,因为两处都是动画效果。 [UIScrollView animateWithDuration:1.0f delay:0 options:UIViewAnimationCurveLinear animations:^{ scrollView.contentOffset = CGPointMake(0, 0); } completion:^(BOOL finished){} ]; // 如果在减速滚动过程中,按了刷新按钮,执行上面的动画,会出现重置的位置,y不是0的情况,这里再调用一次,滚动到0。 [scrollView setContentOffset:CGPointMake(0, 0) animated:YES]; 二十.EXC_BAD_ACCESS Here’s the advice I generally give to developers when you hit an EXC_BAD_ACCESS error: -Set the NSZombieEnabled argument in your executable options, which sometimes helps narrow down the cause -Run with Apple Instruments such as Leaks to look for memory issues -Set a breakpoint in your code and step through until you narrow down where it’s crashing Tried and true “comment out code till it works” then backtrack from there :] Xcode4 下设置 NSZombieEnabled 的方法: 你可以点击 Xcode4 菜单 Product -> Edit Scheme -> Arguments, 然后将点击”加号”, 将 NSZombieEnabled 参数加到 Environment Variables 窗口中, 后面的数值写上 ”YES”. 或者在 Xcode4 菜单 Product -> Edit Scheme -> Diagnostics 设置窗口中直接勾上 Enable Zombie Objects 即可,Xcode 可用 cmd+shift+< 进到这个窗口。 Xcode4 已经考虑到了现在的要求,所以提供了更便捷的设置的方式,你也可以在这个窗口中设置其他一些参数,你肯定能由此获得更多的帮助信息。 好了,看完这篇iOS学习笔记整理,不知道对你是不是有所启发。 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3465596.html,如需转载请自行联系原作者
from:http://www.jakee.cn/index.php/archives/501.html 常用命令整理如下: 查看主板的序列号: dmidecode | grep -i ’serial number’ 用硬件检测程序kuduz探测新硬件:service kudzu start ( or restart) 查看CPU信息:cat /proc/cpuinfo [dmesg | grep -i 'cpu'][dmidecode -t processor] 查看内存信息:cat /proc/meminfo [free -m][vmstat] 查看板卡信息:cat /proc/pci 查看显卡/声卡信息:lspci |grep -i ‘VGA’[dmesg | grep -i 'VGA'] 查看网卡信息:dmesg | grep -i ‘eth’[cat /etc/sysconfig/hwconf | grep -i eth][lspci | grep -i 'eth'] <!--more--> 查看PCI信息:lspci (相比cat /proc/pci更直观) 查看USB设备:cat /proc/bus/usb/devices 查看键盘和鼠标:cat /proc/bus/input/devices 查看系统硬盘信息和使用情况:fdisk & disk – l & df 查看各设备的中断请求(IRQ):cat /proc/interrupts 查看系统体系结构:uname -a 查看及启动系统的32位或64位内核模式:isalist –v [isainfo –v][isainfo –b] dmidecode查看硬件信息,包括bios、cpu、内存等信息 测定当前的显示器刷新频率:/usr/sbin/ffbconfig –rev \? 查看系统配置:/usr/platform/sun4u/sbin/prtdiag –v 查看当前系统中已经应用的补丁:showrev –p 显示当前的运行级别:who –rH 查看当前的bind版本信息:nslookup –class=chaos –q=txt version.bind dmesg | more 查看硬件信息 lspci 显示外设信息, 如usb,网卡等信息 lsnod 查看已加载的驱动 lshw psrinfo -v 查看当前处理器的类型和速度(主频) prtconf -v 打印当前的OBP版本号 iostat –E 查看硬盘物理信息(vendor, RPM, Capacity) prtvtoc /dev/rdsk/c0t0d0s 查看磁盘的几何参数和分区信息 df –F ufs –o i 显示已经使用和未使用的i-node数目 isalist –v 对于“/proc”中文件可使用文件查看命令浏览其内容,文件中包含系统特定信息: Cpuinfo 主机CPU信息 Dma 主机DMA通道信息 Filesystems 文件系统信息 Interrupts 主机中断信息 Ioprots 主机I/O端口号信息 Meninfo 主机内存信息 Version Linux内存版本信息 备注: proc – process information pseudo-filesystem 进程信息伪装文件系统 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3244099.html,如需转载请自行联系原作者
Objective-C中的hasPrefix hasPrefix:方法的功能是判断创建的字符串内容是否以某个字符开始,其语法形式如下: -(BOOL)hasPrefix:(NSString*)aString; 其中,(NSString *)aString;用来指定字符串。该方法的返回值为BOOL,当BOOL为YES或者为1时,则字符串是以某个字符开始;当BOOL为NO或者为0时,则字符串不是以某个字符开始。 【示例】以下程序通过使用hasPrefix:方法来判断使用stringWithCString:方法创建的字符串是否以字母B开始,如果是以字母B开始,输出开头为字母B;如果不是,输出开头不为字母B。程序代码如下: #import <Foundation/Foundation.h> int main(int argc,constchar* argv[]) { @autoreleasepool{ NSString*a=[NSString stringWithCString:"ABCDEF" encoding:NSASCIIStringEncoding]; if([a hasPrefix:@"B"]==YES){//判断字符串是否以B字符开始 NSLog(@"开头为字母B"); }else{ NSLog(@"开头不为字母B"); } } return0; } 运行结果如下: 2013-03-1918:10:02.0874-13[751:303]开头不为字母B 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3449301.html,如需转载请自行联系原作者
一、文件和目录权限概述 在linux中的每一个文件或目录都包含有访问权限,这些访问权限决定了谁能访问和如何访问这些文件和目录。 通 过设定权限可以从以下三种访问方式限制访问权限:只允许用户自己访问;允许一个预先指定的用户组中的用户访问;允许系统中的任何用户访问。同时,用户能够 控制一个给定的文件或目录的访问程度。一个文件活目录可能有读、写及执行权限。当创建一个文件时,系统会自动地赋予文件所有者读和写的权限,这样可以允许 所有者能够显示文件内容和修改文件。文件所有者可以将这些权限改变为任何他想指定的权限。一个文件也许只有读权限,禁止任何修改。文件也可能只有执行权 限,允许它想一个程序一样执行。 三种不同的用户类型能够访问一个目录或者文件:所有着、用户组或其他用户。所有者就是创建文件的用户,用 户是所有用户所创建的文件的所有者,用户可以允许所在的用户组能访问用户的文件。通常,用户都组合成用户组,例如,某一类或某一项目中的所有用户都能够被 系统管理员归为一个用户组,一个用户能够授予所在用户组的其他成员的文件访问权限。最后,用户也将自己的文件向系统内的所有用户开放,在这种情况下,系统 内的所有用户都能够访问用户的目录或文件。在这种意义上,系统内的其他所有用户就是other用户类。 每一个用户都有它自身的读、写和执 行权限。第一套权限控制访问自己的文件权限,即所有者权限。第二套权限控制用户组访问其中一个用户的文件的权限。第三套权限控制其他所有用户访问一个用户 的文件的权限,这三套权限赋予用户不同类型(即所有者、用户组和其他用户)的读、写及执行权限就构成了一个有9种类型的权限组。 我们可以用-l参数的ls命令显示文件的详细信息,其中包括权限。如下所示: yekai@kebao:/media/sda5/软件压缩/Linux$ ls -lh 总用量 191M -rwxrwx--- 1 root plugdev 18M 2007-02-28 18:05 ActionCube_v0.92.tar.bz2 -rwxrwx--- 1 root plugdev 60M 2007-04-30 22:52 nexuiz-223.zip -rwxrwx--- 1 root plugdev 7.4M 2007-04-25 02:16 stardict-oxford-gb-2.4.2.tar.bz2 -rwxrwx--- 1 root plugdev 102M 2007-05-01 18:22 tremulous-1.1.0-installer.x86.run -rwxrwx--- 1 root plugdev 4.9M 2007-04-30 14:32 wqy-bitmapfont-0.8.1-7_all.deb.bin 当执行ls -l 或 ls -al 命令后显示的结果中,最前面的第2~10个字符是用来表示权限。第一个字符一般用来区分文件和目录: d:表示是一个目录,事实上在ext2fs中,目录是一个特殊的文件。 -:表示这是一个普通的文件。 l: 表示这是一个符号链接文件,实际上它指向另一个文件。 b、c:分别表示区块设备和其他的外围设备,是特殊类型的文件。 s、p:这些文件关系到系统的数据结构和管道,通常很少见到。 下面详细介绍一下权限的种类和设置权限的方法。 二、一般权限 第2~10个字符当中的每3个为一组,左边三个字符表示所有者权限,中间3个字符表示与所有者同一组的用户的权限,右边3个字符是其他用户的权限。这三个一组共9个字符,代表的意义如下: r(Read,读取):对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目录的权限。 w(Write,写入):对文件而言,具有新增、修改文件内容的权限;对目录来说,具有删除、移动目录内文件的权限。 x(eXecute,执行):对文件而言,具有执行文件的权限;对目录了来说该用户具有进入目录的权限。 -:表示不具有该项权限。 下面举例说明: -rwx------: 文件所有者对文件具有读取、写入和执行的权限。 -rwxr―r--: 文件所有者具有读、写与执行的权限,其他用户则具有读取的权限。 -rw-rw-r-x: 文件所有者与同组用户对文件具有读写的权限,而其他用户仅具有读取和执行的权限。 drwx--x--x: 目录所有者具有读写与进入目录的权限,其他用户近能进入该目录,却无法读取任何数据。 Drwx------: 除了目录所有者具有完整的权限之外,其他用户对该目录完全没有任何权限。 每个用户都拥有自己的专属目录,通常集中放置在/home目录下,这些专属目录的默认权限为rwx------: 表示目录所有者本身具有所有权限,其他用户无法进入该目录。执行mkdir命令所创建的目录,其默认权限为rwxr-xr-x,用户可以根据需要修改目录的权限。 此 外,默认的权限可用umask命令修改,用法非常简单,只需执行umask 777 命令,便代表屏蔽所有的权限,因而之后建立的文件或目录,其权限都变成000,依次类推。通常root帐号搭配umask命令的数值为022、027和 077,普通用户则是采用002,这样所产生的权限依次为755、750、700、775。有关权限的数字表示法,后面将会详细说明。 用户登录系统时,用户环境就会自动执行rmask命令来决定文件、目录的默认权限。 三、特殊权限 其实文件与目录设置不止这些,还有所谓的特殊权限。由于特殊权限会拥有一些“特权”,因而用户若无特殊需求,不应该启用这些权限,避免安全方面出现严重漏洞,造成黑客入侵,甚至摧毁系统!!! s或S(SUID,Set UID):可执行的文件搭配这个权限,便能得到特权,任意存取该文件的所有者能使用的全部系统资源。请注意具备SUID权限的文件,黑客经常利用这种权限,以SUID配上root帐号拥有者,无声无息地在系统中开扇后门,供日后进出使用。 s或S(SGID,Set GID):设置在文件上面,其效果与SUID相同,只不过将文件所有者换成用户组,该文件就可以任意存取整个用户组所能使用的系统资源。 T或T(Sticky):/tmp和 /var/tmp目录供所有用户暂时存取文件,亦即每位用户皆拥有完整的权限进入该目录,去浏览、删除和移动文件。 因为SUID、SGID、Sticky占用x的位置来表示,所以在表示上会有大小写之分。加入同时开启执行权限和SUID、SGID、Sticky,则权限表示字符是小写的: -rwsr-sr-t 1 root root 4096 6月 23 08:17 conf 如果关闭执行权限,则表示字符会变成大写: -rwSr-Sr-T 1 root root 4096 6月 23 08:17 conf 四、使用文件管理器来改变文件或目录的权限: 如果用户要改变一个文件目录的权限,右击要改变权限的文件或者目录,在弹出的快捷菜单中选择“属性”,系统将打开属性对话框 在“属性”对话框中,单击“权限”标签,就会打开“权限”选项卡。 在这里你可以修改文件或者目录的所有者、组群和其他用户的权限,而且可以设置特殊权限 对于特殊权限,最好不要设置,不然会带来很严重的安全问题。 当然,在这里你也可以改变文件和目录的所有者和所属组。 五、使用chmod和数字改变文件或目录的访问权限 文件和目录的权限表示,是用rwx这三个字符来代表所有者、用户组和其他用户的权限。有时候,字符似乎过于麻烦,因此还有另外一种方法是以数字来表示权限,而且仅需三个数字。 r: 对应数值4 w: 对应数值2 x:对应数值1 -:对应数值0 数字设定的关键是mode的取值,一开始许多初学者会被搞糊涂,其实很简单,我们将rwx看成二进制数,如果有则有1表示,没有则有0表示,那么rwx r-x r- -则可以表示成为: 111 101 100 再将其每三位转换成为一个十进制数,就是754。 例如,我们想让a.txt这个文件的权限为: 自己 同组用户 其他用户 可读 是 是 是 可写 是 是 可执行 那么,我们先根据上表得到权限串为:rw-rw-r--,那么转换成二进制数就是110 110 100,再每三位转换成为一个十进制数,就得到664,因此我 们执行命令: [root@localhost ~]# chmod 664 a.txt 按照上面的规则,rwx合起来就是4+2+1=7,一个rwxrwxrwx权限全开放的文件,数值表示为777;而完全不开放权限的文件“---------”其数字表示为000。下面举几个例子: -rwx------:等于数字表示700。 -rwxr―r--:等于数字表示744。 -rw-rw-r-x:等于数字表示665。 drwx―x―x:等于数字表示711。 drwx------:等于数字表示700。 在文本模式下,可执行chmod命令去改变文件和目录的权限。我们先执行ls -l 看看目录内的情况: [root@localhost ~]# ls -l 总用量 368 -rw-r--r-- 1 root root 12172 8月 15 23:18 conkyrc.sample drwxr-xr-x 2 root root 48 9月 4 16:32 Desktop -r--r--r-- 1 root root 331844 10月 22 21:08 libfreetype.so.6 drwxr-xr-x 2 root root 48 8月 12 22:25 MyMusic -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth0 -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth1 -rwxr-xr-x 1 root root 512 11月 5 08:08 net.lo drwxr-xr-x 2 root root 48 9月 6 13:06 vmware 可以看到当然文件conkyrc.sample文件的权限是644,然后把这个文件的权限改成777。执行下面命令 [root@localhost ~]# chmod 777 conkyrc.sample 然后ls -l看一下执行后的结果: [root@localhost ~]# ls -l 总用量 368 -rwxrwxrwx 1 root root 12172 8月 15 23:18 conkyrc.sample drwxr-xr-x 2 root root 48 9月 4 16:32 Desktop -r--r--r-- 1 root root 331844 10月 22 21:08 libfreetype.so.6 drwxr-xr-x 2 root root 48 8月 12 22:25 MyMusic -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth0 -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth1 -rwxr-xr-x 1 root root 512 11月 5 08:08 net.lo drwxr-xr-x 2 root root 48 9月 6 13:06 vmware 可以看到conkyrc.sample文件的权限已经修改为rwxrwxrwx 如果要加上特殊权限,就必须使用4位数字才能表示。特殊权限的对应数值为: s或 S (SUID):对应数值4。 s或 S (SGID):对应数值2。 t或 T :对应数值1。 用同样的方法修改文件权限就可以了 例如: [root@localhost ~]# chmod 7600 conkyrc.sample [root@localhost ~]# ls -l 总用量 368 -rwS--S--T 1 root root 12172 8月 15 23:18 conkyrc.sample drwxr-xr-x 2 root root 48 9月 4 16:32 Desktop -r--r--r-- 1 root root 331844 10月 22 21:08 libfreetype.so.6 drwxr-xr-x 2 root root 48 8月 12 22:25 MyMusic -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth0 -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth1 -rwxr-xr-x 1 root root 512 11月 5 08:08 net.lo drwxr-xr-x 2 root root 48 9月 6 13:06 vmware 加入想一次修改某个目录下所有文件的权限,包括子目录中的文件权限也要修改,要使用参数-R表示启动递归处理。 例如: [root@localhost ~]# chmod 777 /home/user 注:仅把/home/user目录的权限设置为rwxrwxrwx [root@localhost ~]# chmod -R 777 /home/user 注:表示将整个/home/user目录与其中的文件和子目录的权限都设置为rwxrwxrwx 六、使用命令chown改变目录或文件的所有权 文件与目录不仅可以改变权限,其所有权及所属用户组也能修改,和设置权限类似,用户可以通过图形界面来设置,或执行chown命令来修改。 我们先执行ls -l看看目录情况: [root@localhost ~]# ls -l 总用量 368 -rwxrwxrwx 1 root root 12172 8月 15 23:18 conkyrc.sample drwxr-xr-x 2 root root 48 9月 4 16:32 Desktop -r--r--r-- 1 root root 331844 10月 22 21:08 libfreetype.so.6 drwxr-xr-x 2 root root 48 8月 12 22:25 MyMusic -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth0 -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth1 -rwxr-xr-x 1 root root 512 11月 5 08:08 net.lo drwxr-xr-x 2 root root 48 9月 6 13:06 vmware 可以看到conkyrc.sample文件的所属用户组为root,所有者为root。 执行下面命令,把conkyrc.sample文件的所有权转移到用户user: [root@localhost ~]# chown user conkyrc.sample [root@localhost ~]# ls -l 总用量 368 -rwxrwxrwx 1 user root 12172 8月 15 23:18 conkyrc.sample drwxr-xr-x 2 root root 48 9月 4 16:32 Desktop -r--r--r-- 1 root root 331844 10月 22 21:08 libfreetype.so.6 drwxr-xr-x 2 root root 48 8月 12 22:25 MyMusic -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth0 -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth1 -rwxr-xr-x 1 root root 512 11月 5 08:08 net.lo drwxr-xr-x 2 root root 48 9月 6 13:06 vmware 要改变所属组,可使用下面命令: [root@localhost ~]# chown :users conkyrc.sample [root@localhost ~]# ls -l 总用量 368 -rwxrwxrwx 1 user users 12172 8月 15 23:18 conkyrc.sample drwxr-xr-x 2 root root 48 9月 4 16:32 Desktop -r--r--r-- 1 root root 331844 10月 22 21:08 libfreetype.so.6 drwxr-xr-x 2 root root 48 8月 12 22:25 MyMusic -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth0 -rwxr-xr-x 1 root root 9776 11月 5 08:08 net.eth1 -rwxr-xr-x 1 root root 512 11月 5 08:08 net.lo drwxr-xr-x 2 root root 48 9月 6 13:06 vmware 要修改目录的权限,使用-R参数就可以了,方法和前面一样。 来源:http://hi.baidu.com/skyforum/item/9946ef57b371789608be1747 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3170526.html,如需转载请自行联系原作者
话说,有这样一道据说是月薪2W的笔试题: #include "stdio.h" void print() { * } void main() { } 要求在*部分写代码使整个程序运行后输出“hello world”,有些人说,这还不简单啊,于是写出这样的代码: 01.#include "stdio.h" 02.void print() 03.{ 04. printf("hello world"); 05.} 06.void main() 07.{ 08. print(); 09.} 这样写的确是没问题,但是违背了题目的要求,因为题目不允许修改main函数,这下仿佛我们就没辙了,因为我们学习C/C++语言的时候,明确说明main函数是程序的主函数,也是程序的入口函数,可是现在主函数为空,那怎么会执行子函数呢? 其实这个笔试题考察的不是我们对基本知识的理解,而是要学会发现问题解决问题的能力,有时候,当一条路走不通的时候,我们就要换一条路,通过查找资料,我们发现其实C++是可以修改入口函数的。 这里需要一个C++预编译标识符 #pragma comment() 来帮助我们搞定这个问题。他的使用类型是:pragma comment( comment-type ,["commentstring"] )。 comment-type是一个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之一。 commentstring是一个提供为comment-type提供附加信息的字符串。 这里我们需要使用linker来修改链接设置: #pragma comment(linker, "/entry:print") 看到了么?通过/entry参数来设置程序链接时候的主函数为print,这样,就相当于print函数是整个程序的主函数,他替换了main函数的作用,相反的,main函数则成为了一个子函数 完整的代码和运行结果如图所示: 至于#pragma comment(lib, "msvcrt.lib")是因为使用了puts函数,如果使用printf的话可以不要这一句 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/04/25/3042531.html,如需转载请自行联系原作者
以后慢慢启用个人博客:http://www.yuanrengu.com 提起github相信大家都不会陌生,在这里就不再赘述了。作为开源代码库以及版本控制系统,使用好了确实会非常受益,再说的势利点,你找工作时给面试官说你经常维护自己的技术博客和github,相信你给他的印象会好很多。 windows底下如何使用github,很多好心人都已经给了非常详细的解决方案,你只需问下度娘,她会帮你解决,这里对于windows底下的使用我也就不再赘述了。这里主要讲讲如何在mac底下使用github,我刚开始使用时,还是费了一点功夫的,因为网上的资料比较杂,有些不是太准确。故将自己的安装过程比较详细的分享下,方便有需要的人,攒点人品。 工欲善其事必先利器,首先你得完成如下两个工作: 下载安装git客户端 http://code.google.com/p/git-osx-installer/downloads/list?can=3 注册github账号 https://github.com/ -->Pricing and Signup -->Create a free account 创建ssh: 接下来打开终端(不知道终端在哪儿的,就直接在spotlight里搜terminal): $cd ~/.ssh //检查是否已经存在ssh 如果存在,先将已有的ssh备份,或者将新建的ssh生成到另外的目录下 如果不存在,通过默认的参数直接生成ssh: $ssh-keygen -t rsa -C xxxxx@gmail.com(注册github时的email) Generating public/private rsa key pair. Enter file in which to save the key (/Users/twer/.ssh/id_rsa): Created directory '/Users/twer/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /Users/twer/.ssh/id_rsa. Your public key has been saved in /Users/twer/.ssh/id_rsa.pub. The key fingerprint is: 18:16:11:c9:01:6c:48:09:7f:27:c6:43:0d:7f:3f:84 xxxxx@gmail.com The key's randomart image is: +--[ RSA 2048]----+ |.o.++=== | |.ooo.+. . | | ..* = E . | | o = + o | | . S o | | . | | | | | | | +-----------------+ 如果要修改ssh生成目录,在粗体位置处输入要生成的路径,选择默认的话,会生成在 ~/.ssh下 在github中添加ssh(如图示): 登陆github,选择Account Settings-->SSH Keys 添加ssh Title:xxxxx@gmail.com Key:打开你生成的id_rsa.pub文件,将其中内容拷贝至此。 打开终端,先测试一下你的帐号跟github连上没有:ssh -T git@github.com 如果出现如下提示,表示你连已经连上了.(因为有了第一步,所以不用自己做过多的连接github的操作了,另外,下一次要连接github的时候记得打开第一步的工具). Hi MiracleHe! You've successfully authenticated, but GitHub does not provide shell access. 接下来就可以上传你的代码了,在github下建自己的Repository。Create a New Repository如下: Repository name:通常就写自己自己要建的工程名。 Description:就是你对工程的描述了。 选择Public。 点击 “Create repository”,出现如下图: 按照上面的步骤来就行了(注意记得在终端中输入时把目录切换到你要上传的工程目录下)。简单分析下上面的步骤: touch README.md //新建一个记录提交操作的文档 git init //初始化本地仓库 git add README.md //添加 git commit -m "first commit"//提交到要地仓库,并写一些注释 git remote add origin git@github.com:youname/Test.git //连接远程仓库并建了一个名叫:origin的别名 git push -u origin master //将本地仓库的东西提交到地址是origin的地址,master分支下 需要注意的问题,进行如下操作时: Key:打开你生成的id_rsa.pub文件,将其中内容拷贝至此 这里的id_rsa.pub文件是在.ssh目录下,可能有小伙伴会发现自己的mac下没看见.ssh目录,难道是我忽悠大家啦?当然不会啦,这么败人品的事我怎么可能会做。没看见.ssh目录,是因为mac把这个目录给隐藏了,如果你不信,你可以进行如下操作把隐藏文件给显示出来。 显示Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles YES 隐藏Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles NO 输完单击Enter键,退出终端,重新启动Finder就可以了 其实虽然你可能看不到.ssh目录,但你还是可以通过终端命令来查看到.ssh目录的,操作如下: 通过cat id_rsa.pub查看里面是一大串云里雾里的东西,不需要看懂,复制到“key”里就行了。 相信我已经讲的还比较清楚了,有不清楚的小伙伴可以留言。 疑难问题分析和解决: 如果输入$ git remote add origin git@github.com:djqiang(github帐号名)/gitdemo(项目名).git 提示出错信息:fatal: remote origin already exists. 解决办法如下: 1、先输入$ git remote rm origin 2、再输入$ git remote add origin git@github.com:djqiang/gitdemo.git 就不会报错了! 3、如果输入$ git remote rm origin 还是报错的话,error: Could not remove config section 'remote.origin'. 我们需要修改gitconfig文件的内容 4、找到你的github的安装路径,我的是C:\Users\ASUS\AppData\Local\GitHub\PortableGit_ca477551eeb4aea0e4ae9fcd3358bd96720bb5c8\etc 5、找到一个名为gitconfig的文件,打开它把里面的[remote "origin"]那一行删掉就好了! 如果输入$ ssh -T git@github.com 出现错误提示:Permission denied (publickey).因为新生成的key不能加入ssh就会导致连接不上github。 解决办法如下: 1、先输入$ ssh-agent,再输入$ ssh-add ~/.ssh/id_key,这样就可以了。 2、如果还是不行的话,输入ssh-add ~/.ssh/id_key 命令后出现报错Could not open a connection to your authentication agent.解决方法是key用Git Gui的ssh工具生成,这样生成的时候key就直接保存在ssh中了,不需要再ssh-add命令加入了,其它的user,token等配置都用命令行来做。 3、最好检查一下在你复制id_rsa.pub文件的内容时有没有产生多余的空格或空行,有些编辑器会帮你添加这些的。 如果输入$ git push origin master 提示出错信息:error:failed to push som refs to ....... 解决办法如下: 1、先输入$ git pull origin master //先把远程服务器github上面的文件拉下来 2、再输入$ git push origin master 3、如果出现报错 fatal: Couldn't find remote ref master或者fatal: 'origin' does not appear to be a git repository以及fatal: Could not read from remote repository. 4、则需要重新输入$ git remote add origingit@github.com:djqiang/gitdemo.git 使用git在本地创建一个项目的过程 $ makdir ~/hello-world //创建一个项目hello-world $ cd ~/hello-world //打开这个项目 $ git init //初始化 $ touch README $ git add README //更新README文件 $ git commit -m 'first commit' //提交更新,并注释信息“first commit” $ git remote add origin git@github.com:defnngj/hello-world.git //连接远程github项目 $ git push -u origin master //将本地项目更新到github项目上去 //删除文件夹下的所有 .svn 文件 find . -name ".svn" | xargs rm -Rf //删除文件夹下的所有 .git 文件 find . -name ".git" | xargs rm -Rf 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3462191.html,如需转载请自行联系原作者
在终端下输入:vimtutor 系统自带的教程,虽然是英文版的,但看起来不会太吃力。 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/05/08/3066901.html,如需转载请自行联系原作者
来源:http://melin.iteye.com/blog/838258 三种Singleton的实现方式,一种是用大家熟悉的DCL,另外两种使用cas特性来实现。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class LazySingleton { private static volatile LazySingleton instance; public static LazySingleton getInstantce() { if (instance == null) { synchronized (LazySingleton.class) { if (instance == null) { instance = new LazySingleton(); } } } return instance; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /** * 利用putIfAbsent线程安全操作,实现单例模式 * * @author Administrator * */ public class ConcurrentSingleton { private static final ConcurrentMap<String, ConcurrentSingleton> map = new ConcurrentHashMap<String, ConcurrentSingleton>(); private static volatile ConcurrentSingleton instance; public static ConcurrentSingleton getInstance() { if (instance == null) { instance = map.putIfAbsent("INSTANCE", new ConcurrentSingleton()); } return instance; } } 本文转自夏雪冬日博客园博客,原文链接:XXXXXX,如需转载请自行联系原作者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class AtomicBooleanSingleton { private static AtomicBoolean initialized = new AtomicBoolean(false); private static volatile AtomicBooleanSingleton instance; public static AtomicBooleanSingleton getInstantce() { checkInitialized(); return instance; } private static void checkInitialized() { if(instance == null && initialized.compareAndSet(false, true)) { instance = new AtomicBooleanSingleton(); } } } 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/6104677.html,如需转载请自行联系原作者
来源:http://blog.csdn.net/ferlansue/article/details/7256964 一、Contiki简介 Contiki是一个开源的、高度可移植的多任务操作系统,适用于联网嵌入式系统和无线传感器网络,由瑞典计算机科学学院(Swedish Institute of Computer Science)的Adam Dunkels和他的团队开发,已经应用在许多项目中。 Contiki支持IPv4/IPv6通信,提供了uIPv6协议栈、IPv4协议栈(uIP),支持TCP/UDP,还提供了线程、定时器、文件 系统等功能。Contiki是采用 C 语言开发的非常小型的嵌入式操作系统,针对小内存微控制器设计,典型的Contiki配置只需要2KB的RAM和40KB的ROM。 Contiki具有以下特点: 低功率无线电通信 Contiki同时提供完整的IP网络和低功率无线电通信机制。对于无线传感器网络内部通信,Contiki使用低功率无线电网络栈Rime。Rime实现了许多传感器网络协议,从可靠数据采集、最大努力网络洪泛到多跳批量数据传输、数据传播。 网络交互 可以通过多种方式完成与使用Contiki的传感器网络的交互,如Web浏览器,基于文本的命令行接口,或者存储和显示传感器数据的专用软件等。基 于文本的命令行接口是受到Unix命令行Shell的启发,并且为传感器网络的交互与感知提供了一些特殊的命令。 能量效率 为了延长传感器网络的生命周期,控制和减少传感器节点的功耗很重要。Contiki提供了一种基于软件的能量分析机制,记录每个传感器节点的能量消耗。 由于基于软件,这种机制不需要额外的硬件就能完成网络级别的能量分析。Contiki的能量分析机制既可用于评价传感器网络协议,也可用于估算传感器网络的生命周期。 节点存储:Coffee File System Contiki提供的Coffee File System(CFS)是基于Flash的文件系统,可以在节点上存储数据。 编程模型 Contiki是采用C语言开发,包含一个事件驱动内核。应用程序可以在运行时被动态加载和卸载。在事件驱动内核之上,Contiki提供一种名为 protothread的轻量级线程模型来实现线性的、类线程的编程风格。Contiki中的进程正是使用这种protothread。此 外,Contiki还支持进程中的多线程、进程间的消息通信。Contiki提供三种内存管理方式:常规的malloc、内存块分配和托管内存分配器。 二:Contiki源代码结构 Contiki是一个高度可移植的操作系统,它的设计就是为了获得良好的可移植性,因此源代码的组织很有特点。本文为大家简单介绍Contiki的源代码组织结构以及各部分代码的作用。 Contiki源文件目录可以在Contiki Studio安装目录中的workspace目录下找到。打开Contiki源文件目录,可以看到主要有apps、core、cpu、doc、 examples、platform、tools等目录。下面将分别对各个目录进行介绍。 core core目录下是Contiki的核心源代码,包括网络(net)、文件系统(cfs)、外部设备(dev)、链接库(lib)等等,并且包含了时钟、I/O、ELF装载器、网络驱动等的抽象。 cpu cpu目录下是Contiki目前支持的微处理器,例如arm、avr、msp430等等。如果需要支持新的微处理器,可以在这里添加相应的源代码。 platform platform目录下是Contiki支持的硬件平台,例如mx231cc、micaz、sky、win32等等。Contiki的平台移植主要在这个目录下完成。这一部分的代码与相应的硬件平台相关。 apps apps目录下是一些应用程序,例如ftp、shell、webserver等等,在项目程序开发过程中可以直接使用。使用这些应用程序的方式为, 在项目的Makefile中,定义APPS = [应用程序名称]。在以后的示例中会具体看到如何使用apps。 examples examples目录下是针对不同平台的示例程序。Smeshlink的示例程序也在其中。 doc doc目录是Contiki帮助文档目录,对Contiki应用程序开发很有参考价值。使用前需要先用Doxygen进行编译。 tools tools目录下是开发过程中常用的一些工具,例如CFS相关的makefsdata、网络相关的tunslip、模拟器cooja和mspsim等等。 为了获得良好的可移植性,除了cpu和platform中的源代码与硬件平台相关以外,其他目录中的源代码都尽可能与硬件无关。编译时,根据指定的平台来链接对应的代码。 三:快速开发第一个Contiki应用程序 本文将介绍如何使用Contiki的进程模型方便快速地开发第一个应用程序。正如所有的程序设计学习一样,本文中的应用程序被命名为:Helloworld! 1、建立项目文件夹 Contiki中每一个应用程序都需要一个单独的文件夹,我们为Helloworld!建立一个名为helloworld的文件夹,并在其中创建 hello-world.c和Makefile文件。为了方便,建议将文件夹放在Contiki的examples目录下。 2、编写Helloworld!源代码 在hello-world.c文件中输入或粘贴如下代码: #include "contiki.h" #include <stdio.h> /* 声明一个名为hello_world_process进程 */ PROCESS(hello_world_process, "Hello world process"); /* 这个进程需要自动启动,即当节点启动时启动本进程 */ AUTOSTART_PROCESSES(&hello_world_process); /* hello_world_process进程的主体部分 */ PROCESS_THREAD(hello_world_process, ev, data) { /* 所有的进程开始执行前都必须要有这条语句 */ PROCESS_BEGIN(); printf("Hello world :)\n"); /* 所有的进程结束时都必须要有这条语句 */ PROCESS_END(); } 复制代码 是不是很简单,声明一个进程并声明为自动启动,定义进程主体,完成。 3、编写Makefile 在Makefile文件中输入或粘贴如下代码: /* 项目名称(主文件名称) */ CONTIKI_PROJECT = hello-world all: $(CONTIKI_PROJECT) /* Contiki源文件根目录,根据您的实际情况修改 */ CONTIKI = ../.. /* 包含Contiki的Makefile,以实现整个Contiki系统的编译 */ include $(CONTIKI)/Makefile.include 复制代码 4、编译项目 在控制台/Shell中进入helloworld项目目录,运行如下命令: make 复制代码 这时编译的目标平台是默认的native平台。如果需要指定目标平台,可以使用TARGET参数,如: make TARGET=native 复制代码 编译成功后,项目目录下就会生成hello-world.[目标平台]的目标文件,如hello-world.native。如果您使用的是Linux操作系统,可以运行如下命令查看Contiki程序运行结果: ./hello-world.native 复制代码 运行结果如下所示:(由于Contiki还在运行,需要按Ctrl+C退出程序) Starting Contiki Hello world :) 复制代码 至此,我们完成了第一个Contiki应用程序的开发,希望对大家快速上手Contiki有所帮助。 总结一下,Contiki程序开发是以进程的方式实现。创建一个Contiki进程包含两个步骤,声明和定义,由两个宏分别完成。 PROCESS(process_name, "process description")宏用于声明一个进程;PROCESS_THREAD(process_name, event, data)宏用于定义进程执行主体。 如果进程需要在系统启动时被自动执行,则可以使用AUTOSTART_PROCESSES(&process_name)宏。该宏可以指定 多个进程,如AUTOSTART_PROCESSES(&process_1, &process_2),表示process_1和process_2都会在系统启动时被启动。 进程执行主体代码中,必须以PROCESS_BEGIN()宏开始,以PROCESS_END()宏结束。这是由于Contiki特殊的进程模型导 致的。此外,在进程中不能使用switch语句,慎重使用局部变量,同样也是因为Contiki进程模型的原因。在以后的文章中会详细地说明。 四:使用Contiki Studio 良 好的开始是成功的一半,良好的开发工具是成功开发的一半。开发者当然可以在提示符下make、vi、运键如飞,但若有了开发工具相助,就更是如虎添翼天神 下凡。本文将介绍Contiki开发集成环境Contiki Studio的使用。Contiki Studio基于Eclipse,易用性强,因此熟悉Eclipse的开发者不会觉得陌生,不熟悉Eclipse的开发者也很快就能熟练操作。更多 Contiki Studio的介绍请看这里。Contiki Studio的下载与安装请参考Contiki Studio用户手册。 Contiki Studio运行后如下图所示。 默认布局下,左侧是工作区文件树,显示工程下所有的文件;右侧上部是代码开发区,编辑程序源代码;右侧下部是其他窗口,包括警告错误窗口、编译输出窗口等等。接下来看看如何使用Contiki Studio编译Contiki应用程序。 展开左侧目录区中的examples目录,找到01-hello-world项目,该项目中已经包含了helloworld示例程序,您也可以创建自己的项目(参见Contiki入门学习之三:快速开发第一个Contiki应用程序)。在项目目录上单击右键,在弹出菜单中选择“Make Targets”中的“Build...”,打开“Make Targets”窗口。 点击“Add…”,打开“Create Make Target”窗口,按下图配置后,点击“OK”。其中TARGET的值可以按照您需要编译的目标平台来修改。 添加之后的“Make Targets”窗口如下图所示。选中刚刚添加的Target,点击“Build”,开始编译。 可以看到Console窗口不断输出编译过程信息,编译需要一点时间,请耐心等候。 编译完成之后,可以看到项目目录下生成了hello-world.mx231cc文件(扩展名与您设定的目标平台相同)。 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/03/28/2986584.html,如需转载请自行联系原作者
第一部分(必做):计算机科学基础 1.(单选)软件设计中模块划分应该遵循的准则是: A.低内聚低耦合 B.高内聚低耦合 C.低内聚高耦合 D.高内聚高耦合 [cpp] view plaincopy 答:B 内 聚指模块内部各成分之间相关程度的度量 强度性低到高分成 偶然内聚 :关系松散没什么联系 逻辑内聚:几个逻辑上相关的功能被放在同一模块中,如一个模 块读取各种不同类型外设的输入,逻辑内聚的模块各成分在功能上并无关系。时间内聚:一个模块完成的功能必须在同一时间内执行,这些功能只是因为时间因素关 联在一起。通信内聚:如果一个模块的所有成分都操作同一数据集或生成同一数据集,则称为通信内聚。顺序内聚: 如果一个模块的各个成分和同一个功能密切相 关,而且一个成分的输出作为另一个成分的输入,则称为顺序内聚。功能内聚:模块的所有成分对于完成单一的功能都是必须的,则称为功能内聚。信息内聚:模块 完成多个功能,各个功能都在同一数据结构上操作,每一项功能有一个唯一的入口点。这个模块将根据不同的要求,确定该模块执行哪一个功能。 耦 合指模块之间的关联程度。耦合由高到低分成:内容耦合:当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另一个模块时,这样 的耦合被称为内容耦合。公共耦合:两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。外部耦合:一组模块都访问同一全局简单变量而不 是同一全局数据结构。控制耦合:一个模块通过接口向一个模块传递控制信号,接受信号的的模块根据信号值进行适当的动作。标记耦合:一个模块通过接口向另一 个模块传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合。数据耦合:模块之间通过参数传递数据。非直接耦合:两个模 块间没有直接关系,完全通过主模块的控制和调用实现。 2. (单选)最坏情况下时间复杂度不是n(n-1)/2的排序算法是: A.快速排序 B.冒泡排序 C.直接插入排序 D.堆排序 [cpp] view plaincopy 答:D 快排最差是每次partion得到的位置在数组的两端时出现如排序有序数组。 每次partion全部比较一次,每一趟比较后一个数位置确定,下次比较少一个数字少比较一次 (1+…N-1) 冒泡每一趟通过相邻数字间交换实现把最大或最小数排到数组两端 比较次数为(1+…N-1) 直接插入最差情况是在逆序时如从小到大排序时每个数都比前面的所有数小 比较次数(1+..N-1) 堆排序最好最差情况一样 都为nlogn 3. 哈希表中解决冲突的方法通常可以分为open addressing和chaining两类,请分别解释这两类冲突解决方法的大致实现原理 [cpp] view plaincopy 答:第一个使用冲突算法在哈希表中在此寻找合适位置, 分 为线性探测再散列,存储地址D发生冲突,则放到存储地址(D+1)%m;若又发生冲突则放到存储地址(D+2)%m二次探 测,ND = (D+di)%m; di取1*1,-1*1,2*2,-2*2,……,K*K,-K*K (K≤m/2)。拉链法个将所有关键字为同义词 的结点链接在同一个单链表中 4. 简单的链表结构拥有很好的插入删除节点性能,但随机定位(获取链表第n个节点)操作性能不佳,请你设计一种改进型的链表结构优化随机定位操作的性能,给出设计思路及其改进后随机定位操作的时间复杂度 [cpp] view plaincopy 使用 Node * List[MAX]按顺序存储链表节点地址,随机访问时间复杂度O(1);相对的删除增加节点时间变成O(n); 5. 什么是NP问题?列举典型的NP问题(至少两个)?对于一个给定的问题你通常如何判断它是否为NP问题? [cpp] view plaincopy NP 问题是可以在多项式时间内被确定机(通常意义的计算机)解决的问题.NP(Non-Deterministic Polynomial, 非确定多项式) 问题,是指可以在多项式时间内被非确定机(它可以猜,他总是能猜到最能满足你需要的那种选择,如果你让他解决n皇后问题,他只要猜n次就能完成----每 次都是那么幸运)解决的问题。经典问题有:旅行商问题 TSP Travelling Salesman Problem、子集和问题、Hamilton 回路、最大团问题 判断方法:可以将时间的时间复杂度与某个NP问题的时间复杂度作比较 6. 以下是一个tree的遍历算法, queue是FIFO队列,请参考下面的tree,选择正确的输出 1 / \ 2 3 / \ / \ 4 5 6 7 [cpp] view plaincopy queue.push(tree.root) while(true){ node=queue.pop(); output(node.value);//输出节点对应数字 if(null==node) break; for(child_node in node.children){ queue.push(child_node); } } A.1234567 B. 1245367 C. 1376254 D. 1327654 [cpp] view plaincopy 答:A 按层次遍历输出 第二部分(选作): C/C++程序设计 1.有三个类A B C定义如下,请确定sizeof(A) sizeof(B) sizeof(C)的大小顺序,并给出理由 [cpp] view plaincopy struct A{ A() {}8字节,有虚函数所以又虚指针 占4字节 加上8字节变量 ~A() {} int m1; int m2; }; struct B:public A{//8字节 char因为4字节对齐占4个字节,static不存储在类中 B() {} ~B() {} int m1; char m2; static char m3; }; struct C{ C() {} virtual~C() {}//四字节对齐变量一共占8字节,有虚函数加4字节虚指针一共12字节。 int m1; short m2; }; 答: [cpp] view plaincopy A:8字节变量 B:8字节 char因为4字节对齐占4个字节,static不存储在类中 C:四字节对齐变量一共占8字节,有虚函数加4字节虚指针一共12字节。 2.请用C++实现以下print函数,打印链表I中的所有元素,每个元素单独成一行voidprint(const std::list<int> &I) [cpp] view plaincopy void print(const std::list<int> &I){ for(const std::list<int>::const_itorator it = I.begin():it != I.end(): it++)//访问常量必须使用常迭代器。 cout<<*it<<endl; } 3. 假设某C工程包含a.c和b.c两个文件,在a.c中定义了一个全局变量foo,在b.c中想访问这一变量时该怎么做? [cpp] view plaincopy 答:使用extern 4. C++中的new操作符通常完成两个工作,分配内存及其调用相应的构造函数初始化请问: 1) 如何让new操作符不分配内存,只调用构造函数?2) 这样的用法有什么用? 答:参考 http://blog.csdn.net/aixiaolin/article/details/7367237 [cpp] view plaincopy 使用定位放置new #include <new> // 必须 #include 这个,才能使用 "placement new" #include "Fred.h" // class Fred 的声明 void someCode() { char memory[sizeof(Fred)]; // Line #1 void* place = memory; // Line #2 Fred* f = new(place) Fred(); // Line #3 (详见以下的“危险”) // The pointers f and place will be equal // ... } 作用为:对于需要反复创建并删除的对象,可以降低分配释放内存的性能消耗 5. 下面这段程序的输出是什么?为什么? [cpp] view plaincopy class A{ public: A(){p();} virtual void p(){print("A")} virtual ~A(){p();} }; class B{ public: B(){p();} void p(){print("B")} ~B(){p();} }; int main(int, char**){ A* a=new B(); delete a; } 答: [cpp] view plaincopy 输出:ABBA 原因:先构造父类 再构造子类 子类构造完成前virtual无效,析构虚函数会先析构子类 6. 什么是C++ Traits?并举例说明 [cpp] view plaincopy 答:特性萃取 template <class T> class Demol{ typedef T Type; } template <class T>//偏特化 class Demol<T *>{ typedef T Type; } 第三部分(选作): JAVA程序设计 [cpp] view plaincopy 1. (单选)以下Java程序运行的结构是: public class Tester{ public static void main(String[] args){ Integer var1=new Integer(1); Integer var2=var1; doSomething(var2); System.out.print(var1.intValue()); System.out.print(var1==var2); } public static void doSomething(Integer integer){ integer=new Integer(2); } } A. 1true B. 2true C. 1false D. 2false 2. (单选)往OuterClass类的代码段中插入内部类声明, 哪一个是正确的: public class OuterClass{ private float f=1.0f; //插入代码到这里 } A. class InnerClass{ public static float func(){return f;} } B. abstract class InnerClass{ public abstract float func(){} } C. static class InnerClass{ protected static float func(){return f;} } D. public class InnerClass{ static static float func(){return f;} } 3. Java中的interface有什么作用? 举例说明哪些情况适合用interface, 哪些情况下适合用抽象类. 4. Java多线程有哪几种实现方式? Java中的类如何保证线程安全? 请说明ThreadLocal的用法和适用场景 5. 线程安全的Map在JDK 1.5及其更高版本环境 有哪几种方法可以实现? 6. 1) 简述Java ClassLoader的模型, 说明其层次关系及其类加载的主要流程即可. 2) TypeA.class位于classpath下, /absolute_path/TypeA.class为其在文件系统中的绝对路径, 且类文件小于1k, MyClassLoader为一个自定义的类加载器, 下面的这段类加载程序是否正确, 如果有错请指出哪一行有错, 简述理由 import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class Tester{ public static void main(String[] args){ MyClassLoader cl1=new MyClassLoader(); try{ File f=new File("/absolute_path/TypeA.class"); byte[] b=new byte[1024]; InputStream is=new FileInputStream(f); int I=is.read(b); Class c=cl1.defineMyClass(null,b,0,1); TypeA a=(TypeA)c.newInstance(); }catch(Exception e){ e.printStacktrace(); } } } 第四部分(选作): Linux应用与开发 1. 写出完成以下功能的Linux命令: 1) 在当前目录及其子目录所有的.cpp文件中查找字符串"example",不区分大小写; 2) 使用sed命令,将文件xyz中的单词AAA全部替换为BBB; 3) 用一条命令创建aabb cc三个子目录 4) mount cdrom.iso至/dev/cdrom目录 5) 设置ulimit使得程序在Segment fault等严重错误时可以产生coredump; 2. 设umask为002,则新建立的文件的权限是什么? A. -rw-rwr-- B. rwxrwx-w- C. -------w- D. rwxrwxr-x 3. 用户HOME目录下的.bashrc和.bash_profile文件的功能有什么区别? 4. 写出完成以下功能的gdb命令(可以使用命令简写形式): 1) 使用gdb调试程序foo,使用coredump文件core.12023; 2) 查看线程信息 3) 查看调用堆栈 4) 在类ClassFoo的函数foo上设置一个断点 5) 设置一个断点,当表达式expr的值被改变时触发 5. 1) 例举Linux下多线程编程常用的pthread库提供的函数名并给出简要说明(至少给出5个) 2) pthread库提供哪两种线程同步机制,列出主要API 3) 使用pthread库的多线程程序编译时需要加什么连接参数? 第五部分(选作): Windows开发 1. DC(设备上下文)有哪几类?区别在哪里? [cpp] view plaincopy CpaintDC 在窗口的成员函数OnPaint中使用的一种设备上下文,在构造过程中自动调用BeginPaint析构时自动调用EndPaint CClientDC 代表客户区域的设备上下文 CWindowDC 代表整个窗口的设备上下文 CMetaFileDC 代表Windows图元文件的设备上下文 2. 碰撞检测是游戏中经常要用到的基本技术对于二维情况,请回答以下问题: 1). 如何判断一个点在一个多边形内 答:四边形上下左右边界判断 2). 如何判断两个多边形相交 答:判断A四边形每条边与B多边形的每边相交情况,如果有相交则多边形相交3). 如何判断两个点集所形成的完全图所围的区域是否相交 答:求凸包然后然后问题变成判断多边形是否相交3.PostMessage SendMessage和PostThreadMessage的区别是什么 [cpp] view plaincopy 答:post和send把消息送进指定窗口创建的线程的消息队列,send会等待消息处理后继续执行,post直接处理下一条语句,postThread直接把消息传递给对应线程的消息队列 4. 什么叫Alpha混合?当前流行的图片格式中哪些支持alpha通道?LayeredWindow和普通Window有什么区别? [cpp] view plaincopy 答: (1)将要绘制的物体颜色与颜色缓冲区中存在的颜色相混合,从而绘制出具有半透明效果的物体。 假设一种不透明东西的颜色是A,另一种透明的东西的颜色是B,那么透过B去看A,看上去的颜色C就是B和A的混合颜色,可以用这个式子来近似,设B物体的透明度为alpha(取值为0-1,0为完全透明,1为完全不透明) R(C)=alpha*R(B)+(1-alpha)*R(A) G(C)=alpha*G(B)+(1-alpha)*G(A) B(C)=alpha*B(B)+(1-alpha)*B(A) R(x)、G(x)、B(x)分别指颜色x的RGB分量。 (2)PNG TGA (3)Layered Window可以实现像素级的透明度调整而普通window只能整体调整透明度 5. 如果要实现一个多线程(非MFC)程序,选择多线程CRT, 创建线程的时候应该用CreateThread还是_beginthreadex(),为什么? 为何要用_beginthreadex()而非CreateThread? 答:参考http://blog.csdn.net/shu_nt/article/details/7543528 [cpp] view plaincopy 传统的CRT不支持多线程,为了能正常使用,_beginthreadex()使用了系统的TlsGetValue函数来获取对应线程的tiddata内存块地址,使tiddata与线程关联互不影响。 如果要作多线程(非MFC)程序,在主线程以外的任何线程内 - 使用malloc(),free(),new - 调用stdio.h或io.h,包括fopen(),open(),getchar(),write(),printf(),errno - 使用浮点变量和浮点运算函数 - 调用那些使用静态缓冲区的函数如: asctime(),strtok(),rand()等。 你就应该使用多线程的CRT并配合_beginthreadex(该函数只存在于多线程CRT), 其他情况下你可以使用单线程的CRT并配合CreateThread。 因为对产生的线程而言,_beginthreadex比之CreateThread会为上述操作多做额外的簿记工作,比如帮助strtok()为每个线程准备一份缓冲区。 然而多线程程序极少情况不使用上述那些函数(比如内存分配或者io),所以与其每次都要思考是要使用_beginthreadex还是CreateThread,不如就一棍子敲定_beginthreadex。 当 然你也许会借助win32来处理内存分配和Io,这时候你确实可以以单线程crt配合CreateThread,因为io的重任已经从crt转交 给了 win32。这时通常你应该使用HeapAlloc,HeapFree来处理内存分配,用CreateFile或者GetStdHandle来处 理 Io。 还有一点比较重要的是_beginthreadex传回的虽然是个unsigned long, 其实是个线程Handle(事实上_beginthreadex在内部就是调用了CreateThread),所以你应该用 CloseHandle来结 束他。千万不要使用ExitThread()来退出_beginthreadex创建的线程,那样会丧失释放簿记数据的机会, 应该使用 _endthreadex. 第六部分(选作): 数据库开发 1. 基于哈希的索引和基于树的索引有什么区别? 2. User表用于记录用户相关信息, Photo表用于记录用户的照片信息, 两个表的定义如下: CREATE TABLE User( --用户信息表 UserId bigint, --用户唯一id Account varchar(30) --用户唯一帐号 ); CREATE TABLE Photo( --照片信息表 PhotoId bigint, --照片唯一id UserId bigint, --照片所属用户id AccessCount int, --访问次数 Size bigint --照片文件实际大小 ) 1) 请给出SQL打印帐号为"dragon"的用户访问次数最多的5张照片的id; 2) 给出SQL打印拥有总的照片文件大小(total_size)最多的前10名用户的id, 并根据total_size降序排列 3) 为优化上面两个查询, 需要在User和Photo表上建立什么样的索引? 4) 简述索引对数据库性能的影响? 3. 什么是两阶段提交协议? 4. 数据库事务基本概念: 1) 什么是事务的ACID性质? 2) SQL标准中定义的事务隔离级别有哪四个? 3) 数据库中最常用的是哪两种并发控制协议? 4) 列举你所知的数据库管理系统中采用的并发控制协议 5. 数据库中有表User(id, name, age):表中数据可能会是以下形式: id name age 001 张三 56 002 李四 25 003 王五 56 004 赵六 21 005 钱七 39 006 孙八 56 ..............由于人员年龄有可能相等, 请写出SQL语句, 用于查询age最大的人员中, id最小的一个记录 6. 并发访问数据库时常使用连接池, 请问使用连接池的好处是什么? 对于有多台应用服务器并发访问一台中心数据库的情况, 数据库访问往往成为系统瓶颈, 请问在应用服务器上设计和使用连接池时该注意哪些问题, 以保证系统的可靠性正确性和整体性能. 假设每台应用服务器都执行相同的任务并且负载均衡. 第七部分(选作): Web开发 1. 以下哪一条Javascript语句会产生运行错误: A. var obj=( ); B. var obj=[ ]; C. var obj={ }; D. var obj=/ /; 2. 如下页面代码(示例代码DOCTYPE为Strict) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh"lang="zh"> <head> <title>测试</title> <meta http-equiv="content-type" content="text/html;charset=gbk" /> <meta http-equiv="content-style-type" content="text/cee"/> <meta http-equiv="content-script-type"content="text/javascript" /> <script type="text/css"> *{margin:0; padding:0} html{width:100%;height:100%; overflow:scroll;overflow-x:auto; text-align:center;border:0} .test{height:200px} </script> </head> <body> <div class="text">&nbsp;</div> </body> </html>假设a.jpg图片的规格是200pxX100px, 请给出当前背景图片距div.a顶部距离的计算方式和结果(css) 3. HTTP协议相关知识 A) 常见的HTTPRequest头字段有哪些? B) web服务器如何区分访问者是普通浏览用户还是搜索引擎的Spider? C) cookie按生命周期分类分为哪两类? 其生命周期分别是多长?向浏览器设置cookie时cookie有哪些属性可以设置, 分别起到什么作用? D) HTTP协议中Keep-Alive是什么意思? 使用Keep-Alive有何好处, 对服务器会有什么不利的影响? 对于不利的影响有什么解决方案 4. 简述你最常用的Web服务器的一种或者几种, 并说明如何在Web服务器和应用服务器之间建立反向代理 5. 简述你所了解的MVC各层次的常用开发框架, 说明其特点 6. 简述Web应用环境下远程调用的几种方式, 并且从性能异构性等方面比较其优劣 第八部分(选作): Flash开发 1.flash和js如何交互? 2. flash中的事件处理分哪几个过程 Event对象的target和currentTarget有什么区别? 第九部分(选作): 软件测试 1. 请描述你对测试的了解, 内容可以涉及测试流程, 测试类型, 测试方法, 测试工具等 2. 如果有一天你早上上班,发现不能上网了, 你会用什么步骤找出问题所在? 3. Web应用中实现了好友功能,用户可以给别人发"加为好友"的请求, 发了请求后可以取消请求, 对方收到请求后, 可以选择接受或者拒绝. 互为好友的两个人, 每个人都可以单方面删除对方, 请设想尽可能多的路径对此功能设计测试用例, 每个用例包括测试步骤和预期结果 4. 公司开发了一个web聊天工具, 用于网络用户之间的聊天, 一个人同时可以和多个人聊天, 功能类似于MSN等等IM工具要求该系统能承受1万个在线用户, 平均每个用户会和3个人同时聊天, 在网络条件正常的情况下, 要求用户收到消息的延迟时间不超过1分钟. 现在需要对系统进行性能测试, 验证系统是否达到预定要求, 请你写一个性能测试方案. 提示如下: 1) 性能测试的过程一般都是模拟大量客户端操作, 同时监控服务器的性能和客户端相应, 根据服务器的性能指标和客户端响应状况进行分析和判断 2) 系统的性能问题可以从两个角度考虑, 一个是服务器问题,设计得不好的程序, 在大负载或者长时间运行情况下, 服务器会down机; 另一个是客户端问题, 在负载大的时候, 客户端响应会变慢 3) 在答题中,可以不涉及性能测试工具, 监控工具等细节, 把你的测试思路说清楚就可以 5. 自动功能测试中会将测试用例组织成测试集合来统一运行, 测试集合suite按功能分类可以有若干个模块module, 每个模块module下包含若干个测试用例test. 现测试集合已经运行完毕, 但是需要在测试报告中统计各个模块的用例失败率, 将失败率超过20%的模块名与其失败率记录下来报警, 请编写实现上述功能的getTestReport函数. 可使用Java或C++等您熟悉的编程语言, 提供的接口及方法如下:测试集合接口Isuite: Collection<ITest>getTests() //得到测试集合下的所有测试用例test测试用例接口Itest: String getModule() //得到该用例对应的模块名称module int getResult() //得到该用例的执行结果:0失败 1成功报警函数: void alertMessage(String message) public static void getTestReport(ISuite suite){ //你的实现写在这里 } 来源:http://blog.csdn.net/mishifangxiangdefeng/article/details/8246614 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/03/28/2986856.html,如需转载请自行联系原作者
转自:http://www.cnblogs.com/scorpiozj/p/3302270.html 最近在sae上搭建了个wp,因为深感自己前端的东西缺乏,所以想依次为契机,学习一下。本文是从个人的sae版wp转载过来。 原文见此。 本篇也是在实现微博过程中遇到的问题。原先以为很简单的东西,到了实际做的时候,才发现这里出错那里不对。浪费很多时间,究根结底,还是没有弄清楚文档。 在iOS5, UIImage添加了可以拉伸图片的函数,即: [UIImage resizableImageWithCapInsets:] 它带参数: UIEdgeInsets,这是一结构体,包含 上/左/下/右四个参数。函数的作用我们看下文档: Creates and returns a new image object with the specified cap insets. Discussion You use this method to add cap insets to an image or to change the existing cap insets of an image. In both cases, you get back a new image and the original image remains untouched. During scaling or resizing of the image, areas covered by a cap are not scaled or resized. Instead, the pixel area not covered by the cap in each direction is tiled, left-to-right and top-to-bottom, to resize the image. This technique is often used to create variable-width buttons, which retain the same rounded corners but whose center region grows or shrinks as needed. For best performance, use a tiled area that is a 1×1 pixel area in size. 上左下右4参数定义了cap inset,就是离四条边的距离。拉升时,cap到边的部分不会被拉升,其余部分则会被拉升。尤其需要注意的时,拉升的时候,是从左到右,从上到下的方向。通俗点说,拉升不是全方向的拉升,而是垂直和水平拉升的叠加。 以我遇到的问题为例,我的图片是170×50, 需要填充到240×140,但是四周的圆角以及小箭头保持原样,如图: 开始我设置参数{20,10,10,10},在图上的位置大致: 这样拉升的结果: 很奇怪是不是,为什么出现了两个箭头(红色部分是设置的背景色用语区分)?再回头看下文档,才恍然大悟: 拉升的时候,是按前文说的两个方向来拉升 拉升的部分,是以tiled方式,简单的说就是以镜像的方式 按照1的规则,拉升的时候,水平和垂直方向都需要拉升。这样在水平拉升的时候,箭头其实处于拉升的部分。而拉升的时候,先按照原有的尺寸添加进去,不足的地方再把中间不拉升的部分填充进去,周而复始,直到填充完毕。因此,就有上面的现象了。 要达到需要的效果,必须按照如下的设置: 于是得到了我们需要的效果: Binggo~ 一切完毕。 说实话,这个函数在iOS5 beta的时候就知道了,可是一直是不正确的理解。直到今天需要用到的时候,才发现一直没理解对。于此同时,也发现自己 局限在工作相关的部分,工作以外的东西不是光知道就可以,还是需要去实践的。否则,就会遇到今天的情形,被个小问题,折磨了好久。 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3482733.html,如需转载请自行联系原作者
来源:http://blog.csdn.net/hopeyouknow/article/details/6711216 [cpp] view plaincopy #ifndef List_H #define List_H typedef int Item;/*定义数据项类型*/ typedef struct node * PNode;/*定义节点指针*/ typedef struct node/*节点的定义*/ { Item item; /*数据域*/ PNode next; /*链域*/ }Node; typedef PNode Position; typedef PNode List; List MakeEmpty(List L); /* 功能 生成空链表L */ int IsEmpty(List L); /* 功能 判定链表是否为空 */ int IsLast(Position P); /* 功能 判定位置P的节点是否为尾节点 */ Position Find(Item X,List L); /* 功能 在链表L中查找数据项为X的第一个节点 */ void Delete(Item X,List L); /* 功能 在链表L中删除数据项为X的第一个节点 */ Position FindPrevious(Item X,List L); /* 功能 在链表L中查找数据项为X的第一个节点的前驱位置 */ Position FindNext(Item X,List L); /* 功能 在链表L中查找数据项为X的第一个节点的后继位置 */ void Insert(Item X,List L,Position P); /* 功能 在链表L中P位置插入数据项为X的节点 */ void DeleteList(List L); /* 功能 删除链表L初头节点外的所有节点 */ Position Header(List L); /* 功能 获得链表L中头节点位置 */ Position First(List L); /* 功能 获得链表L中第一个数据节点的位置 */ Position Advance(Position P); /* 功能 获得P位置的后继节点位置 */ Item Retrieve(Position P); /* 功能 获得P位置节点的数据项 */ #endif 实现如下 [cpp] view plaincopy #include"List.h" #include<malloc.h> #include<stdlib.h> /* List MakeEmpty(List L) 参数 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3272645.html,如需转载请自行联系原作者
动操作系统的市场已经形成了三大系统三足鼎立的局面,谷歌的Android、苹果的iOS以及微软的Windows Phone三大移动移动操作占据着主要的领导地位。在Android操作系统出现的时候,市面上还有包括像诺基亚的Meego、三星Bada、Limo等 小众的移动操作系统出现,经过了1年多的发展,那些年昙花一现的移动操作系统机会都宣告死亡。最近,一批新兴的移动操作系统悄然崛起,新一代MeeGo系 统旗鱼(Sailfish)、Firefox OS、三星Tizen等新系统出现之后,又有一个新的移动操作系统诞生,这就是Ubuntu。 Canonical发布Ubuntu系统的时候,Ubuntu创始人沙特尔沃思表示:“相对于其他操作系统来说,我们要打造的生态系统会更加深入和 广泛,我们一直相信一个平台能够横跨多个环境,我们希望能够推出一款涵盖桌面应用和云端服务的‘超级手机’!”这席话能够看出Ubuntu是有备而来的移 动操作系统,下面我们就来看看Ubuntu到底如何来探索移动操作系统这个领域。 和Android本是同根生 借助Android的力量 Ubuntu对于大家来说十分陌生,但其实Ubuntu并非是一个头脑发热创造出来的移动操作系统。Ubuntu最早是一个以桌面应用为主的 Linux操作系统,主要注重PC端市场;在2012年2月,Ubuntu推出了Android版操作系统;而在2013年的1月3日,Ubuntu正式 发布独立的Ubuntu移动操作系统,从而也正式标志着Ubuntu进入移动操作系统领域。 (一)和Android使用相同的驱动 和Android使用相同的驱动就意味着生产Android的厂商可以直接使用Ubuntu移动操作系统,这对于终端厂商来说门槛非常低,很容易就 和终端结合,另外一方面我们也可以理解为目前市面上的Android系统智能手机也可以后期通过刷机来安装ubuntu移动操作系统,这对于Ubuntu 来说是天然的优势。 (二)兼容Android应用还并未确定 Ubuntu拥有的基于HTML5开发的应用可以像原生应用一样安装到系统中独立运行,并且使用各种系统服务和独立的系统通知。而且还可以获得原生 的OpenGL支持,这些优势都能够吸引各种游戏开发商加入到应用开发当中。不过目前尚不清楚Ubuntu手机是否支持直接转制已有的Android应 用,在发布会上的演示视频中可以看到最新的Android平台游戏《滑雪大冒险)》可以正常运行,因此从技术上来看兼容Android应用是可行的,但是 作为一款对立的移动操作系统要想和Android共用一个应用源还是很有挑战的风险的。 走微软的多平台互通战略 目前可以没有任何一个操作系统可以成功的实现多平台互通的战略,微软的Windows Phone 8和windows 8让我们看到了微软依旧想实现多平台贯穿的大战略,而微软在摸索了13年的移动操作平台依旧处于磨合阶段。此次Ubuntu移动操作系统的诞生,再加上之 前的Ubuntu的一举一措,我们可以看到Ubuntu将这种多平台互通的战略作为核心思路。 Ubuntu从早期作为PC上的桌面系统再到移动端Android版的桌面OS,再到如今的独立系统,每一步的选择足以能够说明Ubuntu未来发展的重点是移动版和桌面版相结合的主要发展思路。 Ubuntu for Android UbuntuTV界面 Ubuntu已经推出了智能电视版本系统UbuntuTV,现在又推出了手机版系统。Ubuntu官方非常强调多平台统一用户体验的概念。我们可以 看到大量的界面设计和功能特性在三个平台进行了统一。尽管现在Ubuntu在技术上已经实现了这种互通的概念,但是Ubuntu仍然面临着许多挑战: (一)终端的合作建立困难重重 Ubuntu在手机操作系统领域当中可以说是新军,虽然和Android采用相同的驱动,降低了和终端匹配的门槛,但这不足以让终端厂商来将更多的 注意力放到Ubuntu移动操作系统上,因为Android目前的市场份额之大完全让终端厂商不必冒这个风险。所以笔者认为终端的选择上应该考虑和芯片方 案厂商进行合作。 一个新的系统选择终端或者芯片厂商是很关键的一步 (二)开发环境的限制提高了门槛 如果你要开发原生应用,那么你需要一个Ubuntu桌面系统,并通过添加官方PPA软件仓库的形式来获取开发工具。目前Android 提供适用于所有主流桌面操作系统的开发环境;Windows Phone的开发虽然限定需要Windows操作系统,但是Windows系统拥有超过90%的桌面市场占有率;iOS虽然只能使用OSX系统开发,但是 iOS平台拥有成熟的盈利模式,这一点吸引到了很多开发者。而对于Ubuntu来说,如何能够吸引一个开发者加入到开发中来是最重要的,毕竟目前 Ubuntu还没有终端出现,据Ubuntu官方称搭载Ubuntu移动操作系统的手机也要2014年面世,这一切还是个未知数。 原生应用需要用Ubuntu桌面系统来开发 (三)体验创新但却很难被用户接受 Ubuntu将用户体验押宝在全手势操作上,虽然相比目前的主流移动操作系统来说是一个全新的创新,但是我们静下心来想想,这个技术并非很难实现, 只是现在适不适合抛弃传统的操作体验。毕竟全手势操作的上手并不容易,对于专业用户来说可能可以轻松搞定,但对于小白用户来说带来的是方便还是困惑,目前 还说不好。 选择全手势操作有很大风险 Android光环笼罩下争夺第三的位置 对于Ubuntu来说,目前的竞争对手并非是Android,我们可以把Ubuntu看作是Android操作系统的差异化变种,而Ubuntu的 大战略则是和微软相同,所以说目前Ubuntu应该借助和Android共同特性的优势来实现多平台互通的战略。Ubuntu目前应该解决的是能否兼容 Android的应用,因为在目前的移动互联网大环境下,应用的数量和质量已经成为了每个移动操作系统的根本。 虽然目前的移动操作系统领域形成了三足鼎立,但是Android和iOS的前两名地位几乎无法超越,对于市场份额很小的Windows Phone来说,Ubuntu的出现可以说让微软倍感压力,因为这款移动操作系统拥有Android先天开源的优势,同时也为多平台互通建立了完善的体 系,未来第三的位置之战将会更加激烈。 笔者认为Ubuntu可以被看作是Android的替补系统,毕竟现在选择Android系统的终端厂商也面临着谷歌随时的战略调整的危机,所以 Ubuntu自身保有android的开源优势,同时又有清晰的战略思路,这种Android+Windows Phone的混合体相信还是能够吸引一些厂商的加入。另外Ubuntu面临不光是和微软Windows Phone的直面竞争,旗鱼(Sailfish)、Firefox OS、三星Tizen等新兴系统的出现也不容忽视,在下周将举行的CES2013大会上,这些新兴的系统有可能都将展示出来,到底谁的体验得到用户的认 可,还需要有了终端之后才能够做出定论。Ubuntu只有真正完善了操作系统生态链的各个方面,才能够让用户来考虑是否该换一个新的操作系统来使用,而现 在Ubuntu只能说破茧而出的初期阶段。 来源:http://mobile.51cto.com/comment-376102.htm 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/01/14/2860252.html,如需转载请自行联系原作者
同步发布:http://www.yuanrengu.com/index.php/mysqlsolvetimestamp.html 在使用mysql时,如果数据库中的字段类型是timestamp,默认为0000-00-00,会发生异常:Value ‘0000-00-00 00:00:00’ can not be represented as java.sql.Timestamp. 解决办法如下: 给数据库的jdbc.url加上zeroDateTimeBehavior参数,如下: jdbc.url=jdbc:mysql://localhost:3306/table?characterEncoding=UTF-8&zeroDateTimeBehavior=round zeroDateTimeBehavior参数有两种配置: zeroDateTimeBehavior=round ,”0000-00-00“会默认转换为”0001-01-01 00:00:00” zeroDateTimeBehavior=convertToNull,“0000-00-00“会转换为null 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/6086303.html,如需转载请自行联系原作者
来源:http://51ctoblog.blog.51cto.com/26414/929322#559183-qzone-1-70272-9032e4e5e88102269a9addf0a99ae97c 20年前的夏天,Linux之父 你牛死.脱袜子 (Linus Torvalds) 勇敢的向全世界共享他编写的操作系统,从此这个诞生于一个偶然机会的Linux开始壮大。 博文专题 1 【Linux二十周年】爱上Linux的N+1个理由 http://blog.51cto.com/zt/42 2 构建高可用 Linux 服务器 http://blog.51cto.com/zt/185 3 一招一式攻克 Linux http://blog.51cto.com/zt/184 4 Linux 运维实战经验精彩分享 http://blog.51cto.com/zt/175 5 Linux Shell脚本攻略 http://blog.51cto.com/zt/143 6 Linux 下 DNS服务器配置 http://blog.51cto.com/zt/127 7 Linux运维监控利器- Nagios http://blog.51cto.com/zt/102 8 Linux 软件包管理系统:RPM http://blog.51cto.com/zt/100 9 Linux Squid代理服务器配置资料汇总 http://blog.51cto.com/zt/26 10 Linux虚拟服务器LVS从基础概念到实际应用 http://blog.51cto.com/zt/11 11 视频教程:轻松学习Linux http://blog.51cto.com/zt/222 推荐博文 1 抚琴煮酒 巧用手机邮件来设置报警短信息 http://andrewyu.blog.51cto.com/1604432/676032 2 抚琴煮酒 单IP电信服务器如何实现多view功能 http://andrewyu.blog.51cto.com/1604432/619378 3 抚琴煮酒 关于Nginx的limit_conn模块的思考 http://andrewyu.blog.51cto.com/1604432/595778 4 抚琴煮酒 修改Tomcat7的/webapps/ROOT发布路径 http://andrewyu.blog.51cto.com/1604432/544659 5 抚琴煮酒 Linux下用crontab定时执行PHP程序 http://andrewyu.blog.51cto.com/1604432/507309 6 抚琴煮酒 源码配置bind主从时的注意事项 http://andrewyu.blog.51cto.com/1604432/505080 7 抚琴煮酒 安全的Web主机iptables防火墙脚本 http://andrewyu.blog.51cto.com/1604432/716016 8 抚琴煮酒 自动甄别黑白名单的iptables安全脚本 http://andrewyu.blog.51cto.com/1604432/622704 9 抚琴煮酒 Centos5.5 X86_64下安装PortSentry1.2防止恶意扫描 http://andrewyu.blog.51cto.com/1604432/602015 10 抚琴煮酒 工作中的Linux防火墙心得 http://andrewyu.blog.51cto.com/1604432/502391 11 南非蚂蚁 Heartbeat3.x应用全攻略之: 测试Heartbeat的HA功能 http://ixdba.blog.51cto.com/2895551/747510 12 南非蚂蚁 Linux系统下常见性能分析工具的使用 http://ixdba.blog.51cto.com/2895551/715742 13 南非蚂蚁 分享与快乐-我的Linux情结 http://ixdba.blog.51cto.com/2895551/631002 14 南非蚂蚁 献给初学者:谈谈如何学习Linux操作系统 http://ixdba.blog.51cto.com/2895551/569329 15 南非蚂蚁 在Linux下轻松玩转Samba服务器 http://ixdba.blog.51cto.com/2895551/568644 16 南非蚂蚁 在Linux下轻松搭建自己的DNS服务器 http://ixdba.blog.51cto.com/2895551/567920 17 南非蚂蚁 Linux下集群技术应用概述 http://ixdba.blog.51cto.com/2895551/566802 18 南非蚂蚁 浅谈linux系统下常见的故障与处理方法 http://ixdba.blog.51cto.com/2895551/566345 19 南非蚂蚁 浅谈Linux磁盘存储管理续【逻辑卷管理(LVM)】 http://ixdba.blog.51cto.com/2895551/562111 20 南非蚂蚁 浅谈Linux磁盘存储管理 http://ixdba.blog.51cto.com/2895551/560119 21 南非蚂蚁 Linux任务调度进程crond的使用 http://ixdba.blog.51cto.com/2895551/545371 22 南非蚂蚁 初探Linux进程管理机制 http://ixdba.blog.51cto.com/2895551/543737 23 南非蚂蚁 浅谈Linux的内存管理机制 http://ixdba.blog.51cto.com/2895551/541355 24 南非蚂蚁 细说Linux下软件包的安装与管理 http://ixdba.blog.51cto.com/2895551/537892 25 南非蚂蚁 Linux系统运行级与启动机制剖析 http://ixdba.blog.51cto.com/2895551/533740 26 南非蚂蚁 浅谈Linux用户权限管理之三(文件与权限的设定) http://ixdba.blog.51cto.com/2895551/531799 27 南非蚂蚁 浅谈Linux用户权限管理之二(用户管理工具) http://ixdba.blog.51cto.com/2895551/531793 28 南非蚂蚁 浅谈Linux用户权限管理之一(用户与组的概念) http://ixdba.blog.51cto.com/2895551/531787 29 南非蚂蚁 谈谈Linux下Yum的使用 http://ixdba.blog.51cto.com/2895551/530708 30 南非蚂蚁 Linux性能调优基本策略设定 http://ixdba.blog.51cto.com/2895551/526450 31 南非蚂蚁 locale: Cannot set问题 http://ixdba.blog.51cto.com/2895551/526447 32 南非蚂蚁 PXE+TFTP+DHCP网络自动引导安装Linux http://ixdba.blog.51cto.com/2895551/526446 33 南非蚂蚁 SUN软件包管理的命令:pkginfo、pkgadd和pkgrm http://ixdba.blog.51cto.com/2895551/526444 34 南非蚂蚁 Linux下常用安全策略设置方法 http://ixdba.blog.51cto.com/2895551/526443 35 南非蚂蚁 再谈shell之“>/dev/null 2>&1” http://ixdba.blog.51cto.com/2895551/526442 36 南非蚂蚁 如何选择适合自己的linux发行版 http://ixdba.blog.51cto.com/2895551/526440 37 南非蚂蚁 Linux下shell的使用 http://ixdba.blog.51cto.com/2895551/526439 38 南非蚂蚁 Redhat的Linux产品版本AS/ES/WS的联系与区别 http://ixdba.blog.51cto.com/2895551/526438 39 南非蚂蚁 献给初学者:轻松快捷搭建VSFTP服务器 http://ixdba.blog.51cto.com/2895551/526437 40 南非蚂蚁 PCI ROOT HID fail=0x5 ACPI Linux错误一般解决之道 http://ixdba.blog.51cto.com/2895551/526113 41 老男孩oldboy lamp系列-MySQL运维管理思想 http://oldboy.blog.51cto.com/2561410/843316 42 老男孩oldboy lamp系列-MySQL灾难恢复精华 http://oldboy.blog.51cto.com/2561410/843303 43 老男孩oldboy lamp系列-MySQL主从复制实践视频讲解 http://oldboy.blog.51cto.com/2561410/839399 44 老男孩oldboy lamp系列-MySQL主从复制原理视频 http://oldboy.blog.51cto.com/2561410/839383 45 老男孩oldboy 老男孩linux运维实战培训网络班学习介绍 http://oldboy.blog.51cto.com/2561410/826627 46 老男孩oldboy 批量分发管理三种解决方案案例视频分享 http://oldboy.blog.51cto.com/2561410/824931 47 老男孩oldboy 老男孩linux运维实战培训中心讲师介绍 http://oldboy.blog.51cto.com/2561410/822770 48 老男孩oldboy 7、sudo权限问题考察一题(考试题答案系列) http://oldboy.blog.51cto.com/2561410/792478 49 老男孩oldboy find+sed考试题及生产实战解决案例分享(考试答案系列) http://oldboy.blog.51cto.com/2561410/792396 50 老男孩oldboy 3.请执行命令取出linux中eth0的IP地址(考试题答案系列) http://oldboy.blog.51cto.com/2561410/791670 51 老男孩oldboy [原创]2.建一个新目录/oldboy的硬链接数是多少?(考试题答案系列) http://oldboy.blog.51cto.com/2561410/791651 52 老男孩oldboy 1、取得/etiantian文件的权限对应的数字(考试题答案系列) http://oldboy.blog.51cto.com/2561410/791638 53 老男孩oldboy linux下文件删除的原理精华讲解(考试题答案系列) http://oldboy.blog.51cto.com/2561410/791322 54 老男孩oldboy linux运行级别0-6的各自含义(考试题答案系列) http://oldboy.blog.51cto.com/2561410/791318 55 老男孩oldboy linux shell单引号、双引号及无引号区别(考试题答案系列) http://oldboy.blog.51cto.com/2561410/791314 56 老男孩oldboy linux下软链接和硬链接的区别(考试题答案系列) http://oldboy.blog.51cto.com/2561410/791292 57 老男孩oldboy linux开机到登陆的启动过程描述(考试题答案系列) http://oldboy.blog.51cto.com/2561410/791273 58 老男孩oldboy 老男孩linux培训某节课前考试试题及答案分享 http://oldboy.blog.51cto.com/2561410/791245 59 老男孩oldboy Linux系统基础网络配置老鸟精华篇 http://oldboy.blog.51cto.com/2561410/784625 60 老男孩oldboy 老男孩之学好运维四要素“坚持”的启示 http://oldboy.blog.51cto.com/2561410/768712 61 老男孩oldboy linux系统计算从1加到100之和思路风暴 http://oldboy.blog.51cto.com/2561410/767862 62 老男孩oldboy 一道实用linux运维问题的9种shell解答方法! http://oldboy.blog.51cto.com/2561410/760192 63 李晨光 Linux安全应用之防垃圾邮件服务器的构建 http://chenguang.blog.51cto.com/350944/862523 64 李晨光 Linux下网络服务的安全设置 http://chenguang.blog.51cto.com/350944/861398 65 李晨光 Linux常用的安全工具 http://chenguang.blog.51cto.com/350944/857907 66 李晨光 Linux系统安全加固(一) http://chenguang.blog.51cto.com/350944/847451 67 李晨光 轻松掌握Ubuntu Linux的3D桌面快捷键使用 http://chenguang.blog.51cto.com/350944/795401 68 李晨光 通过PXE安装Linux实况 http://chenguang.blog.51cto.com/350944/786474 69 李晨光 Linux下汇编调试器GDB的使用 http://chenguang.blog.51cto.com/350944/746692 70 李晨光 基于Linux平台的Lotus Domino.. http://chenguang.blog.51cto.com/350944/479670 71 李晨光 如何解决Linux下的软件包依赖.. http://chenguang.blog.51cto.com/350944/478728 72 李晨光 应用Linux远程桌面(附视频) http://chenguang.blog.51cto.com/350944/739498 73 李晨光 Linux智能手机安全策略研究 http://chenguang.blog.51cto.com/350944/718057 74 李晨光 国产麒麟Linux安装体验 http://chenguang.blog.51cto.com/350944/715052 75 李晨光 Linux桌面新彩虹-Fedora 14 炫.. http://chenguang.blog.51cto.com/350944/601954 76 李晨光 Linux下搭建JSP环境 http://chenguang.blog.51cto.com/350944/589432 77 李晨光 如何使用Linux套接字? http://chenguang.blog.51cto.com/350944/581159 78 李晨光 IPod在Linux下的实战 http://chenguang.blog.51cto.com/350944/578725 79 李晨光 基于Linux系统的Nagios网络管.. http://chenguang.blog.51cto.com/350944/486368 80 林肯 shell解决服务器高可用 http://president.blog.51cto.com/4990508/860765 81 林肯 shell解决DNS负载均衡RS的健康检测 http://president.blog.51cto.com/4990508/859637 82 林肯 linux-shell面试题 之三 http://president.blog.51cto.com/4990508/854647 83 林肯 linux-shell面试题 http://president.blog.51cto.com/4990508/854249 84 林肯 linux-shell面试题 http://president.blog.51cto.com/4990508/851407 85 菜菜光 linux服务器集群运维经验 http://1662935.blog.51cto.com/1652935/846177 86 煮酒品茶 一起学shell之变量判断重复(五) http://cwtea.blog.51cto.com/4500217/858605 87 煮酒品茶 一起学Shell之文本处理以及管道(四) http://cwtea.blog.51cto.com/4500217/855587 88 煮酒品茶 一起学Shell之之查找与替换(三) http://cwtea.blog.51cto.com/4500217/851828 89 煮酒品茶 一起学Shell之输出以及其它(二) http://cwtea.blog.51cto.com/4500217/851118 90 煮酒品茶 一起学Shell之背景知识(一) http://cwtea.blog.51cto.com/4500217/849534 91 煮酒品茶 对网页文章进行采集(适合小说采集) http://cwtea.blog.51cto.com/4500217/860356 92 煮酒品茶 思维发散-减轻运维十倍工作量 http://cwtea.blog.51cto.com/4500217/845330 93 煮酒品茶 规律批量下载51CTO运维趋势后引发的问题及反思 http://cwtea.blog.51cto.com/4500217/845004 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/04/09/3009366.html,如需转载请自行联系原作者
名称 复杂度 说明 备注 冒泡排序 BubbleSort O(N*N) 将待排序的元素看作是竖着排列的 “ 气泡 ” ,较小的元素比较轻,从而要往上浮 插入排序 InsertionSort O(N*N) 逐一取出元素,在已经排序的元素序列中从后向前扫描,放到适当的位置 起初,已经排序的元素序列为空 选择排序 SelcetionSort O(N*N) 首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此递归。 快速排序 QuickSort O(n*log2 (n)) 先选择中间值,然后把比它小的放在左边,大的放在右边(具体的实现是从两边找,找到一对后交换)。然后对两边分别使用这个过程(递归)。 堆排序 HeapSort O(n*log2 (n)) 利用堆( heaps )这种数据结构来构造的一种排序算法。堆是一个近似完全二叉树结构,并同时满足堆属性:即子节点的键值或索引总是小于(或者大于)它的父节点。 近似完全二叉树 希尔排序 ShellSort O(n1+ £ ) 0<£ <1 选择一个步长 (Step) , 然后按间隔为步长的单元进行排序 . 递归 , 步长逐渐变小 , 直至为 1. 箱排序 BinSort O(n) 设置若干个箱子,把关键字等于 k 的记录全都装入到第 k 个箱子里 ( 分配 ) ,然后按序号依次将各非空的箱子首尾连接起来 ( 收集 ) 。 分配排序的一种:通过 " 分配 " 和 " 收集 " 过程来实现排序。 桶排序 BucketSort O(n) 桶排序的思想是把 [0 , 1) 划分为 n 个大小相同的子区间,每一子区间是一个桶。 分配排序的一种:通过 " 分配 " 和 " 收集 " 过程来实现排序。 冒泡排序 冒泡排序算法的思想:很简单,每次遍历完序列都把最大(小)的元素放在最前面,然后再对剩下的序列重复前面的一个过程,每次遍历完之后待排序序列就少一个元素,当待排序序列减小为只有一个元素的时候排序就结束了。因此,复杂度在最坏的情况下是O(N ^ 2)。 Java代码 public static void BubbleSort(int[] array){ if(array==null || array.length==0){ return; } int size = array.length; for(int i=0; i<size-1; i++){ boolean hasSwap = false; for(int j=i+1; j<size; j++){ if(array[j]<array[i]){ // swap int temp = array[i]; array[i] = array[j]; array[j] = temp; hasSwap = true; } if(!hasSwap){ break; } } } } 选择排序 选择排序(Selection Sort)的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕。 Java代码 public static void SelectionSort(int[] array){ if(array==null || array.length==0){ return; } int size = array.length; for(int i=0; i<size-1; i++){ int minIndex = i; for(int j=i+1; j<size; j++){ if(array[j]<array[minIndex]){ minIndex = j; } } // 将最小值置于最前端 if(minIndex!=i){ int temp = array[minIndex]; array[minIndex] = array[i]; array[i] = temp; } } } *与冒泡排序的区别,交换次数。每次遍历找到最小值,只交换一次。冒泡是每次比较都进行交换。 插入排序 插入排序是最简单最直观的排序算法了,它的依据是:遍历到第N个元素的时候前面的N-1个元素已经是排序好的了,那么就查找前面的N-1个元素把这第N个元素放在合适的位置,如此下去直到遍历完序列的元素为止。 算法的复杂度也是简单的,排序第一个需要1的复杂度,排序第二个需要2的复杂度,因此整个的复杂度就是1 + 2 + 3 + …… + N = O(N ^ 2)的复杂度。 Java代码 public static void InsertionSort(int[] array){ if(array==null || array.length==0){ return; } int size = array.length; // 默认认为第一位是有序的 for(int i=1; i<size; i++){ int key = array[i]; // 对有序列从后向前扫描 int j=0; for(j=i-1; j>=0; j--){ if(key<array[j]){ array[j+1] = array[j]; }else{ break; } } array[j+1] = key; } } 希尔排序 shell排序是对插入排序的一个改装,它每次排序把序列的元素按照某个增量分成几个子序列,对这几个子序列进行插入排序,然后不断的缩小增量 扩大每个子序列的元素数量,直到增量为一的时候子序列就和原先的待排列序列一样了,此时只需要做少量的比较和移动就可以完成对序列的排序了。 Java代码 public static void ShellSort(int array[]) { if(array==null || array.length==0){ return; } int temp; int size = array.length; // 增量从数组长度的一半开始,每次减小一倍 for (int increment = size / 2; increment > 0; increment /= 2) { for (int i = increment; i < size; ++i) { temp = array[i]; // 对一组增量为increment的元素进行插入排序 int j = 0; for (j = i; j >= increment; j -= increment) { // 把i之前大于array[i]的数据向后移动 if (temp < array[j - increment]) { array[j] = array[j - increment]; } else { break; } } // 在合适位置安放当前元素 array[j] = temp; } } } 快速排序 快速排序的算法思想: 选定一个枢轴元素,对待排序序列进行分割,分割之后的序列一个部分小于枢轴元素,一个部分大于枢轴元素,再对这两个分割好的子序列进行上述的过程。 Java代码 public static void QuickSort(int[] array, int low, int hight){ if(array==null || array.length==0){ return; } if(low<hight){ int n = Partition(array, low, hight); QuickSort(array, 0, n); QuickSort(array, n+1, hight); } } // 对一个给定范围的子序列选定一个枢纽元素,执行完函数之后返回分割元素所在的位置, // 在分割元素之前的元素都小于枢纽元素,在它后面的元素都大于这个元素 private static int Partition(int[] array, int low, int hight){ // 采用子序列的第一个元素为枢纽元素 int pivot = array[low]; int temp = 0; while(low<hight){ // 从后往前在后半部分中寻找第一个小于枢纽元素的元素 while(low<hight && array[hight]>=pivot){ hight--; } // 将这个比枢纽元素小的元素交换到前半部分 temp = array[low]; array[low] = array[hight]; array[hight] = pivot; // 从前往后在前半部分中寻找第一个大于枢纽元素的元素 while(low<hight && array[low]<=pivot){ low++; } // 将这个比枢纽元素大的元素交换到后半部分 temp = array[low]; array[low] = array[hight]; array[hight] = temp; } // 返回枢纽元素所在的位置 return low; } 来源:http://univasity.iteye.com/blog/1164713 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/05/08/3066927.html,如需转载请自行联系原作者
在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。 静态成员的定义或声明要加个关键static。静态成员可以通过双冒号来使用即<类名>::<静态成员名>。 在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象。希望阅读本文可以使读者对类的静态成员变量和成员函数有更为深刻的认识。 第一个例子,通过类名调用静态成员函数和非静态成员函数 class Point { public: void init() { } static void output() { } }; void main() { Point::init(); Point::output(); } 编译出错:error C2352: 'Point::init' : illegal call of non-static member function 结论1:不能通过类名来调用类的非静态成员函数。 第二个例子,通过类的对象调用静态成员函数和非静态成员函数 将上例的main()改为: void main() { Point pt; pt.init(); pt.output(); } 编译通过。 结论2:类的对象可以使用静态成员函数和非静态成员函数。 第三个例子,在类的静态成员函数中使用类的非静态成员 #include <stdio.h> class Point { public: void init() { } static void output() { printf("%d\n", m_x); } private: int m_x; }; void main() { Point pt; pt.output(); } 编译出错:error C2597: illegal reference to data member 'Point::m_x' in a static member function 因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。 结论3:静态成员函数中不能引用非静态成员。 第四个例子,在类的非静态成员函数中使用类的静态成员 class Point { public: void init() { output(); } static void output() { } }; void main() { Point pt; pt.output(); } 编译通过。 结论4:类的非静态成员函数可以调用用静态成员函数,但反之不能。 第五个例子,使用类的静态成员变量 #include <stdio.h> class Point { public: Point() { m_nPointCount++; } ~Point() { m_nPointCount--; } static void output() { printf("%d\n", m_nPointCount); } private: static int m_nPointCount; }; void main() { Point pt; pt.output(); } 按Ctrl+F7编译无错误,按F7生成EXE程序时报链接错误 error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA) 这是因为类的静态成员变量在使用前必须先初始化。 在main()函数前加上int Point::m_nPointCount = 0; 再编译链接无错误,运行程序将输出1。 结论5:类的静态成员变量必须先初始化再使用。 结合上面的五个例子,对类的静态成员变量和成员函数作个总结: 一。静态成员函数中不能调用非静态成员。 二。非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。 三。静态成员变量使用前必须先初始化(如int MyClass::m_nNumber = 0;),否则会在linker时出错。 再给一个利用类的静态成员变量和函数的例子以加深理解,这个例子建立一个学生类,每个学生类的对象将组成一个双向链表,用一个静态成员变量记录这个双向链表的表头,一个静态成员函数输出这个双向链表。 #include <stdio.h> #include <string.h> const int MAX_NAME_SIZE = 30; class Student { public: Student(char *pszName); ~Student(); public: static void PrintfAllStudents(); private: char m_name[MAX_NAME_SIZE]; Student *next; Student *prev; static Student *m_head; }; Student::Student(char *pszName) { strcpy(this->m_name, pszName); //建立双向链表,新数据从链表头部插入。 this->next = m_head; this->prev = NULL; if (m_head != NULL) m_head->prev = this; m_head = this; } Student::~Student ()//析构过程就是节点的脱离过程 { if (this == m_head) //该节点就是头节点。 { m_head = this->next; } else { this->prev->next = this->next; this->next->prev = this->prev; } } void Student::PrintfAllStudents() { for (Student *p = m_head; p != NULL; p = p->next) printf("%s\n", p->m_name); } Student* Student::m_head = NULL; void main() { Student studentA("AAA"); Student studentB("BBB"); Student studentC("CCC"); Student studentD("DDD"); Student student("MoreWindows"); Student::PrintfAllStudents(); } 程序将输出: 当然在本例还可以增加个静态成员变量来表示链表中学生个数,如果读者有兴趣,就将这个作为小练习吧。 原文地址:http://www.cnblogs.com/morewindows/archive/2011/08/26/2154198.html 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3182030.html,如需转载请自行联系原作者
以为用mac后使用会变得更方便些,写毕设时终于派上用场,可惜啊,mac竟然打不开.caj文件,这意味着什么?相信所有在做毕设的小伙伴们都能懂其中的凄凉。特别是硕士或博士的论文,你得从知网上下上百篇的文献,下后竟然发现打不开,打不开有木有?是不是有种砸电脑的冲动。网上有一些破解方法,但实现起来都比较麻烦。 冲动是魔鬼。淡定,现在cajviewer官网出了CAJViewer for MAC(测试版)。 这真是个激动人心的消息,小伙伴们再也不用担心比不了业了! 下载地址:http://cajviewer.cnki.net/download.html 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3476690.html,如需转载请自行联系原作者
转载于:http://blog.csdn.net/iunion/article/details/9045573 刚刚更新过的代码出现了问题,在上传之前的验证就不通过,提示 Apps are not permitted to access the UDID and must not use the uniqueIdentifier method of UIDevice. Please update your apps and servers to associate users with the Vendor or Advertising identifiers introduced in iOS 6。于是很纠结怎么解决这个问题。查询后才知道苹果刚刚修改了上传的规则,而且很严厉的执行,不允许有任何UUID的代码,看来是要100%将UUID从AppStore上绝迹啊。弄了两个小时解决的方法,给出我的解决办法 1.在xcode的工程代码中全局搜索uniqueIdentifier,搜索到的代码要去掉,或者用其他的方法替换掉。 2.第二个可能就是代码中引用的.a文件中可能用到了UUID,这个也是不能通过的,解决办法: 1>首先打开终端,cd到工程根目录; 2>输入命令 find . -name "*.a",这个命令过后就会将工程中用到的.a文件全部列出来,类似这种 ./DMOfferWallSDK/libDomobOfferWallSDK.a ./DomobAdSDK/libDomobAdSDK.a ./libDianRuAdWall.a ./libFlurry.a ./libYouMi.a 3>然后输入命令 strings ./DMOfferWallSDK/libDomobOfferWallSDK.a | grep unique ,命令的红色部分,依次换成上面的列出的.a文件,一旦有不符合UUID使用的.a文件,遇到这个命令后会有如下显示结果出现:uniqueIdentifier,然后将相应的SDk去掉,或者换上最新的版本,同样的方法确认没有用到UUID 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3449192.html,如需转载请自行联系原作者
来源:http://www.cnblogs.com/lanxuezaipiao/p/3325628.html 一、eclipse安装过程 首先确保在安装eclipse之前已经安装好Java虚拟机 1. eclipse官网下载压缩包 下载地址:http://www.eclipse.org/downloads/?osType=linux&release=undefined 2. 解压缩到 /opt/(/opt一般为大型商业软件或第三方软件包安装的地方,我习惯将第三方软件安装在此,当然你也可以安装在/usr/local下或其他地方) sudo tar xzvf eclipse-standard-kepler-R-linux-gtk.tar.gz -C /opt tar的-C参数指定了文件解压后所在的目录 注意: (1)由于/opt权限默认情况下为root所拥有,普通用户不能写,故需要加sudo 如果希望普通用户也能读写/opt,则可以修改该目录的权限(完全为了方便,当然如果需要考虑安全问题,则不应该修改此目录权限): sudo chown -R jmwang:jmwang /opt (2)如果想把eclipse目录的更改为root拥有,则可以执行下面的命令 sudo chown -R root:root /opt/eclipse 3. 在/usr/bin目录下创建一个启动脚本eclipse sudo gedit /usr/bin/eclipse 然后在该文件中添加以下内容: #!/bin/sh export ECLIPSE_HOME=/opt/eclipse $ECLIPSE_HOME/eclipse $* PS:$*($@) 传递给脚本的所有参数的值 该命令的目的就是为了能在terminal下直接输入eclipse命令就能打开eclipse,但此时权限不够,还需要第4步 4. 修改该脚本的权限,让它变成可执行,执行下面的命令: sudo chmod +x /usr/bin/eclipse 以上可以通过命令行输入eclipse就可以启动IDE了。 5. 在桌面上创建启动图标 方法一、通过桌面启动器创建 命令:gnome-desktop-item-edit ~/ --create-new 名称:eclipse 命令:eclipse 图标: /opt/eclipse/icon.xpm 将用户目录(我的是/home/hadoop)下刚创建的启动图标拖到桌面即可。 注意: (1)上述命令并不是Ubuntu自带的,需要我们自己安装: sudo apt-get install --no-install-recommends gnome-panel (2)用该方式产生的启动图标双击运行时不会产生命令行提示窗口,十分友好 方法二、通过在应用程序中创建,其实就是添加到applications中 sudo gedit /usr/share/applications/eclipse.desktop 然后在弹出的文件中输入: [Desktop Entry] Name=eclipse Comment=Eclipse IDE (v4.3) Exec=eclipse Icon=/opt/eclipse/icon.xpm Terminal=false Type=Application Categories=Development; StartupNotify=true 保存文件。然后将此文件拷贝到桌面,可以双击桌面 eclipse的图标来运行eclipse。 注意:红色部分表示双击运行时是否会产生命令行窗口,true表示产生命令行窗口,是否不友好,所以一定要把Terminal的值写为false 但此时我的eclipse启动出现了问题: 找不到jre路径,解决方案如下: 方案一、修改eclipse安装目录下的eclipse.ini文件,在首行添加虚拟机参数-vm的设置 -vm /opt/java/jdk1.7.0_25/jre/bin/java # -vm 参数用以指定使用哪一个 jvm 来执行Eclipse 方案二、修改步骤3中的启动脚本,在这里面指定启动参数,如下: #!/bin/sh export ECLIPSE_HOME=/opt/eclipse #$ECLIPSE_HOME/eclipse $* $ECLIPSE_HOME/eclipse -vm /opt/java/jdk1.7.0_25/jre/bin/java -data /home/jmwang/workspace & # -vm 参数用以指定使用哪一个 jvm 来执行Eclipse # -date参数用以指定Eclipse的workspace 二、eclipse使用问题小记 1. eclipse不小心删除默认工作空间后启动不了IDE 经常会遇到删除原来工作空间及相应的目录会发现eclipse启动不了的问题,如我本来的linux用户名为jmwang,eclipse默认工作空间是 /home/jmwang/workspace,但有一次因为需要更改了用户名,改为hadoop,相应/home/jmwang/workspace也 改为了/home/hadoop/workspace,此时打开eclipse出现以下错误: 当然首先想到改变eclipse默认的工作空间,改为/home/hadoop/workspace,而且只能通过配置文件改(IDE根本打不开),方法如下: 打开eclipse的安装目录,依次打开以下目录,configuration\.settings 文件夹下有一个文件 org.eclipse.ui.ide.prefs,里面的内容格式如下: MAX_RECENT_WORKSPACES=5 RECENT_WORKSPACES=/home/hadoop/workspace RECENT_WORKSPACES_PROTOCOL=3 SHOW_WORKSPACE_SELECTION_DIALOG=false eclipse.preferences.version=1 修改上面的红色加粗部分即可,最后保存,发现还是启动不了eclipse,仍然报那个错误,说明工作空间还没改掉,苦思冥想,回忆eclipse的安装过程,发现我当初在/usr/bin下建了个eclipse的启动脚本eclipse,内容如下: #!/bin/sh export ECLIPSE_HOME=/opt/eclipse #$ECLIPSE_HOME/eclipse $* $ECLIPSE_HOME/eclipse -vm /opt/java/jdk1.7.0_25/jre/bin/java -data /home/jmwang/workspace & 红色部分仍为原来的空间,而这个优先级是最高的,所以前面的修改无效,将其改为/home/hadoop/workspace后再打开eclipse就可以了。 2. 如何恢复eclipse工作空间提示功能 由于一直习惯eclipse中只使用一个工作空间,所以一般在eclipse刚刚安装好后第一次启动时,我就钩上了弹出的工作空间选择的对话框中以后不再提示的钩选。 结果这次突然需要用到它的工作空间提示功能了,却突然不知道如何找回它的提示功能了。 设置方法如下: Window -> Preferences -> General -> Startup and Shuodown -> Workspaces -> Prompt for workspace on startup 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3366996.html,如需转载请自行联系原作者
1. 最简单的用法 UIAlertView*alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"这是一个简单的警告框!" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil]; [alert show]; [alert release]; 2. 为UIAlertView添加多个按钮 UIAlertView*alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"请选择一个按钮:" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"按钮一", @"按钮二", @"按钮三",nil]; [alert show]; [alert release]; 3. 如何判断用户点击的按钮 UIAlertView有一个委托UIAlertViewDelegate ,继承该委托来实现点击事件 头文件: @interface MyAlertViewViewController : UIViewController<UIAlertViewDelegate> { } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex; -(IBAction) buttonPressed; @end 源文件: -(IBAction) buttonPressed { UIAlertView*alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"请选择一个按钮:" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"按钮一", @"按钮二", @"按钮三",nil]; [alert show]; [alert release]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { NSString* msg = [[NSString alloc] initWithFormat:@"您按下的第%d个按钮!",buttonIndex]; UIAlertView* alert = [[UIAlertView alloc]initWithTitle:@"提示" message:msg delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil]; [alert show]; [alert release]; [msg release]; } 点击“取消”,“按钮一”,“按钮二”,“按钮三”的索引buttonIndex分别是0,1,2,3 4. 手动的取消对话框 [alertdismissWithClickedButtonIndex:0 animated:YES]; 5:为UIAlertView添加子视图 在 为UIAlertView对象太添加子视图的过程中,有点是需要注意的地方,如果删除按钮,也就是取消UIAlerView视图中所有的按钮的时候,可能 会导致整个显示结构失衡。按钮占用的空间不会消失,我们也可以理解为这些按钮没有真正的删除,仅仅是他不可见了而已。如果在UIAlertview对象中 仅仅用来显示文本,那么,可以在消息的开头添加换行符(@"\n)有助于平衡按钮底部和顶部的空间。 下面的代码用来演示如何为UIAlertview对象添加子视图的方法。 UIAlertView*alert = [[UIAlertView alloc]initWithTitle:@"请等待" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:nil]; [alert show]; UIActivityIndicatorView*activeView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; activeView.center = CGPointMake(alert.bounds.size.width/2.0f, alert.bounds.size.height-40.0f); [activeView startAnimating]; [alert addSubview:activeView]; [activeView release]; [alert release]; 6. UIAlertView默认情况下所有的text是居中对齐的。 那如果需要将文本向左对齐或者添加其他控件比如输入框时该怎么办呢? 不用担心, iPhone SDK还是很灵活的, 有很多delegate消息供调用程序使用。 所要做的就是在 - (void)willPresentAlertView:(UIAlertView *)alertView 中按照自己的需要修改或添加即可, 比如需要将消息文本左对齐,下面的代码即可实现: -(void) willPresentAlertView:(UIAlertView *)alertView { for( UIView * view in alertView.subviews ) { if( [view isKindOfClass:[UILabel class]] ) { UILabel* label = (UILabel*) view; label.textAlignment=UITextAlignmentLeft; } } } 这段代码很简单, 就是在消息框即将弹出时,遍历所有消息框对象,将其文本对齐属性修改为 UITextAlignmentLeft即可。 添加其他部件也如出一辙, 如下代码添加两个UITextField: -(void) willPresentAlertView:(UIAlertView *)alertView { CGRect frame = alertView.frame; frame.origin.y -= 120; frame.size.height += 80; alertView.frame = frame; for( UIView * viewin alertView.subviews ) { if( ![viewisKindOfClass:[UILabelclass]] ) { CGRect btnFrame = view.frame; btnFrame.origin.y += 70; view.frame = btnFrame; } } UITextField* accoutName = [[UITextFieldalloc] init]; UITextField* accoutPassword = [[UITextFieldalloc] init]; accoutName.frame = CGRectMake( 10, frame.origin.y + 40,frame.size.width - 20, 30 ); accoutPassword.frame = CGRectMake( 10, frame.origin.y + 80,frame.size.width -20, 30 ); accoutName.placeholder = @"请输入账号"; accoutPassword.placeholder = @"请输入密码"; accoutPassword.secureTextEntry = YES; [alertView addSubview:accoutPassword]; [alertView addSubview:accoutName]; [accoutName release]; [accoutPassword release]; } 显示将消息框固有的button和label移位, 不然添加的text field会将其遮盖住。 然后添加需要的部件到相应的位置即可。 对于UIActionSheet其实也是一样的, 在 - (void)willPresentActionSheet:(UIActionSheet *)actionSheet 中做同样的处理一样可以得到自己想要的界面。 来源:http://hi.baidu.com/richiechyi/item/e2aa2f714996f012d0dcb39a 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3469038.html,如需转载请自行联系原作者
来源:http://blog.csdn.net/duxinfeng2010/article/details/8757211 最近遇到这样一个问题,以前的时候并未注意;新建一个工程,然后添加一个类,文件结构是这样的 然后写了这样一小段程序,运行 [cpp] view plaincopy - (void)viewDidLoad { [super viewDidLoad]; Test *testObj = [[Test alloc] init]; NSLog(@"release 前 %d",[testObj retainCount]); [testObj release]; NSLog(@"release 后 %d",[testObj retainCount]); } 明明release了,retainCount计数应该为0,但是 为什么retainCount计数还是1,当我们release操作两次的时候程序就崩溃了; 然后我们打印一下testObj对象 [cpp] view plaincopy - (void)viewDidLoad { [super viewDidLoad]; Test *testObj = [[Test alloc] init]; NSLog(@"release 前 %d",[testObj retainCount]); NSLog(@"testObj release指向-->%@",testObj); [testObj release]; NSLog(@"release 后 %d",[testObj retainCount]); NSLog(@"testObj release指向-->%@",testObj); } 发现他们指向同一块地址; testObj 在alloc的时候在堆上申请到一片空间,然后它的retainCount计数为1,然后我们release之后,testObj指向的空间被销毁了,不 存在了。此时testObj就是一个野指针了;此时我们调用[testObj retainCount]就属于一个不安全的做法; 然后我们在添加一行代码,[testObj release]之后,添加 testObj = nil; [cpp] view plaincopy - (void)viewDidLoad { [super viewDidLoad]; Test *testObj = [[Test alloc] init]; NSLog(@"release 前 %d",[testObj retainCount]); NSLog(@"testObj release指向-->%@",testObj); [testObj release]; testObj = nil; NSLog(@"release 后 %d",[testObj retainCount]); NSLog(@"testObj release指向-->%@",testObj); } 唉,看到这里就应该明白了 吧,[testObj release] 后,testObj仍有指向,只是testObj原来指向的那片空间已被销毁,但是本身还存在,通过置为nil这一步操作,就不在指向原来那片地址;应该 记起viewDidUnload函数作用了吧,它就是干这个活的,我们申明一个对象属性的时候,在viewDidUnload中将这个属性置为nil这一 步操作; 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3471082.html,如需转载请自行联系原作者
我们在程序设计中,时时刻刻都用到变量的定义和变量的声明,可有些时候我们对这个概念不是很清楚,知道它是怎么用,但却不知是怎么一会事,下面我就简单的把他们的区别介绍如下:(望我的指点对你受益) 变量的声明有两种情况: 1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。 2、另一种是不需要建立存储空间的。 例如:extern int a 其中变量a是在别的文件中定义的。 前者是“定义性声明(defining declaration)”或者称为“定义(definition)”,而后者是“引用性声明(referncing declaration)”,从广义的角度来讲声明中包含着定义,即定义是声明的一个特例,所以并非所有的声明都是定义,例如:int a 它既是声明,同时又是定义。然而对于 extern a 来讲它只是声明不是定义。一般的情况下我们常常这样叙述,把建立空间的声明称之为“定义”,而把不需要建立存储空间的声明称之为“声明”。很明显我们在这 里指的声明是范围比较窄的,即狭义上的声明,也就是说非定义性质的声明,例如:在主函数中: int main() { extern int A; //这是个声明而不是定义,声明A是一个已经定义了的外部变量 //注意:声明外部变量时可以把变量类型去掉如:extern A; dosth(); //执行函数 } int A; //是定义,定义了A为整型的外部变量 外部变量的“定义”与外部变量的“声明”是不相同的,外部变量的定义只能有一次,它的位置是在所有函数之外,而同一个文件中的外部变量声明可以是多 次的,它可以在函数之内(哪个函数要用就在那个函数中声明)也可以在函数之外(在外部变量的定义点之前)。系统会根据外部变量的定义(而不是根据外部变量 的声明)分配存储空间的。对于外部变量来讲,初始化只能是在“定义”中进行,而不是在“声明”中。所谓的“声明”,其作用,是声明该变量是一个已在后面定 义过的外部变量,仅仅是为了“提前”引用该变量而作的“声明”而已。extern 只作声明,不作任何定义。 (我们声明的最终目的是为了提前使用,即在定义之前使用,如果不需要提前使用就没有单独声明的必要,变量是如此,函数也是如此,所以声明不会分配存储空间,只有定义时才会分配存储空间。) 用static来声明一个变量的作用有二: (1)对于局部变量用static声明,则是为该变量分配的空间在整个程序的执行期内都始终存在。 (2)外部变量用static来声明,则该变量的作用只限于本文件模块。 http://www.cnblogs.com/GavinDai/archive/2011/10/24/2222735.html 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3305827.html,如需转载请自行联系原作者
来源:http://www.cppblog.com/woaidongmao/archive/2010/07/01/119024.html C++中派生类对基类成员的访问形式主要有以下两种: 1、内部访问:由派生类中新增成员对基类继承来的成员的访问。 2、对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问。今天给大家介绍在3中继承方式下,派生类对基类成员的访问规则。 1、私有继承的访问规则 当类的继承方式为私有继承时,基类的public成员和protected成员被继承后成为派生类的private成员,派生类的其它成员可以直接访问它们,但是在类的外部通过派生类的对象无法访问。基类的private成员在私有派生类中是不可直接访问的,所以无论是派生类的成员还是通过派生类的对象,都无法直接访问从基类继承来的private成员,但是可以通过基类提供的public成员函数间接访问。私有继承的访问规则总结如下: 基类成员 private成员 public成员 protected成员 内部访问 不可访问 可访问 可访问 对象访问 不可访问 不可访问 不可访问 2、公有继承的访问规则 当类的继承方式为公有继承时,基类的public成员和protected成员被继承到派生类中仍作为派生类的public成员和protected成员,派生类的其它成员可以直接访问它们。但是,类的外部使用者只能通过派生类的对象访问继承来的public成员。基类的private成员在私有派生类中是不可直接访问的,所以无论是派生类成员还是派生类的对象,都无法直接访问从基类继承来的private成员,但是可以通过基类提供的public成员函数直接访问它们。公有继承的访问规则总结如下: 基类成员 private成员 public成员 protected成员 内部访问 不可访问 可访问 可访问 对象访问 不可访问 可访问 不可访问 3、保护继承的访问规则 当类的继承方式为保护继承时,基类的public成员和protected成员被继承到派生类中都作为派生类的protected成员,派生类的其它成员可以直接访问它们,但是类的外部使用者不能通过派生类的对象访问它们。基类的private成员在私有派生类中是不可直接访问的,所以无论是派生类成员还是通过派生类的对象,都无法直接访问基类中的private成员。保护继承的访问规则总结如下: 基类成员 private成员 public成员 protected成员 内部访问 不可访问 可访问 可访问 对象访问 不可访问 不可访问 不可访问 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/04/17/3026107.html,如需转载请自行联系原作者
已知ip地址为10.130.89.95,其子网掩码为255.255.255.224,求其网络号、子网号和主机号。 要看子网掩码变长在第几节,255.255.255.224是在第四节借了位 把224转换为2进制,windows的计算器科学型能帮你计算。是11100000,借了三位 借了三位,子网个数为2的三次方等于8 即八个子网 其实书上说得挺复杂,我感觉,计算网络号最简单的方法就是 256(这是个固定的数字)除以8(子网个数),等于32 那么,八个子网号就分别是 10.130.89.0 10.130.89.32 10.130.89.64 10.130.89.96 10.130.89.128 10.130.89.160 10.130.89.192 10.130.89.224 即从0开始每一跳加32,就得到了这个答案。 广播地址的算法就是除了10.130.89.0以外,其他的子网号减1,还有一个10.130.89.255 就是: 10.130.89.31 10.130.89.63 10.130.89.95 10.130.89.127 10.130.89.159 10.130.89.191 10.130.89.223 主机号就是除了网络号和广播地址之外的所有地址。 10.130.89.1~10.130.89.30 10.130.89.33 ~ 63 10.130.89.65 ~ 95 10.130.89.97 ~ 127 10.130.89.129 ~ 159 10.130.89.161 ~ 191 10.130.89.193 ~ 223 10.130.89.225 ~ 254 然后得到的答案就是10.130.89.95是一个广播地址 网络号是10.130.89.64 地址范围是10.130.89.65~94 根据掩码255.255.255.224,可知块大小为32那子网号应该是0,32,64,96.....显然该IP属于网络10.130.89.64并且是该网络的广播地址该网络主机范围是10.130.89.65---94 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3644508.html,如需转载请自行联系原作者
同步发布:http://www.yuanrengu.com/index.php/springmvc-user-initbinder.html 在使用SpingMVC框架的项目中,经常会遇到页面某些数据类型是Date、Integer、Double等的数据要绑定到控制器的实体,或者控制器需要接受这些数据,如果这类数据类型不做处理的话将无法绑定。 这里我们可以使用注解@InitBinder来解决这些问题,这样SpingMVC在绑定表单之前,都会先注册这些编辑器。一般会将这些方法些在BaseController中,需要进行这类转换的控制器只需继承BaseController即可。其实Spring提供了很多的实现类,如CustomDateEditor、CustomBooleanEditor、CustomNumberEditor等,基本上是够用的。 demo如下: public class BaseController { @InitBinder protected void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Date.class, new MyDateEditor()); binder.registerCustomEditor(Double.class, new DoubleEditor()); binder.registerCustomEditor(Integer.class, new IntegerEditor()); } private class MyDateEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = null; try { date = format.parse(text); } catch (ParseException e) { format = new SimpleDateFormat("yyyy-MM-dd"); try { date = format.parse(text); } catch (ParseException e1) { } } setValue(date); } } public class DoubleEditor extends PropertiesEditor { @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.equals("")) { text = "0"; } setValue(Double.parseDouble(text)); } @Override public String getAsText() { return getValue().toString(); } } public class IntegerEditor extends PropertiesEditor { @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.equals("")) { text = "0"; } setValue(Integer.parseInt(text)); } @Override public String getAsText() { return getValue().toString(); } } } 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/6186633.html,如需转载请自行联系原作者
1 #include<stdio.h> 2 #include<stdlib.h> 3 int sw(char *a){ 4 int i=0,c=0; 5 while(a[i]){ 6 if(a[i]>='0'&&a[i]<='9') 7 c=c*10+a[i]-'0'; 8 i++; 9 } 10 if(a[0]=='-') 11 c=-c; 12 return c; 13 } 14 int main(){ 15 char a[99],b[99]; 16 int a1,b1,c[99],i=0; 17 while(scanf("%s %s",a,b)!=EOF) 18 { 19 a1=sw(a); 20 b1=sw(b); 21 22 c[i]=a1+b1; 23 i++; 24 } 25 for(int j=0;j<i;j++) 26 printf("%d\n",c[j]); 27 return 0; 28 } 1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 using namespace std; 5 int main(){ 6 //freopen("a.txt","r",stdin); 7 char inA[20]={0}; 8 char inB[20]={0}; 9 while(cin>>inA>>inB) 10 { 11 string strA(inA); 12 string strB(inB); 13 strA.erase(remove(strA.begin(),strA.end(),','),strA.end()); 14 strB.erase(remove(strB.begin(),strB.end(),','),strB.end()); 15 int a = atoi(strA.c_str()); //c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同. 16 int b = atoi(strB.c_str()); //atoi()会将字符串转换为整型数 17 cout<<a+b<<endl; 18 } 19 // getchar(); 20 21 22 return 0; 23 } 关于如下两行代码的使用很让人疑惑: 接下来就举例子来说明一下: 1 #include <iostream> 2 3 #include <list> 4 5 #include <algorithm> 6 7 using namespace std; 8 9 int main() 10 11 { 12 13 list<int> coll; 14 15 //insert elements from 6 to 1 and 1 to 6 16 17 for (int i=1; i<=6; ++i) { 18 19 coll.push_front(i); 20 21 coll.push_back(i); 22 23 } 24 25 //print all elements of the collection 26 27 cout << "pre: "; 28 29 copy (coll.begin(), coll.end(), ostream_iterator<int> (cout," ")); 30 31 cout << endl; 32 33 //remove all elements with value 3 34 35 remove (coll.begin() , coll.end(), 3); 36 37 //print all elements of the collection 38 39 cout << "post: "; 40 41 copy (coll.begin(), coll.end(), ostream_iterator<int> (cout," ")); 42 43 cout << endl; 44 45 } 执行remove动作后,值为3的节点还在,只是里面的值被后续节点的值覆盖了,整个容器的长度没有改变。 向左转|向右转 这样调整一下,就达到目的了。 list<int>::iterator end = remove (coll.begin(), coll.end(), 3); coll.erase (end, coll.end()); c_str()的用法: 语法: const char *c_str(); c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同. 这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。 注意:一定要使用strcpy()函数 等来操作方法c_str()返回的指针 比如:最好不要这样: char* c; string s="1234"; c = s.c_str(); //c最后指向的内容是垃圾,因为s对象被析构,其内容被处理 应该这样用: char c[20]; string s="1234"; strcpy(c,s.c_str()); 这样才不会出错,c_str()返回的是一个临时指针,不能对其进行操作 再举个例子 c_str() 以 char* 形式传回 string 内含字符串 如果一个函数要求char*参数,可以使用c_str()方法: string s = "Hello World!"; printf("%s", s.c_str()); //输出 "Hello World!" atoi函数的使用: 原型:int atoi (const char *nptr) 用法:#include <stdlib.h> 功能:将字符串转换成整型数;atoi()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负号才开始做转换,而再遇到非数字或字符串时('\0')才结束转化,并将结果返回。 说明:atoi()函数返回转换后的整型数。 可参考:http://blog.csdn.net/youbang321/article/details/7888138 举例: #include <stdio.h> #include <stdlib.h> int main() { char a[] = "-100"; char b[] = "456"; int c = 0; c = atoi(a) + atoi(b); printf("c = %d\n",c); } 结果: 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3263568.html,如需转载请自行联系原作者
以前在方向的选择上,经常会听到BS架构的系统和CS架构的系统,于是我带着迷茫去了解了一下B/S架构和C/S架构,在这之后似乎一切清晰了很多,那么就请大家一起来分享一下这方面的知识吧! C/S结构,即Client/Server(客户机/服务器)结构,是大家熟知的软件系统体系结构,通过将任务合理分配到Client端和Server端,降低了系统的通讯开销,可以充分利用两端硬件环境的优势。早期的软件系统多以此作为首选设计标准。 B/S结构,即Browser/Server(浏览器/服务器)结构,是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。 在这种结构下,用户界面完全通过WWW浏览器实现,一部分事务逻辑在前端实现,但是主要事务逻辑在服务器端实现,形成所谓3-tier结构。 B/S结构,主要是利用了不断成熟的WWW浏览器技术,结合浏览器的多种scrīpt语言(VBscrīpt、Javascrīpt…)和ActiveX 技术,用通用浏览器就实现了原来需要复杂专用软件才能实现的强大功能,并节约了开发成本,是一种全新的软件系统构造技术。随着 98/Windows 2000将浏览器技术植入内部,这种结构更成为当今应用软件的首选体系结构。 C/S 与 B/S 区别: Client/Server是建立在局域网的基础上的.Browser/Server是建立在广域网的基础上的. 1.硬件环境不同: C/S 一般建立在专用的网络上, 小范围里的网络环境, 局域网之间再通过专门服务器提供连接和数据交换服务. B/S 建立在广域网之上的, 不必是专门的网络硬件环境,例如电话上网, 租用设备. 信息管理. 有比C/S更强的适应范围, 一般只要有操作系统和浏览器就行 2.对安全要求不同 C/S 一般面向相对固定的用户群, 对信息安全的控制能力很强. 一般高度机密的信息系统采用C/S 结构适宜. 可以通过B/S发布部分可公开信息. B/S 建立在广域网之上, 对安全的控制能力相对弱, 面向是不可知的用户群. 3.对程序架构不同 C/S 程序可以更加注重流程, 可以对权限多层次校验, 对系统运行速度可以较少考虑. B/S 对安全以及访问速度的多重的考虑, 建立在需要更加优化的基础之上. 比C/S有更高的要求 B/S结构的程序架构是发展的趋势, 从MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持网络的构件搭建的系统. SUN 和推的JavaBean 构件技术等,使 B/S更加成熟. 4.软件重用不同 C/S 程序可以不可避免的整体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好. B/S 对的多重结构,要求构件相对独立的功能. 能够相对较好的重用. 5.系统维护不同 系统维护在是软件生存周期中,开销大, -------重要 C/S 程序由于整体性, 必须整体考察, 处理出现的问题以及系统升级. 升级难. 可能是再做一个全新的系统 B/S 构件组成,方面构件个别的更换,实现系统的无缝升级. 系统维护开销减到最小.用户从网上自己下载安装就可以实现升级. 6.处理问题不同 C/S 程序可以处理用户面固定, 并且在相同区域, 安全要求高需求, 与操作系统相关. 应该都是相同的系统 B/S 建立在广域网上, 面向不同的用户群, 分散地域, 这是C/S无法作到的. 与操作系统平台关系最小. 7.用户接口不同 C/S 多是建立的Window平台上,表现方法有限,对程序员普遍要求较高 B/S 建立在浏览器上, 有更加丰富和生动的表现方式与用户交流. 并且大部分难度减低,减低开发成本. 8.信息流不同 C/S 程序一般是典型的中央集权的机械式处理, 交互性相对低 B/S 信息流向可变化, B-B B-C B-G等信息、流向的变化, 更象交易中心 来源:http://blog.csdn.net/fsqcy/article/details/6958004 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/05/01/3053323.html,如需转载请自行联系原作者
首先看一个例子: 1 #include <iostream> 2 using namespace std; 3 4 class A{}; 5 6 class B 7 { 8 int b; 9 char c; 10 }; 11 12 class C 13 { 14 int c1; 15 static int c2; 16 }; 17 int C::c2 = 1; 18 19 class D:public C,public B{ 20 int d; 21 }; 22 int main() 23 { 24 cout<<"sizeof(A)="<<sizeof(A)<<endl; 25 cout<<"sizeof(B)="<<sizeof(B)<<endl; 26 cout<<"sizeof(C)="<<sizeof(C)<<endl; 27 cout<<"sizeof(D)="<<sizeof(D)<<endl; 28 29 return 0; 30 } 运行结果为: sizeof(A)=1 sizeof(B)=8 sizeof(C)=4 sizeof(D)=16 对于类A来说,虽然A是一个空类,但为了便于空类进行实例化,编译器往往会给它分配一个字节,这样A实 例化后便在内存中有了一个独一无二的地址.对于类B,B的大小应为sizeof(int)+sizeof(char)=5,但是考虑内存对齐,B的大小应 为8.对于类C,类的静态成员变量被放在全局区,和类的普通成员并没有放在一块。类的静态成员被声明后就已存在,而非静态成员只有类被实例化后才存在。所 以C的大小为sizeof(int)=4。D的大小为B+C的大小+自身数据成员的大小,一共为16. ==========================分割线在这里==================================== 下面讨论含有虚函数的类的大小: 1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 void virtual aa(){}; 8 }; 9 10 class B:public A 11 { 12 void virtual bb(){}; 13 }; 14 15 class C:virtual A 16 { 17 public: 18 void virtual aa(){}; 19 void cc(){}; 20 }; 21 22 class D:virtual A 23 { 24 public: 25 void virtual dd(){}; 26 }; 27 28 int main() 29 { 30 cout<<"sizeof(A)="<<sizeof(A)<<endl; 31 cout<<"sizeof(B)="<<sizeof(B)<<endl; 32 cout<<"sizeof(C)="<<sizeof(C)<<endl; 33 cout<<"sizeof(D)="<<sizeof(D)<<endl; 34 35 return 0; 36 } 运行结果为: sizeof(A)=4 sizeof(B)=4 sizeof(C)=8 sizeof(D)=12 对于class A,它含有一个虚函数,编译器会为虚函数生成一张虚函数表,来记录对应的函数地址,为此,在class A的内存地址中要有一个vfptr_A指针指向这个虚表,所以class A的大小为指针大小,即4.(注意,无论类中有多少个虚函数,它们的大小都是4,因为内存中只需要保存这个指针即可)。 对于class B,它是public继承A,虽然它也有一个虚函数,但是从结果看,B应该和A都在B的vtable(虚表中),所以class B的大小为4. 对于class C,它是vitual 继承A,所以要有一个指向父类A的指针,占有4字节大小aa()是继承自class A的虚函数,从结果来看,它没有在内存中占有空间,所以C的大小为sizeof(A)+4=8. 对于class D,它是虚继承class A,同上,要有一个指向父类A的指针,同时,class D中有虚函数,所以要有一个指向虚表的指针,所以sizeof(D)=sizeof(A)+4+4=12 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/05/07/3064963.html,如需转载请自行联系原作者
以后慢慢启用个人博客:http://www.yuanrengu.com 在项目中碰到了正则表达式的运用,正则还是非常强大的,不管什么编程语言,基本上都可以用到。之前在用java时特别是对用户名或密码使用正则非常爽,写脚本上用正则也非常爽,可是到了OC这却把我虐了一把,可能是对OC掌握的不够。这里就罗列了从网上找的很有用的资料,感谢大神们的贡献。 首先举一个例子: 匹配9-15个由字母/数字组成的字符串的正则表达式: NSString * regex = @"^[A-Za-z0-9]{9,15}$"; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; BOOL isMatch = [pred evaluateWithObject:txtfldPhoneNumber.text]; 假如是在OC里用,一定要注意细节。 列出我在项目中用到的代码: NSString *regex = @"[a-zA-Z\u4e00-\u9fa5][a-zA-Z0-9\u4e00-\u9fa5]+"; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; if(![pred evaluateWithObject: nickNameTextField.text]) { /* ////此动画为弹出buttonqww UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:@"昵称只能由中文、字母或数字组成" delegate:self cancelButtonTitle:@"确定" otherButtonTitles: nil]; [alertView show]; return; */ Warning_boxes *reminderView = [[Warning_boxes alloc]init]; [self.view addSubview:reminderView]; reminderView.title_alter.text = @"昵称只能由中文、字母或数字组成"; [reminderView animationStart]; [reminderView release]; /* //此动画为在顶上显示文字 [MPNotificationView notifyWithText:@"昵称只能由中文、字母或数字组成" andDuration:0.5]; */ return; 下一行代码非常关键: if(![pred evaluateWithObject: nickNameTextField.text]) 这里有!一定要注意。因为nickNameTextField.text和pred匹配的时候返回的是YES。所以在判断他们匹配时的情况要加!。 要学好正则的小伙伴,强烈推荐:正则表达式30分钟入门教程 说明:正则表达式通常用于两种任务:1.验证,2.搜索/替换。用于验证时,通常需要在前后分别加上^和$,以匹配整个待验证字符串;搜索/替换时是否加上此限定则根据搜索的要求而定,此外,也有可能要在前后加上\b而不是^和$。此表所列的常用正则表达式,除个别外均未在前后加上任何限定,请根据需要,自行处理。 说明 正则表达式 网址(URL) [a-zA-z]+://[^\s]* IP地址(IP Address) ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?) 电子邮件(Email) \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* QQ号码 [1-9]\d{4,} HTML标记(包含内容或自闭合) <(.*)(.*)>.*<\/\1>|<(.*) \/> 密码(由数字/大写字母/小写字母/标点符号组成,四种都必有,8位以上) (?=^.{8,}$)(?=.*\d)(?=.*\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\n).*$ 日期(年-月-日) (\d{4}|\d{2})-((1[0-2])|(0?[1-9]))-(([12][0-9])|(3[01])|(0?[1-9])) 日期(月/日/年) ((1[0-2])|(0?[1-9]))/(([12][0-9])|(3[01])|(0?[1-9]))/(\d{4}|\d{2}) 时间(小时:分钟, 24小时制) ((1|0?)[0-9]|2[0-3]):([0-5][0-9]) 汉字(字符) [\u4e00-\u9fa5] 中文及全角标点符号(字符) [\u3000-\u301e\ufe10-\ufe19\ufe30-\ufe44\ufe50-\ufe6b\uff01-\uffee] 中国大陆固定电话号码 (\d{4}-|\d{3}-)?(\d{8}|\d{7}) 中国大陆手机号码 1\d{10} 中国大陆邮政编码 [1-9]\d{5} 中国大陆身份证号(15位或18位) \d{15}(\d\d[0-9xX])? 非负整数(正整数或零) \d+ 正整数 [0-9]*[1-9][0-9]* 负整数 -[0-9]*[1-9][0-9]* 整数 -?\d+ 小数 (-?\d+)(\.\d+)? 不包含abc的单词 \b((?!abc)\w)+\b 正则表达式:是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串,简单说,就是我们写个模板,然后去匹配字符串。 下面我们来看看一些基本的正则表达式的语法: \:将下个字符标记为一个特殊的字符、一个原义字符、一个向后引用或者一个八进制转义符例如“\n”就是匹配一个换行符。 ^:匹配开始位置,^(a)这个就匹配开头必须为a。 $:匹配结束位置,$(a)这个就匹配结尾必须为a。 *:匹配前面的子表达式零次或者多次,如“xu*”这个表达式就能够匹配“x”和“xuu”。 +:匹配前面的子表达式一次或者多次,如“xu+”这个表达式就能够匹配“xuu”和“xu”,但不能够匹配“x”,这个就是和“*”的区别。 ?:匹配前面的子表达式零次或者一次,如“xu?”这个表达式就能够匹配“jian(guo)?”就可以匹配“jian”和“jianguo”。 {n}:n是一个非负数,匹配n次,如“guo{2}”,可以匹配“guoo”,不能匹配“guo”。 {n,}:n是一个非负数,匹配至少n次。 {n, m}:m、n都是非负数,最少匹配n次,最多匹配m次。 (pattern):匹配pattern并获取匹配结果。 (?:pattern):匹配pattern但不获取匹配结果。 x|y:匹配x或y,如“(xu|jian)guo”匹配“xuguo”或者“jianguo”。 [xyz]:字符集合,匹配所包含的任意字符。如“[abc]”可以匹配“apple”中的“a”。 [^xyz]:匹配未被包含的字符。 [a-z]:字符范围,匹配指定范围内的任意字符。 [^a-z]:匹配指定不在范围内的任意字符。 \b:匹配一个单词的边界,如“guo\b”可以匹配“xujianguo”中的“guo”。 \B:匹配非单词边界,如“jian\B”可以匹配“xujianguo”中的“jian”。 \d:匹配一个数字字符,等价于“[0-9]”。 \D:匹配一个非数字字符。 \f:匹配一个换页符。 \n:匹配一个换行符。 \r:匹配一个回车符。 \s:匹配任何空白字符 其实还有很多语法我就不一一列举了,先说这么多先 一.NSString自带的正则查找,替换方法 正则查找方法– rangeOfString:options:– rangeOfString:options:range:– rangeOfString:options:range:locale: 正则替换方法– stringByReplacingOccurrencesOfString:withString:options:range: options参数指定搜索选项,类型为NSStringCompareOptions,可通过位或操作指定为NSCaseInsensitiveSearch, NSLiteralSearch, NSBackwardsSearch, NSAnchoredSearch>等选项的组合。 若指定的选项为NSRegularExpressionSearch,则搜索字符串被认为是ICU兼容的正则表达式,如果指定了此选项,则与其可以同时存在的选项只有NSCaseInsensitiveSearch和NSAnchoredSearch 二.使用RegexKitLite RegexKitLite向标准NSString类增加了很多方法来使用正则表达式,RegexKitLite使用iOS系统自带的ICU(International Components for Unicode)正则引擎处理正则表达式,所以RegexKitLite使用的正则语法为ICU的语法,使用RegexKitLite需要导入libicucore.dylib库。 使用RegexKitLite的方法很简单,将RegexKitLite.h和RegexKitLite.m加入到工程,然后引入libicucore.dylib库即可。RegexKitLite.h RegexKitLite.m RegexKitLit NSString方法参考RegexKitLite NSString Additions Reference RegexKitLite的使用说明见:Using RegexKitLite ICU正则语法为:ICU SyntaxICU User Guide – Regular Expressions 三.使用RegexKit.framework框架 RegexKit Framework与RegexKitLite来自同一体系,但其更复杂和强大。RegexKit Framework不使用iOS系统的ICU正则库,而是自带 PCRE(Perl Compatible Regular Expressions)库, 所以其正则语法是PCRE的语法。 RegexKit Framework功能很强大,其向NSArray,NSData,NSDictionary,NSSet和NSString对象增加了正则表达式的支持。 TRegexKit.framework与RegexKitLite的区别 RegexKit.framework RegexKitLite Regex Library PCRE ICU Library Included Yes, built into framework object file. No, provided by Mac OS X. Library Linked As Statically linked into framework. Dynamically linked to/usr/lib/libicucore.dylib. Compiled Size Approximately 371KB† per architecture. Very small, approximately 16KB—20KB‡ per architecture. Style External, linked to framework. Compiled directly in to final executable. Feature Set Large, with additions to many classes. Minimal, NSString only. 四.常用ICU正则匹配模式 常用的ICU正则匹配模式见:RegexKitLite Cookbook 数字 Numbers Description Regex Examples Integer [+\-]?[0-9]+ 123-42+23 Hex Number 0[xX][0-9a-fA-F]+ 0×00xdeadbeef0xF3 Floating Point [+\-]?(?:[0-9]*\.[0-9]+|[0-9]+\.) 123..123+.42 Floating Point with Exponent [+\-]?(?:[0-9]*\.[0-9]+|[0-9]+\.)(?:[eE][+\-]?[0-9]+)? 123..12310.0E131.23e-7 Comma Separated Number [0-9]{1,3}(?:,[0-9]{3})* 421,2341,234,567 Comma Separated Number [0-9]{1,3}(?:,[0-9]{3})*(?:\.[0-9]+)? 421,2341,234,567.89 文本文件 Text Files Description Regex Empty Line (?m:^$) Empty or Whitespace Only Line (?m-s:^\s*$) Strip Leading Whitespace (?m-s:^\s*(.*?)$) Strip Trailing Whitespace (?m-s:^(.*?)\s*$) Strip Leading and Trailing Whitespace (?m-s:^\s*(.*?)\s*$) Quoted String, Can Span Multiple Lines, May Contain \" "(?:[^"\\]*+|\\.)*" Quoted String, Single Line Only, May Contain \" "(?:[^"\\\r\n]*+|\\[^\r\n])*" HTML Comment (?s:<--.*?-->) Perl / Shell Comment (?m-s:#.*$) C, C++, or ObjC Comment (?m-s://.*$) C, C++, or ObjC Comment and Leading Whitespace (?m-s:\s*//.*$) C, C++, or ObjC Comment (?s:/\*.*?\*/) 网络与URL相关 Network and URL Description Regex HTTP \bhttps?://[a-zA-Z0-9\-.]+(?:(?:/[a-zA-Z0-9\-._?,'+\&%$=~*!():@\\]*)+)? HTTP \b(https?)://([a-zA-Z0-9\-.]+)((?:/[a-zA-Z0-9\-._?,'+\&%$=~*!():@\\]*)+)? HTTP \b(https?)://(?:(\S+?)(?::(\S+?))?@)?([a-zA-Z0-9\-.]+)(?::(\d+))?((?:/[a-zA-Z0-9\-._?,'+\&%$=~*!():@\\]*)+)? E-Mail \b([a-zA-Z0-9%_.+\-]+)@([a-zA-Z0-9.\-]+?\.[a-zA-Z]{2,6})\b Hostname \b(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}?[a-zA-Z0-9]\.)+[a-zA-Z]{2,6}\b IP \b(?:\d{1,3}\.){3}\d{1,3}\b IP with Optional Netmask \b((?:\d{1,3}\.){3}\d{1,3})(?:/(\d{1,2}))?\b IP or Hostname \b(?:(?:\d{1,3}\.){3}\d{1,3}|(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}?[a-zA-Z0-9]\.)+[a-zA-Z]{2,6})\b 五.贪婪匹配与最小匹配 在正则表达式中单独使用*或+时,默认是匹配尽可能多的数据,即贪婪匹配。 * Match zero or more times. Match as many times as possible. + Match one or more times. Match as many times as possible. 比如对 abcdefgabcdefg 使用abc(.*)g进行匹配,则捕获到到的数据为 defgabcdef。 若只想捕获到第一个g,即只想得到def,则需要使用最小匹配,在*或+后面加上?,即使用abc(.*?)g进行匹配。 *? Match zero or more times. Match as few times as possible. +? Match one or more times. Match as few times as possible. 另外,在正则中用(…)包含内容是要捕获的数据,如果只要用(…)来引用group而不想捕获则可使用(?:…)。 (…) Capturing parentheses. Range of input that matched the parenthesized subexpression is available after the match. (?:…) Non-capturing parentheses. Groups the included pattern, but does not provide capturing of matching text. Somewhat more efficient than capturing parentheses. 六.正则表达式书写格式 在书写正则表达式时,需要将\进行转义,即写成两个\\。 例如 匹配IP地址的正则表达式为 \b(?:\d{1,3}\.){3}\d{1,3}\b,则在实际书写时则为 NSString *regex = @"\\b(?:\\d{1,3}\.){3}\\d{1,3}\\b"; 参考:iOS 开发中使用正则表达式-暨 RegexKitLite 库的用法RegexKitLite Documentation[perl]理解贪婪匹配和最小匹配之间的区别NSString Class ReferenceICU – International Components for Unicode 来源:http://blog.csdn.net/zeng11088/article/details/8766121 常用的第三方正则库: http://regexkit.sourceforge.net/RegexKitLite/index.html 匹配中文字符的正则表达式: [\u4e00-\u9fa5] 评注:匹配中文还真是个头疼的事,有了这个表达式就好办了 匹配双字节字符(包括汉字在内):[^\x00-\xff] 评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1) 匹配空白行的正则表达式:\n\s*\r 评注:可以用来删除空白行 匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> 评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力 匹配首尾空白字符的正则表达式:^\s*|\s*$ 评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式 匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* 评注:表单验证时很实用 匹配网址URL的正则表达式:[a-zA-z]+://[^\s]* 评注:网上流传的版本功能很有限,上面这个基本可以满足需求 匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 评注:表单验证时很实用 匹配国内电话号码:\d{3}-\d{8}|\d{4}-\d{7} 评注:匹配形式如 0511-4405222 或 021-87888822 匹配腾讯QQ号:[1-9][0-9]{4,} 评注:腾讯QQ号从10000开始 匹配中国邮政编码:[1-9]\d{5}(?!\d) 评注:中国邮政编码为6位数字 匹配身份证:\d{15}|\d{18} 评注:中国的身份证为15位或18位 匹配ip地址:\d+\.\d+\.\d+\.\d+ 评注:提取ip地址时有用 匹配特定数字: ^[1-9]\d*$ //匹配正整数 ^-[1-9]\d*$ //匹配负整数 ^-?[1-9]\d*$ //匹配整数 ^[1-9]\d*|0$ //匹配非负整数(正整数 + 0) ^-[1-9]\d*|0$ //匹配非正整数(负整数 + 0) ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ //匹配正浮点数 ^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ //匹配负浮点数 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ //匹配浮点数 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ //匹配非负浮点数(正浮点数 + 0) ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ //匹配非正浮点数(负浮点数 + 0) 评注:处理大量数据时有用,具体应用时注意修正 匹配特定字符串: ^[A-Za-z]+$ //匹配由26个英文字母组成的字符串 ^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串 ^[a-z]+$ //匹配由26个英文字母的小写组成的字符串 ^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串 ^\w+$ //匹配由数字、26个英文字母或者下划线组成的字符串 来源:http://www.cnblogs.com/xujh/archive/2008/08/21/1273525.html <input onkeypress="return /[\w\u4e00-\u9fa5]/.test(String.fromCharCode(window.event.keyCode))" onpaste="return !/[^\w\u4e00-\u9fa5]/g.test(window.clipboardData.getData('Text'))" ondragenter="return false"/> 再粘贴一些别人写的。 1.只能输入数字和英文的: <input onkeyup="value=value.replace(/[\W]/g,'') " onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))" ID="Text1" NAME="Text1"> 2.只能输入数字的: <input onkeyup="value=value.replace(/[^\d]/g,'') " onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))" ID="Text2" NAME="Text2"> 3.只能输入全角的: <input onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))" ID="Text3" NAME="Text3"> 4.只能输入汉字的: <input onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))" ID="Text4" NAME="Text4"> 5.邮件地址验证: var regu = "^(([0-9a-zA-Z]+)|([0-9a-zA-Z]+[_.0-9a-zA-Z-]*[0-9a-zA-Z]+))@([a-zA-Z0-9-]+[.])+([a-zA-Z]{2}|net|NET|com|COM|gov|GOV|mil|MIL|org|ORG|edu|EDU|int|INT)$" var re = new RegExp(regu); if (s.search(re) != -1) { return true; } else { window.alert ("请输入有效合法的E-mail地址 !") return false; } 6.身份证: "^\\d{17}(\\d|x)$" 7.17种正则表达式 "^\\d+$" //非负整数(正整数 + 0) "^[0-9]*[1-9][0-9]*$" //正整数 "^((-\\d+)|(0+))$" //非正整数(负整数 + 0) "^-[0-9]*[1-9][0-9]*$" //负整数 "^-?\\d+$" //整数 "^\\d+(\\.\\d+)?$" //非负浮点数(正浮点数 + 0) "^(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*))$" //正浮点数 "^((-\\d+(\\.\\d+)?)|(0+(\\.0+)?))$" //非正浮点数(负浮点数 + 0) "^(-(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*)))$" //负浮点数 "^(-?\\d+)(\\.\\d+)?$" //浮点数 "^[A-Za-z]+$" //由26个英文字母组成的字符串 "^[A-Z]+$" //由26个英文字母的大写组成的字符串 "^[a-z]+$" //由26个英文字母的小写组成的字符串 "^[A-Za-z0-9]+$" //由数字和26个英文字母组成的字符串 "^\\w+$" //由数字、26个英文字母或者下划线组成的字符串 "^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$" //email地址 "^[a-zA-z]+://(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*(\\?\\S*)?$" //url ============================================= 1.取消按钮按下时的虚线框 在input里添加属性值 hideFocus 或者 HideFocus=true 2.只读文本框内容 在input里添加属性值 readonly 3.防止退后清空的TEXT文档(可把style内容做做为类引用) <INPUT style=behavior:url(#default#savehistory); type=text id=oPersistInput> 4.ENTER键可以让光标移到下一个输入框 <input onkeydown="if(event.keyCode==13)event.keyCode=9" > 5.只能为中文(有闪动) <input onkeyup="value="/value.replace(/[" -~]/g,’’)" onkeydown="if(event.keyCode==13)event.keyCode=9"> 6.只能为数字(有闪动) <input onkeyup="value="/value.replace(/["^\d] /g,’’) "onbeforepaste="clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^\d]/g,’’))"> 7.只能为数字(无闪动) <input ime- mode:disabled" onkeydown="if(event.keyCode==13)event.keyCode=9" onKeyPress="if ((event.keyCode<48 || event.keyCode>57)) event.returnValue=false"> 8.只能输入英文和数字(有闪动) <input onkeyup="value="/value.replace(/[\W] /g,"’’)" onbeforepaste="clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^\d]/g,’’))"> 9.屏蔽输入法 <input type="text" name="url" ime-mode:disabled" onkeydown="if(event.keyCode==13)event.keyCode=9"> 10. 只能输入 数字,小数点,减号(-) 字符(无闪动) <input onKeyPress="if (event.keyCode!=46 && amp; event.keyCode!=45 && (event.keyCode<48 || event.keyCode>57)) event.returnValue=false"> 11. 只能输入两位小数,三位小数(有闪动) <input maxlength=9 onkeyup="if(value.match(/^\d{3}$/))value=" /value.replace(value,parseInt(value/10))" ;value="/value.replace(/\.\d*\./g,’."’)" onKeyPress="if((event.keyCode<48 || event.keyCode>57) && event.keyCode!=46 && event.keyCode!=45 || value.match(/^\d{3}$/) || /\.\d{3}$/.test(value)) {event.returnValue=false}" id=text_kfxe name=text_kfxe> javascript正则表达式使用详解 简介 简单的说,正则表达式是一种可以用于模式匹配和替换的强有力的工具。其作用如下: 测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证。 替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字。 根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字。 基本语法 在对正则表达式的功能和作用有了初步的了解之后,我们就来具体看一下正则表达式的语法格式。 正则表达式的形式一般如下: /love/ 其中位于“/”定界符之间的部分就是将要在目标对象中进行匹配的模式。用户只要把希望查找匹配对象的模式内容放入“/”定界符之间 即可。为了能够使用户更加灵活的定制模式内容,正则表达式提供了专门的“元字符”。所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符,可以用来 规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。 较为常用的元字符包括: “+”, “*”,以及 “?”。 “+”元字符规定其前导字符必须在目标对象中连续出现一次或多次。 “*”元字符规定其前导字符必须在目标对象中出现零次或连续多次。 “?”元字符规定其前导对象必须在目标对象中连续出现零次或一次。 下面,就让我们来看一下正则表达式元字符的具体应用。 /fo+/ 因为上述正则表达式中包含“+”元字符,表示可以与目标对象中的 “fool”, “fo”, 或者 “football”等在字母f后面连续出现一个或多个字母o的字符串相匹配。 /eg*/ 因为上述正则表达式中包含“*”元字符,表示可以与目标对象中的 “easy”, “ego”, 或者 “egg”等在字母e后面连续出现零个或多个字母g的字符串相匹配。 /Wil?/ 因为上述正则表达式中包含“?”元字符,表示可以与目标对象中的 “Win”, 或者“Wilson”,等在字母i后面连续出现零个或一个字母l的字符串相匹配。 有时候不知道要匹配多少字符。为了能适应这种不确定性,正则表达式支持限定符的概念。这些限定符可以指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。 {n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 {n,} n 是一个非负整数。至少匹配 n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 {n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 除了元字符之外,用户还可以精确指定模式在匹配对象中出现的频率。例如,/jim {2,6}/ 上述正则表达式规定字符m可以在匹配对象中连续出现2-6次,因此,上述正则表达式可以同jimmy或jimmmmmy等字符串相匹配。 在对如何使用正则表达式有了初步了解之后,我们来看一下其它几个重要的元字符的使用方式。 代码 \s:用于匹配单个空格符,包括tab键和换行符; \S:用于匹配除单个空格符之外的所有字符; \d:用于匹配从0到9的数字; \w:用于匹配字母,数字或下划线字符; \W:用于匹配所有与\w不匹配的字符; . :用于匹配除换行符之外的所有字符。 (说明:我们可以把\s和\S以及\w和\W看作互为逆运算) 下面,我们就通过实例看一下如何在正则表达式中使用上述元字符。 /\s+/ 上述正则表达式可以用于匹配目标对象中的一个或多个空格字符。 /\d000/ 如果我们手中有一份复杂的财务报表,那么我们可以通过上述正则表达式轻而易举的查找到所有总额达千元的款项。 除了我们以上所介绍的元字符之外,正则表达式中还具有另外一种较为独特的专用字符,即定位符。定位符用于规定匹配模式在目标对象中的出现位置。 较为常用的定位符包括: “^”, “$”, “\b” 以及 “\B”。 代码 “^”定位符规定匹配模式必须出现在目标字符串的开头 “$”定位符规定匹配模式必须出现在目标对象的结尾 “\b”定位符规定匹配模式必须出现在目标字符串的开头或结尾的两个边界之一 “\B”定位符则规定匹配对象必须位于目标字符串的开头和结尾两个边界之内, 即匹配对象既不能作为目标字符串的开头,也不能作为目标字符串的结尾。 同样,我们也可以把“^”和“$”以及“\b”和“\B”看作是互为逆运算的两组定位符。举例来说: /^hell/ 因为上述正则表达式中包含“^”定位符,所以可以与目标对象中以 “hell”, “hello”或“hellhound”开头的字符串相匹配。 /ar$/ 因为上述正则表达式中包含“$”定位符,所以可以与目标对象中以 “car”, “bar”或 “ar” 结尾的字符串相匹配。 /\bbom/ 因为上述正则表达式模式以“\b”定位符开头,所以可以与目标对象中以 “bomb”, 或 “bom”开头的字符串相匹配。/man\b/ 因为上述正则表达式模式以“\b”定位符结尾,所以可以与目标对象中以 “human”, “woman”或 “man”结尾的字符串相匹配。 为了能够方便用户更加灵活的设定匹配模式,正则表达式允许使用者在匹配模式中指定某一个范围而不局限于具体的字符。例如: 代码 /[A-Z]/ 上述正则表达式将会与从A到Z范围内任何一个大写字母相匹配。 /[a-z]/ 上述正则表达式将会与从a到z范围内任何一个小写字母相匹配。 /[0-9]/ 上述正则表达式将会与从0到9范围内任何一个数字相匹配。 /([a-z][A-Z][0-9])+/ 上述正则表达式将会与任何由字母和数字组成的字符串,如 “aB0” 等相匹配。 这里需要提醒用户注意的一点就是可以在正则表达式中使用 “()” 把字符串组合在一起。“()”符号包含的内容必须同时出现在目标对象中。因此,上述正则表达式将无法与诸如 “abc”等的字符串匹配,因为“abc”中的最后一个字符为字母而非数字。 如果我们希望在正则表达式中实现类似编程逻辑中的“或”运算,在多个不同的模式中任选一个进行匹配的话,可以使用管道符 “|”。例如:/to|too|2/ 上述正则表达式将会与目标对象中的 “to”, “too”, 或 “2” 相匹配。 正则表达式中还有一个较为常用的运算符,即否定符 “[^]”。与我们前文所介绍的定位符 “^” 不同,否定符 “[^]”规定目标对象中不能存在模式中所规定的字符串。例如:/[^A-C]/ 上述字符串将会与目标对象中除A,B,和C之外的任何字符相匹配。一般 来说,当“^”出现在 “[]”内时就被视做否定运算符;而当“^”位于“[]”之外,或没有“[]”时,则应当被视做定位符。 最后,当用户需要在正则表达式的模式中加入元字符,并查找其匹配对象时,可以使用转义符“\”。例如:/Th\*/ 上述正则表达式将会与目标对象中的“Th*”而非“The”等相匹配。 在构造正则表达式之后,就可以象数学表达式一样来求值,也就是说,可以从左至右并按照一个优先级顺序来求值。优先级如下: 代码 1.\ 转义符 2.(), (?:), (?=), [] 圆括号和方括号 3.*, +, ?, {n}, {n,}, {n,m} 限定符 4.^, $, \anymetacharacter 位置和顺序 5.|“或”操作 使用实例 在JavaScript 1.2中带有一个功能强大的RegExp()对象,可以用来进行正则表达式的匹配操作。其中的test()方法可以检验目标对象中是否包含匹配模式,并相应的返回true或false。 我们可以使用JavaScript编写以下脚本,验证用户输入的邮件地址的有效性。 代码 <html> <head> <script language="Javascript1.2"> <!-- start hiding function verifyAddress(obj) { var email = obj.email.value; var pattern = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/; flag = pattern.test(email); if(flag) { alert(“Your email address is correct!”); return true; } else { alert(“Please try again!”); return false; } } // stop hiding --> </script> </head> <body> <form onSubmit="return verifyAddress(this);"> <input name="email" type="text"> <input type="submit"> </form> </body> </html> 正则表达式对象 本对象包含正则表达式模式以及表明如何应用模式的标志。 代码 语法 1 re = /pattern/[flags] 语法 2 re = new RegExp("pattern",["flags"]) 参数 re 必选项。将要赋值为正则表达式模式的变量名。 Pattern 必选项。要使用的正则表达式模式。如果使用语法 1,用 "/" 字符分隔模式。如果用语法 2,用引号将模式引起来。 Flags 可选项。如果使用语法 2 要用引号将 flag 引起来。标志可以组合使用,可用的有: 代码 g (全文查找出现的所有 pattern) i (忽略大小写) m (多行查找) 示例 下面的示例创建一个包含正则表达式模式及相关标志的对象(re),向您演示正则表达式对象的用法。在本例中,作为结果的正则表达式对象又用于 match 方法中: 代码 function MatchDemo() { var r, re; // 声明变量。 var s = "The rain in Spain falls mainly in the plain"; re = new RegExp("ain","g"); // 创建正则表达式对象。 r = s.match(re); // 在字符串 s 中查找匹配。 return(r); } 返回值: ain,ain,ain,ain\\ 属性 lastIndex 属性 | source 属性\\ 方法 compile 方法 | exec 方法 | test 方法\\ 要求 版本 3\\ 请参阅 RegExp 对象 | 正则表达式语法 | String 对象\\ exec 方法 用正则表达式模式在字符串中运行查找,并返回包含该查找结果的一个数组。 rgExp.exec(str) 参数 rgExp 必选项。包含正则表达式模式和可用标志的正则表达式对象。 str 必选项。要在其中执行查找的 String 对象或字符串文字。 说明\\ 如果 exec 方法没有找到匹配,则它返回 null。如果它找到匹配,则 exec 方法返回一个数组,并且更新全局 RegExp 对象的属性,以反映匹配结果。数组的0元素包含了完整的匹配,而第1到n元素中包含的是匹配中出现的任意一个子匹配。这相当于没有设置全局标志 (g) 的 match 方法。 如果为正则表达式设置了全局标志,exec 从以 lastIndex 的值指示的位置开始查找。如果没有设置全局标志,exec 忽略 lastIndex 的值,从字符串的起始位置开始搜索。 exec 方法返回的数组有三个属性,分别是 input、index 和 lastIndex。Input 属性包含了整个被查找的字符串。Index 属性中包含了整个被查找字符串中被匹配的子字符串的位置。LastIndex 属性中包含了匹配中最后一个字符的下一个位置。 示例\\ 下面的例子举例说明了 exec 方法的用法: 代码 function RegExpTest() { var ver = Number(ScriptEngineMajorVersion() + "." + ScriptEngineMinorVersion()) if (ver >= 5.5){ // 测试 JScript 的版本。 var src = "The rain in Spain falls mainly in the plain."; var re = /\w+/g; // 创建正则表达式模式。 var arr; while ((arr = re.exec(src)) != null) document.write(arr.index + "-" + arr.lastIndex + arr + "\t"); } else{ alert("请使用 JScript 的更新版本"); } } 返回值:0-3The 4-8rain 9-11in 12-17Spain 18-23falls 24-30mainly 31-33in 34-37the 38-43plain test 方法\\ 返回一个 Boolean 值,它指出在被查找的字符串中是否存在模式。 rgexp.test(str) 参数\\ rgexp 必选项。包含正则表达式模式或可用标志的正则表达式对象。 str 必选项。要在其上测试查找的字符串。 说明 test 方法检查在字符串中是否存在一个模式,如果存在则返回 true,否则就返回 false。 全局 RegExp 对象的属性不由 test 方法来修改。 示例 下面的例子举例说明了 test 方法的用法: 代码 function TestDemo(re, s) { var s1; // 声明变量。 // 检查字符串是否存在正则表达式。 if (re.test(s)) // 测试是否存在。 s1 = " contains "; // s 包含模式。 else s1 = " does not contain "; // s 不包含模式。 return("'" + s + "'" + s1 + "'"+ re.source + "'"); // 返回字符串。 } 函数调用:document.write (TestDemo(/ain+/ ,"The rain in Spain falls mainly in the plain.")); 返回值:'The rain in Spain falls mainly in the plain.' contains 'ain+' match 方法 使用正则表达式模式对字符串执行查找,并将包含查找的结果作为数组返回。\\ stringObj.match(rgExp) 参数\\ stringObj 必选项。对其进行查找的 String 对象或字符串文字。 rgExp 必选项。为包含正则表达式模式和可用标志的正则表达式对象。也可以是包含正则表达式模式和可用标志的变量名或字符串文字。 说明\\ 如果 match 方法没有找到匹配,返回 null。如果找到匹配返回一个数组并且更新全局 RegExp 对象的属性以反映匹配结果。 match 方法返回的数组有三个属性:input、index 和 lastIndex。Input 属性包含整个的被查找字符串。Index 属性包含了在整个被查找字符串中匹配的子字符串的位置。LastIndex 属性包含了最后一次匹配中最后一个字符的下一个位置。 如果没有设置全局标志 (g),数组的 0 元素包含整个匹配,而第 1 到 n 元素包含了匹配中曾出现过的任一个子匹配。这相当于没有设置全局标志的 exec 方法。如果设置了全局标志,元素 0 到 n 中包含所有匹配。 示例\\ 下面的示例演示了match 方法的用法: 代码 function MatchDemo() { var r, re; // 声明变量。 var s = "The rain in Spain falls mainly in the plain"; re = /ain/i; // 创建正则表达式模式。 r = s.match(re); // 尝试匹配搜索字符串。 return(r); // 返回第一次出现 "ain" 的地方。 } 返回值:ain 本示例说明带 g 标志设置的 match 方法的用法。 代码 function MatchDemo() { var r, re; // 声明变量。 var s = "The rain in Spain falls mainly in the plain"; re = /ain/ig; // 创建正则表达式模式。 r = s.match(re); // 尝试去匹配搜索字符串。 return(r); // 返回的数组包含了所有 "ain" // 出现的四个匹配。 } 返回值:ain,ain,ain,ain 上面几行代码演示了字符串文字的 match 方法的用法。 代码 var r, re = "Spain"; r = "The rain in Spain".replace(re, "Canada"); return r; 返回值:The rain in Canada search 方法 返回与正则表达式查找内容匹配的第一个子字符串的位置。 stringObj.search(rgExp) 参数\\ stringObj 必选项。要在其上进行查找的 String 对象或字符串文字。 rgExp 必选项。包含正则表达式模式和可用标志的正则表达式对象。 说明 search 方法指明是否存在相应的匹配。如果找到一个匹配,search 方法将返回一个整数值,指明这个匹配距离字符串开始的偏移位置。如果没有找到匹配,则返回 -1。 示例\\ 下面的示例演示了 search 方法的用法。 代码 function SearchDemo() { var r, re; // 声明变量。 var s = "The rain in Spain falls mainly in the plain."; re = /falls/i; // 创建正则表达式模式。 r = s.search(re); // 查找字符串。 return(r); // 返回 Boolean 结果。 } 返回值:18 正则表达式语法 一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。 这里有一些可能会遇到的正则表达式示例: 代码 JScript VBScript 匹配 /^\[ \t]*$/ "^\[ \t]*$" 匹配一个空白行。 /\d{2}-\d{5}/ "\d{2}-\d{5}" 验证一个ID 号码是否由一个2位数字,一个连字符以及一个5位数字组成。 /<(.*)>.*<\/\1>/ "<(.*)>.*<\/\1>" 匹配一个 HTML 标记。 下表是元字符及其在正则表达式上下文中的行为的一个完整列表: 字符 描述 \ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 后向引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。 ^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。 $ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。 * 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。 + 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。 ? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。 {n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 {n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 {n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 ? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。 . 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 (pattern) 匹配pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。 (?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。 (?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 (?!pattern) 负向预查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。 [xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。 [^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。 [a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。 [^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。 \b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 \B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 \cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 \d 匹配一个数字字符。等价于 [0-9]。 \D 匹配一个非数字字符。等价于 [^0-9]。 \f 匹配一个换页符。等价于 \x0c 和 \cL。 \n 匹配一个换行符。等价于 \x0a 和 \cJ。 \r 匹配一个回车符。等价于 \x0d 和 \cM。 \s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 \S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 \t 匹配一个制表符。等价于 \x09 和 \cI。 \v 匹配一个垂直制表符。等价于 \x0b 和 \cK。 \w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 \W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 \xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如, '\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。. \num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。 \n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 \nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 \nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 \un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。 优先权顺序 在构造正则表达式之后,就可以象数学表达式一样来求值,也就是说,可以从左至右并按照一个优先权顺序来求值。 下表从最高优先级到最低优先级列出各种正则表达式操作符的优先权顺序: 代码 操作符 描述 \ 转义符 (), (?:), (?=), [] 圆括号和方括号 *, +, ?, {n}, {n,}, {n,m} 限定符 ^, $, \anymetacharacter 位置和顺序 | “或”操作 普通字符 普通字符由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符,所有数字,所有标点符号以及一些符号。 最简单的正则表达式是一个单独的普通字符,可以匹配所搜索字符串中的该字符本身。例如,单字符模式 'A' 可以匹配所搜索字符串中任何位置出现的字母 'A'。这里有一些单字符正则表达式模式的示例: 代码 /a/ /7/ /M/ 等价的 VBScript 单字符正则表达式为: 代码 "a" "7" "M" 可以将多个单字符组合在一起得到一个较大的表达式。例如,下面的 JScript 正则表达式不是别的,就是通过组合单字符表达式 'a'、'7'以及 'M' 所创建出来的一个表达式。 /a7M/ 等价的 VBScript 表达式为: "a7M" 请注意这里没有连接操作符。所需要做的就是将一个字符放在了另一个字符后面 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3476885.html,如需转载请自行联系原作者
题目:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。 这就是有名的八皇后问题。解决这个问题通常需要用递归,而递归对编程能力的要求比较高。因此有不少面试官青睐这个题目,用来考察应聘者的分析复杂问题的能力以及编程的能力。 由于八个皇后的任意两个不能处在同一行,那么这肯定是每一个皇后占据一行。于是我们可以定义一个数组ColumnIndex[8],数组中第i个数字表示位于第i行的皇后的列号。先把ColumnIndex的八个数字分别用0-7初始化,接下来我们要做的事情就是对数组ColumnIndex做全排列。由于我们是用不同的数字初始化数组中的数字,因此任意两个皇后肯定不同列。我们只需要判断得到的每一个排列对应的八个皇后是不是在同一对角斜线上,也就是数组的两个下标i和j,是不是i-j==ColumnIndex[i]-ColumnIndex[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。 关于排列的详细讨论,详见《字符串的排列》,这里不再赘述。 接下来就是写代码了。思路想清楚之后,编码并不是很难的事情。下面是一段参考代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 int g_number = 0; void EightQueen() { const int queens = 8; int ColumnIndex[queens]; for(int i = 0; i < queens; ++ i) ColumnIndex[i] = i; Permutation(ColumnIndex, queens, 0); } void Permutation(int ColumnIndex[], int length, int index) { if(index == length) { if(Check(ColumnIndex, length)) { ++ g_number; PrintQueen(ColumnIndex, length); } } else { for(int i = index; i < length; ++ i) { int temp = ColumnIndex[i]; ColumnIndex[i] = ColumnIndex[index]; ColumnIndex[index] = temp; Permutation(ColumnIndex, length, index + 1); temp = ColumnIndex[index]; ColumnIndex[index] = ColumnIndex[i]; ColumnIndex[i] = temp; } } } bool Check(int ColumnIndex[], int length) { for(int i = 0; i < length; ++ i) { for(int j = i + 1; j < length; ++ j) { if((i - j == ColumnIndex[i] - ColumnIndex[j]) || (j - i == ColumnIndex[i] - ColumnIndex[j])) return false; } } return true; } void PrintQueen(int ColumnIndex[], int length) { printf("Solution %d\n", g_number); for(int i = 0; i < length; ++i) printf("%d\t", ColumnIndex[i]); printf("\n"); } 转自:http://zhedahht.blog.163.com/blog/static/2541117420114331616329/ 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3645762.html,如需转载请自行联系原作者
来源:http://blog.csdn.net/mishifangxiangdefeng/article/details/8012752 答案仅供参考 一、C/C++类 1.以下程序的输入是() [cpp] view plaincopy class Base { public: Base(int j):i(j){} virtual ~Base(){} void func1{i *= 10; func2();} int getValue(){reurn i;} protected: virtual void func2(){i++;} protected: int i; }; class Child:public Base{ public: Child(int j):Base(j){} void func1(){i *= 100; func2();} protected: void func2(){i += 2;} }; int main() { Base *pb = new Child(1); pb->func1(); cout<<pb->getValue()<<endl; delete pb; } 答:12 i初始化为1,由于func1不是虚函数,pb是父类的指针,所以调用父类的func1(),i=10。再调用func2。由非虚函数调用的虚函数也有虚函数的效果。pb是指针,这里调用的是子类的func2,i=12。 2.请问程序的输出结果是() 设有代码如下: [cpp] view plaincopy #define DOUBLE(x) x+x//x*2:-) int i = DOUBLE(5)*5; printf("%d", i); 答:30 5+5*5 3.写出以下程序的输出() [cpp] view plaincopy int main() { char num; for(num = 0; num < 255;){ num += num; } printf("the num is %d\n",num); } 答:无输出,死循环,因为num始终为0 4.程序出错在什么阶段?() [cpp] view plaincopy int main(int argc, char **argv) { http://www.sogo.com cout<<"welcome to sogou"<<endl; return 0; } A.编译阶段出错 B.运行阶段出错 C.编译和运行都出错 D.程序运行正常 答:A 5.下面程序执行结果为【说明:x86_64环境】 [cpp] view plaincopy int a[4][4] = { {1,2,3,4}, {50,60,70,80}, {900,1000,1100,1200}, {13000,14000,15000,16000} }; int (*p1)[4] = a; int (*p2)[4] = &a[0]; int *p3 = &a[0][0]; printf("%d, %d, %d, %d\n", *(*(a+1)-1), *(*(p1+3)-2)+1, *(*(p2-1)+16)+2, *(p3+sizeof(p1)-3) ); A. 16000, 1101, 13002, 2 B. 4, 2, 3, 60 C. 16000, 2, 3, 2 D. 4, 1101, 13002, 60 [cpp] view plaincopy 答:D a、p1、p2都是一样的,是类型为int[4]的指针,当a+1时,实际上地址=地址+sizeof(int)*4。 p3和a指向同一地址,但p3是int类型的指针。当p3+1时,实现上地址=地址+sizeof(int)。 因为是64位的环境,sizoef(p1)=8 6.在32位操作系统gcc编译器环境下,下面程序的运行结果为() [cpp] view plaincopy #include "iostream.h" class A { public: int b; char c; virtual void print() { cout<<"this is father's function!"<<endl; } }; class B:A { public: virtual void print() { cout<<"this is children's function!"<<endl; } }; int main(int argc, char *argv[]) { cout<<sizeof(A)<<" "<<sizeof(B)<<endl; return 0; } A. 12 12 B. 8 8 C. 9 9 D. 12 16 答:A 见类的sizeof 答:AC,见多态总结 [cpp] view plaincopy 答:ABD A:智能指针不能放到容器中 B:共享指针不能放到容器中 D:不返回NULL,返回异常 9.有如下几个类和函数定义,选项中描述正确的是:【多选】() [cpp] view plaincopy class A { public: virtual void foo(){} }; class B { public: virtual void foo(){} }; class C:public A, public B { public: virtual void foo(){} }; void bar1(A *pa) { B *pc = dynamic_cast<B*>(pa); } void bar2(A *pa) { B *pc = static_cast<B*>(pa); } void bar3() { C c; A *pa = &c; B *pb = static_cast<B*>(static_cast<C*>(pa)); } A. bar1无法通过编译 B. bar2无法通过编译 C. bar3无法通过编译 D. bar1可以正确运行,但是采用了错误的cast方法 [cpp] view plaincopy 答:B B:B和A没有继承关系,因此不能从A类的指针通过这种方式转换为B类的指针 D:如果不能转换就返回空指针,不存在“错误”这样说法 10.在Intel CPU上,以下多线程对int型变量x的操作,哪几个不是原子操作,假定变量的地址是对齐的。【多选】() A. x=y B. x++ C. ++x D. x=1 答:ABC 参考http://www.cnblogs.com/qlee/archive/2011/09/13/2174434.html 11.C++下,下面哪些template实例化使用,会引起编译错误?【多选】() [cpp] view plaincopy class A { string a; void f1(){printf("Hello World");} void f2(){a = "Hello World"; printf("%d",a.c_str());} virtual void f3(){printf("Hello World");} virtual void f4(){a = "Hello World"; printf("%d",a.c_str());} }; 一般情况下,下面哪些操作会执行失败?【多选】() A. A *aptr = NULL;aptr->f1(); B. A *aptr = NULL;aptr->f2(); C. A *aptr = NULL;aptr->f3(); D. A *aptr = NULL;aptr->f4(); [cpp] view plaincopy 答:ABCD。因为class默认是私有的 如果都是公有成员,则选BCD。面试宝典上的一道题 12. [cpp] view plaincopy template<class Type>class stack; void fi(stack<char>); //A class Ex { stack<double> &rs; //B stack<int>si; //C }; int main() { stack<char>* sc; //D fi(*sc); //E int i = sizeof(stack<string>);//F } 答:B,引用必须初始化 二、Java类 略 三、Windows类 答:C 答:ACD 答:BCD,参考http://blog.csdn.net/dadalan/article/details/2834850 [cpp] view plaincopy 答:A 在屏幕上显示一个窗口的过程一般有以下步骤,这就是主程序的结构流程: (1)得到应用程序的句柄(GetModuleHandle)。 (2)注册窗口类(RegisterClassEx)。 (3)建立窗口(CreateWindowEx)。 (4)显示窗口(ShowWindows)。 (5)刷新窗口客户区(UpdateWindow)。 (6)进入无限的消息获取和处理的循环。 答:A 答:D [cpp] view plaincopy 答:A C:先传给系统,再传给窗口,如果窗口没有处理,再传给系统 D:如果优先级成高的消息到来 答:B,Debug版有个保护机制 答:BCD 、 答:C 答:B [cpp] view plaincopy 答:A SendMessage后会把自己挂起并等待回应 四、数据结构类 答:128 C(8,0)+C(8,2)+C(8,4)+C(8,6)+C(8,8) 答:B 已经有序的序列用快事排序时间为O(n^2) 答:BD 层次:ABECFDIGJH 先序:(A) 中序:(C) 后序:DCBIJHGFEA 40.在有序双向链表中定位删除一个元素的平均时间复杂度为() A.O(1) B.O(N) C.O(logN) D.O(N*logN) 答:B 定位一个元素的时间为O(N),删除一个元素的时间为O(1) 41.将10阶对称矩阵压缩存储到一维数组A中,则数组A的长度最少为() A.100 B.40 C.55 D.80 答:C 仅存储上三角或下三角以及对角线 42.设数组a[]作为循环队列SQ的存储空间,f为队头指示,r为队尾指示,则执行出队操作的语句为() A. f = f + 1 B. f = (f + 1) % m C. r = (r + 1) % m D. f = (f + 1) % (m + 1) 答:B 出队操作在队头进行,所以对f操作。若数组大小为m,则f的取值范围是[0..m-1] 43.以下哪种操作最适合先进行排序处理?() A. 找最大、最小值 B. 计算算术平均值 C. 找中间值 D. 找出现次数最多的值 答:C 44.设有一个二维数组A[m][n],假设A[0][0]存放在位置644(10),A[2][2]存放在676(10),每个元素占一个空间,问A[3][3](10)存放在什么位置?()注脚(10)表示用10进制表示 A. 688 B. 678 C. 692 D. 696 答:C 从644(10)到676(10)中间存放了2n+2个元素,共占用32个空间。从A[2][2]到A[3][3]共n+1元素,因此占用16个空间。 答:D 答:B [cpp] view plaincopy 答:B tagLen值是15,而代码只有11行 答:A 五、Research类 [cpp] view plaincopy 答:14 假设A走得比B快。且河宽为5+x公里 第一段:出发-第一次相遇,A走了x公里,B走了5公里,且x>5 第二段:第一次相遇-第二次相遇,A走了5+5+x-1=x+9公里,B走了x+1公里 等式:x/5 = (x+9)/(x+1) ==> x1 = 9, x2 = 4(舍去) 答:D 参考http://blog.csdn.net/chl033/article/details/4735111 [cpp] view plaincopy 答:C 令事件A表示患癌症,事件B表示诊断为癌症,由题目可知: P(A) = 0.008 P(!A) = 0.992 P(B|A) = 98% P(!B|A) = 2% P(B|!A) = 3% P(!B|!A) = 97% 求P(A|B)? 解: P(AB) P(B|A)P(A) P(B|A)P(A) 98% * 0.008 P(A|B) = ----- = ---------- = ----------------------- = ------------------ = 20.85% P(B) P(B) P(B|A)P(A)+P(B|!A)P(!A) 98%*0.008+3%*0.992 54.在大规模的语料中,挖掘词的相关性是一个重要的问题,以下哪一个信息不能用于确定两个词的相关性。() A.互信息 B.最大熵 C.卡方检验 D.最大似然比 55.以下哪个不属于CRF模型对于HMM和MEMM模型的优势() A.特征灵活 B.速度快 C.可容纳较多上下文信息 D.全局最优 56.下列不是SVM核函数的中() A.多项式核函数 B.logistic核函数 C.径向基核函数 D.Sigmoid核函数 答:B 57.下列属于无监督学习的是() A. k-means B. SVM C. 最大熵 D. CRF [cpp] view plaincopy 答:C,每次决策时选择分类效果最好的 无监督学习:学习过程中使用的样例不包含输入/输出对,学习的任务是理解数据产生的过程。典型的非监督学习例子是聚类,类别的数量,名称,事先全都没有确定,由计算机自己观察样例来总结得出。 58.以下哪些方法不可以直接用来对文本分类() A. Kmeans B. 决策树 C. 支持向量机 D. KNN 答:B 59.解决稳马模型中预测问题的算法是() A.前向算法 B.后向算法 C.Baum-Welch算法 D.维特比算法 62.假设某日是否有雨只和前一日是否有雨相关:今日有雨,则明日有雨的概率是0.7;今日无雨,则明日有雨的概率是0.5。如果周一有雨,求周三也有雨的概率() A. 0.5 B. 0.64 C. 0.72 D. 0.81 [cpp] view plaincopy 答:B |0.7 0.5| |1 0| * (|0.3 0.5|^2) = |0.64 0.36| 63.在large-scale且sparse的数据分析中,knn的k个最近邻应该如何选择() A. 随机选择 B. L1-norm最近的 C. L2-norm最近的 D. 不用knn 六、Test类 略 七、IOS类 略 八、Web类 略 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/03/28/2986879.html,如需转载请自行联系原作者
来源:http://www.cnblogs.com/Braveliu/archive/2013/01/04/2844757.html 【1】设置或者清除某位。 示例代码如下: 1 #include<iostream> 2 using namespace std; 3 4 #define BIT3 (0x1<<3) 5 6 void Set_bit3(int &a) 7 { 8 a|=BIT3; 9 } 10 11 void Clear_bit3(int &a) 12 { 13 a&=~BIT3; 14 } 15 16 void main() 17 { 18 int m=10; //1010 19 Set_bit3(m); 20 cout<<m<<endl;//1010 == 10 21 Clear_bit3(m); 22 cout<<m<<endl; //0010 == 2 23 24 int n=7; 25 Set_bit3(n); 26 cout<<n<<endl; //1111 == 15 27 Clear_bit3(n); 28 cout<<n<<endl; //0111 == 7 29 } 30 /* 31 10 32 2 33 15 34 7 35 */ 【2】指针引用经典笔试题 (1) 1 #include<iostream.h> 2 #include<malloc.h> 3 #include<string.h> 4 5 void GetMemory(char *p,int num) 6 { 7 p=(char *)malloc(sizeof(char)*num); 8 } 9 10 void main() 11 { 12 char *str = NULL; 13 GetMemory(str,100); 14 strcpy(str,"hello"); 15 } 16 17 //GetMemory函数仅仅只改变了p指针的指向,而str的指向不变 18 //类似于: 19 //char *str=NULL; 20 //char *p = str; 21 //p = (char *)malloc(sizeof(char)*num); 22 //那么这样的三行代码执行结果显然没有达到改变str的作用 (2) 1 #include<iostream.h> 2 #include<string.h> 3 #include<malloc.h> 4 5 void GetMemory2(char **p,int num) 6 { 7 *p=(char *)malloc(sizeof(char)*num); 8 } 9 10 void main() 11 { 12 char *str = NULL; 13 GetMemory2(&str,100); 14 strcpy(str,"hello"); 15 cout<<str<<endl; 16 free(str); 17 } 18 19 //GetMemory函数“隔山打牛” 20 //类似于: 21 //char *str=NULL; 22 //char **p=&str; 23 //*p=(char *)malloc(sizeof(char)*num); 24 //那么这样的三行代码执行结果显然达到改变str的作用 (3) 1 #include<iostream.h> 2 #include<malloc.h> 3 #include<string.h> 4 5 char * GetMemory3(int num) 6 { 7 char *p=(char *)malloc(sizeof(char)*num); 8 return p; 9 } 10 11 void main() 12 { 13 char *str=NULL; 14 str=GetMemory3(100); 15 strcpy(str,"hello"); 16 cout<<str<<endl; 17 free(str); 18 } 19 20 //GetMemory函数功在当代,利在千秋 21 //尽管p变量在栈中,它当生则生,当死则死 22 //但是它在世的一瞬间,却创造了举世的成就,开天辟地!! 23 //p=(char *)malloc(sizeof(char)*num);一句足矣 24 //返回p的值,意义无量! (4) 1 #include<iostream.h> 2 #include<string.h> 3 #include<malloc.h> 4 5 char *GetString() 6 { 7 char p[]="hello world"; 8 return p; //编译器警告!!!返回局部变量 9 } 10 11 void main() 12 { 13 char *str=NULL; 14 str=GetString(); 15 cout<<str<<endl; //垃圾 16 } 17 18 //GetMemory函数山寨版 19 //p变量在栈中,当生则生,当死则死 20 //但是它在世的一瞬间,却目光短浅,于后世无功! 21 //返回p的值,一文不值! (5) 1 #include<iostream.h> 2 #include<string.h> 3 #include<malloc.h> 4 5 char * GetString() 6 { 7 char *p="hello world!"; 8 return p; 9 } 10 11 void main() 12 { 13 char *str=NULL; 14 str=GetString(); 15 cout<<str<<endl; 16 } 17 18 //GetMemory函数正版 19 //p变量在栈中,当生则生,当死则死 20 //但是它在世的一瞬间,却赋予了一份常量,不随它的消失而泯灭! (6) 1 #include<iostream> 2 #include<string> 3 #include<malloc.h> 4 using namespace std; 5 6 void GetString(char *&p) 7 { 8 p=(char *)malloc(sizeof(char)*10); 9 } 10 11 void main() 12 { 13 char *str=NULL; 14 GetString(str); 15 strcpy(str,"hello"); 16 cout<<str<<endl; 17 free(str); 18 str=NULL; 19 } 以上几种例子是面试时遇到的最频繁的试题,在此特意备份,以便学习。 【3】这道题是最典型的数组越界示例: 1 #include<iostream.h> 2 #define MAX 255 3 void main() 4 { 5 unsigned char A[MAX]; 6 for(int i = 0; i <= MAX; i++) 7 { 8 A[i] = i; 9 } 10 } 无限循环....... 【4】求最大字段和 示例代码如下: 1 #include<iostream> 2 using namespace std; 3 4 inline int Max(int a,int b) 5 { 6 return a > b ? a : b; 7 } 8 9 int MaxSubSum(int br[],int n) 10 { 11 int data= 0,max= 0; 12 for(int i=0 ;i<n ;++i) 13 { 14 data = Max(0,br[i]); 15 max = Max(data+max,max); 16 } 17 return max; 18 } 19 20 void main() 21 { 22 int ar[] = {1,-4,-2,-1,7,-3,9}; 23 int result1 = MaxSubSum(ar,7); 24 cout<<result1<<endl; //17 25 } 【5】字节对齐 示例代码: 1 #include<iostream.h> 2 class A 3 { 4 public: 5 int i; 6 }; 7 class B 8 { 9 public: 10 char ch; 11 }; 12 class C 13 { 14 public: 15 int i; 16 short j; 17 }; 18 class D 19 { 20 public: 21 int i; 22 short j; 23 char ch; 24 }; 25 class E 26 { 27 public: 28 int i; 29 int ii; 30 short j; 31 char ch; 32 char chr; 33 }; 34 class F 35 { 36 public: 37 int i; 38 int ii; 39 int iii; 40 short j; 41 char ch; 42 char chr; 43 }; 44 class G 45 { 46 public: 47 int i; 48 int ii; 49 short j; 50 char ch; 51 char chr; 52 int iii; 53 }; 54 class H 55 { 56 public: 57 int i; 58 int ii; 59 char ch; 60 char chr; 61 int iii; 62 short j; 63 }; 64 class I 65 { 66 public: 67 int i; 68 char ch; 69 int ii; 70 char chr; 71 int iii; 72 short j; 73 }; 74 void main() 75 { 76 cout<<"sizeof(int): "<<sizeof(int)<<endl; 77 cout<<"sizeof(short): "<<sizeof(short)<<endl; 78 cout<<"sizeof(char): "<<sizeof(char)<<endl; 79 cout<<endl; 80 cout<<"sizeof(A): "<<sizeof(A)<<endl; 81 cout<<"sizeof(B): "<<sizeof(B)<<endl; 82 cout<<"sizeof(C): "<<sizeof(C)<<endl; 83 cout<<"sizeof(D): "<<sizeof(D)<<endl; 84 cout<<"sizeof(E): "<<sizeof(E)<<endl; 85 cout<<"sizeof(F): "<<sizeof(F)<<endl; 86 cout<<"sizeof(G): "<<sizeof(G)<<endl; 87 cout<<"sizeof(H): "<<sizeof(H)<<endl; 88 cout<<"sizeof(I): "<<sizeof(I)<<endl; 89 } 90 91 //Out put: 92 /* 93 sizeof(int): 4 94 sizeof(short): 2 95 sizeof(char): 1 96 97 sizeof(A): 4 98 sizeof(B): 1 99 sizeof(C): 8 100 sizeof(D): 8 101 sizeof(E): 12 102 sizeof(F): 16 103 sizeof(G): 16 104 sizeof(H): 20 105 sizeof(I): 24 106 */ 【6】大小端判断 题目:请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1 分析: 为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。 但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器), 另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。 因此就导致了大端存储模式和小端存储模式。 例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。 对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。 小端模式,刚好相反。我们常用的X86结构是小端模 式,而KEIL C51则为大端模式。 嵌入式开发对大小端都比较敏感。所谓的大端模式是指: 数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中。 这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放; 所谓的小端模式是指:数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中, 这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的实际逻辑方法一致。 示例代码如下: 1 #include<iostream> 2 using namespace std; 3 4 int CheckCpu() 5 { 6 union w 7 { 8 int a; 9 char b; 10 }c; 11 c.a=1; 12 return (c.b==1); 13 } 14 15 void main() 16 { 17 cout<<CheckCpu()<<endl; //1 //说明是小端模式 18 } 总结: 其实大小端的问题很简单的,就是因为数据在同样的内存可以有两种存储模式。 简单记住:低低小,低高大。 也就是说:低位数据存入低地址小端;低位数据存入高地址大端。 【7】求整型数组中的最小以及次小项 示例代码如下: 1 #include<iostream> 2 using namespace std; 3 4 void select(int ar[],int n) 5 { 6 int m1, m2; 7 m1 = m2 = 0xffff; 8 int x1, x2; 9 x1 = x2 = 0; 10 for(int j = 0; j < n ;j++) 11 { 12 if (ar[j] < m1) 13 { 14 m2 = m1; //暂存次小 15 x2 = x1; //暂存次小索引 16 m1 = ar[j]; //暂存最小 17 x1 = j; //暂存最小索引 18 } 19 else if(ar[j] < m2 ) 20 { 21 m2 = ar[j]; //保存次小 22 x2 = j; //保存次小索引 23 } 24 } 25 cout<<x1<<" "<<m1<<endl; //输出最小 26 cout<<x2<<" "<<m2<<endl; //输出次小 27 } 28 void main() 29 { 30 int ar[5] = {1, 7, 5, 4, 2}; 31 select(ar,5); 32 } 33 34 /*运行结果: 35 0 1 36 4 2 37 */ 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/04/15/3021926.html,如需转载请自行联系原作者
题目:定义一个map对象,其元素的键是家族姓氏,而值是存储该家族孩子名字的vector对象。为这个map容器输入至少六个条目。通过基于家族姓氏的查询检测你的程序,查询应输出该家族所有孩子的名字。 1 //定义一个map对象,其元素的键是家族姓氏 2 //而值则是存储该家族孩子名字的vector对象 3 //进行基于家族姓氏的查询,输出该家族所有孩子的名字 4 #include<iostream> 5 #include<map> 6 #include<vector> 7 #include<string> 8 using namespace std; 9 10 int main() 11 { 12 map<string , vector<string> > children; 13 string surname , childName; 14 15 //读入条目(家族姓氏及其所有孩子的名字) 16 do{ 17 cout<<"Enter surname: "<<endl; 18 cin>>surname; 19 if(!cin) //读入结束 20 break; 21 //插入新条目 22 vector<string> chd; 23 pair<map<string , vector<string> >::iterator , bool> ret = children.insert(make_pair(surname , chd)); 24 25 if(!ret.second){//该家族姓氏已在map容器中存在 26 cout<<"repeated surname: "<<surname<<endl; 27 continue; 28 } 29 30 cout<<"Enter children's name: "<<endl; 31 while(cin>>childName)//读入该家族所有孩子的名字 32 ret.first->second.push_back(childName); 33 cin.clear(); //使输入流重新有效 34 }while(cin); 35 36 cin.clear(); //使输入流重新有效 37 38 //读入要查询的家族 39 cout<<"Enter a surname to search: "<<endl; 40 cin>>surname; 41 42 //根据读入的家族姓氏进行查找 43 map<string , vector<string> >::iterator iter = children.find(surname); 44 45 //输出查询结果 46 if(iter == children.end()) //找不到该家族姓氏 47 cout<<"no this surname: "<<surname<<endl; 48 else 49 { 50 cout<<"children: "<<endl; 51 //输出该家族中所有孩子的名字 52 vector<string>::iterator it = iter->second.begin(); 53 while(it != iter->second.end()) 54 cout<<*it++<<endl; 55 } 56 57 return 0; 58 } 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3300971.html,如需转载请自行联系原作者
新浪微博开放平台为第三方应用提供了简便的合作模式,满足了手机用户和平板电脑用户随时随地分享信息的需求。通过调用平台的api即可实现很多微博上的功能。 本篇主要目的是记录新浪微博移动SDK iOS版本的在iOS5下的嵌入和使用。 1、申请一个新浪微博的移动应用 。 申请地址:http://open.weibo.com/development,申请后得到App key 和 App Secret 2、下载iOS_sdk 下载地址:http://open.weibo.com/wiki/SDK#iOS_SDK ,下载第一个就ok了。 3、新建一个项目Sina_weibo,选择single View app。而且使用5.0后的ARC特性 。 导入解压后的sdk 导入SDK 4、适配SDK在arc环境下运行 这时候运行程序,你会发现很多关于ARC的错误,因为sdk里是没有使用arc的。这时候如果想sdk的文件不参与arc方式的编译,那就需要做下设置,在Build Phases里添加“-fno-objc-arc”标示 双击需要标识的文件,输入-fno-objc-arc。 这样weibo SDK的文件就不会以arc的方式编译了。 5、 在自己的工程里面增加Security.framework。SDK需要使用Security.framework将OAuth认证以后的token放到keyChain里面从而增加整个工程的安全性。 这时候运行,程序就编译运行正常了 6、其他的和SDK里的Demo一样了 登录调用 [weiBoEnginelogIn]; 注销调用 [weiBoEnginelogOut]; 发微博: 可以调用SDK默认的界面发送: WBSendView *sendView = [[WBSendViewalloc] initWithAppKey:appKeyappSecret:appSecrettext:@"test"image:[UIImageimageNamed:@"bg.png"]]; [sendView setDelegate:self]; [sendView show:YES]; 对应的发送微博的api是:statuses/upload 发送微博并上传图片。如果在微博上显示地图,那就发送经纬度参数,多加上 lat false float 纬度,有效范围:-90.0到+90.0,+表示北纬,默认为0.0。 long false float 经度,有效范围:-180.0到+180.0,+表示东经,默认为0.0。 7、调用自定义api 6步骤里调用的是sdk里封装好的,那微博这么api和功能,怎么调用呢? 我们试着获取个人信息 [cpp] view plaincopy NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:2]; [params setObject:[engine accessToken]forKey:@"access_token"]; [params setObject:[engine userID]forKey:@"uid"]; NSLog(@"params:%@", params); [engine loadRequestWithMethodName:@"users/show.json" httpMethod:@"GET" params:params postDataType:kWBRequestPostDataTypeNone httpHeaderFields:nil]; params的参数是必须的。 返回的数据参考接口http://open.weibo.com/wiki/2/users/show 这样可以获取微博自己的昵称等信息。 微博所有api文档都在这个页面http://open.weibo.com/wiki/API%E6%96%87%E6%A1%A3_V2,使用的方法和例子都有。 需要什么用什么接口,把loadRequestWithMethodName 改变成自己需要的接口,params参数改成需要的参数,就可以了。 有的接口是不需要params的,比如 statuses/friends_timeline.json获取关注人的微博,这里params可以是nil. PS:本篇记录用的是Oauth认证,xauth认证需要审核资格才能使用的。 8、项目源码下载地址:http://download.csdn.net/detail/totogo2010/4633077 继上篇 iOS学习之iOS5.0以上 使用新浪微博开放平台OAuth 过后,新浪微博授权弹出的网页又有调整,中间还有过瘫痪情况。如果按上篇做出来的授权页面就成这样了: 第一:网页页面变大了, 第二:没有了取消按钮。 根据这个情况在sina weibo SDK里做了写调整 调整:增加一个关闭按钮,弹出窗口大小。 在WBAuthorizeWebView.m文件的方法:bounceOutAnimationStopped里添加按钮: [cpp] view plaincopy UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; [closeButton setFrame:CGRectMake(280, 430, 60, 60)]; [closeButton setImageEdgeInsets:UIEdgeInsetsMake(3, 0, 0, 0)]; [closeButton setImage:[UIImage imageNamed:@"close"] forState:UIControlStateNormal]; [closeButton addTarget:self action:@selector(hideAndCleanUp) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:closeButton]; close.png图片sdk里自带就有。hideAndCleanUp方法就是把窗口移除。hideAndCleanUp方法原来就有。运行效果: 看右下角有个关闭按钮,为什么放在右下角呢,因为右上角有个注册按钮,容易被点到。一会把网页窗口最大化了就能看到了。 扩大窗口 在WBAuthorizeWebView.m文件的方法- (void)sizeToFitOrientation:(UIInterfaceOrientation)orientation 修改如下: 上面的尺寸是横屏的时候的,我修改了竖屏时的窗口的大小。 [cpp] view plaincopy - (void)sizeToFitOrientation:(UIInterfaceOrientation)orientation { [self setTransform:CGAffineTransformIdentity]; if (UIInterfaceOrientationIsLandscape(orientation)) { [self setFrame:CGRectMake(0, 0, 480, 320)]; [panelView setFrame:CGRectMake(10, 30, 460, 280)]; [containerView setFrame:CGRectMake(10, 10, 440, 260)]; [webView setFrame:CGRectMake(0, 0, 440, 260)]; [indicatorView setCenter:CGPointMake(240, 160)]; } else { [self setFrame:CGRectMake(0, 5, 320, 470)]; [panelView setFrame:CGRectMake(0, 5, 320, 470)]; [containerView setFrame:CGRectMake(0, 5, 320, 460)]; [webView setFrame:CGRectMake(0, 0, 320, 460)]; [indicatorView setCenter:CGPointMake(160, 240)]; } [self setCenter:CGPointMake(160, 240)]; [self setTransform:[self transformForOrientation:orientation]]; previousOrientation = orientation; } 运行效果: 这个状态差不多就可以了。 还有在调用WeiBoEngine 的Logout 登出无效的情况。修改如下: 在WBAuthorize.m文件,把startAuthorize函数修改如下: [cpp] view plaincopy NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:appKey, @"client_id", @"code", @"response_type", redirectURI, @"redirect_uri", @"mobile", @"display", @"true",@"forcelogin", nil]; 就是在 params里添加@”true”,@”forcelogin”。 以上是使用新浪微博sdk开发遇到的问题和解决的一些方法。 修改过的项目代码:http://download.csdn.net/detail/totogo2010/4928029 来源:http://blog.csdn.net/totogo2010/article/details/8435174 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3709791.html,如需转载请自行联系原作者
分析以下代码的输出: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include<iostream> using namespace std; class A { public: A(int j):age(j) , num(age + 1) { cout<<"age:"<<age<<",num:"<<num<<endl; } protected: int num; int age; }; void main() { A sa(15); } 运行结果:age:15 , num:2(num为一个随机数) 由于按成员在类定义中的声明顺序进行构造,而不是按构造函数说明中冒号后面的顺序,所以num成员被赋得是一个随机值,并不是想赋的16,因为这个时候,成员age还没有被赋值,age的内存空间中是一个随机值。 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3419848.html,如需转载请自行联系原作者
我先画一个单链表,这个单链表有4个元素。我的思路就是,每次把第二个元素提到最前面来。比如下面是第一次交换,我们先让头结点的next域指向结点a2,再让结点a1的next域指向结点a3,最后将结点a2的next域指向结点a1,就完成了第一次交换。 第一次交换 然后进行相同的交换将结点a3移动到结点a2的前面,然后再将结点a4移动到结点a3的前面就完成了反转。 第二次交换 第三次交换 思路有了,那就可以写代码了。这里我们需要额外的两个工作指针来辅助交换。这个下面的步骤慢慢理解下,结合图片。注意结点之间的关系要先断再连。 步骤: 定义当前结点 current,初始值为首元结点,current = L->next; 定义当前结点的后继结点 pnext, pnext = current->next; 只要 pnext 存在,就执行以下循环: 定义新节点 prev,它是 pnext的后继结点,prev = pnext->next; 把pnext的后继指向current, pnext->next = current; 此时,pnext 实际上已经到了 current 前一位成为新的current,所以这个时候 current 结点实际上成为新的 pnext,current = pnext; 此时,新的 current 就是 pnext,current = pnext; 而新的 pnext 就是 prev,pnext = prev; 最后将头结点与 current 重新连上即可,L->next = current; 函数设计如下: 01 /* 单链表反转/逆序 */ 02 Status ListReverse(LinkList L) 03 { 04 LinkList current,pnext,prev; 05 if(L == NULL || L->next == NULL) 06 return L; 07 current = L->next; /* p1指向链表头节点的下一个节点 */ 08 pnext = current->next; 09 current->next = NULL; 10 while(pnext) 11 { 12 prev = pnext->next; 13 pnext->next = current; 14 current = pnext; 15 pnext = prev; 16 printf("交换后:current = %d,next = %d \n",current->data,current->next->data); 17 } 18 //printf("current = %d,next = %d \n",current->data,current->next->data); 19 L->next = current; /* 将链表头节点指向p1 */ 20 return L; 21 } 其实在你写函数的时候,我也写了个函数,也能运行。思路也差不多,不过你的current一直是表的第一个结点,我这里的current始终是首元结点的值,我的函数需要每次对pnext重新赋值。一会解释下。 01 Status ListReverse2(LinkList L) 02 { 03 LinkList current, p; 04 05 if (L == NULL) 06 { 07 return NULL; 08 } 09 current = L->next; 10 while (current->next != NULL) 11 { 12 p = current->next; 13 current->next = p->next; 14 p->next = L->next; 15 L->next = p; 16 } 17 return L; 18 } p = current->next; p 就相当于前面的 pnext。(图1中a2即为p) current->next = p->next; p->next 就相当于 prev的角色,这句代码意思是 current 的后继指向 prev.(相当于图1中a1->next = a3(a2->next)) p->next = L->next; 这句就是 p 的后继直接指向首元节点。(相当于图1中a2->next = a1) L->next = p; 然后再将头结点指向 p。(相当于图1中L->next = a2) 参照图就很容易理解上面的步骤了。我觉得我这么写比你的清晰一些。我先将current指向prev,再将pnext指向current,最后将头结点指向pnext。 这个是程序运行的结果。 01 整体创建L的元素(头插法): 02 // 原链表,current = 68, pnext = 55,68指向18,55指向18,头结点指向55 03 -> 68 -> 55 -> 18 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67 04 05 // 第一次交换后,原链表变成这样 06 -> 55 -> 68 -> 18 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67 07 // 进行第二次交换,pnext = 18,68指向45,18变成头结点 08 -> 18 -> 55 -> 68 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67 09 // 进行第三次交换,pnext = current->next = 45,68指向41,45变成头结点 10 -> 45 -> 18 -> 55 -> 68 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67 11 // …… 12 -> 41 -> 45 -> 18 -> 55 -> 68 -> 43 -> 5 -> 28 -> 80 -> 67 13 14 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 5 -> 28 -> 80 -> 67 15 16 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 28 -> 80 -> 67 17 18 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 80 -> 67 19 20 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 67 21 // current 68 没有后继,反转结束 22 -> 67 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 23 24 25 反转L后 26 -> 67 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 最后附上完整代码,反转有两个函数。 方法1,current始终保持在第一位,pnext与prev遍历并完成交换。 方法2,current始终是原链表的第一个数,然后把pnext不断移动到首位。 View Code 有两个方法可以实现单链表的反转: 方法一: 1 #include <stdio.h> 2 #include <stdlib.h> 3 4 typedef struct Node 5 { 6 int data; 7 struct Node *next; 8 }Node; 9 Node *head,*p; 10 11 Node * ReverseLink(Node *head) 12 { 13 Node *p1, *p2, *p3; 14 if(head==NULL || head->next==NULL) 15 return head; 16 p1=head, p2=p1->next; 17 while(p2) 18 { 19 p3=p2->next; 20 p2->next=p1; 21 p1=p2; 22 p2=p3; 23 } 24 head->next=NULL; 25 head=p1; 26 return head; 27 } 28 29 void CreateList(int n) 30 { 31 Node *q; 32 int i; 33 printf("Input %2d data: ",n); 34 head=(Node *)malloc(sizeof(Node)); 35 q=head; 36 scanf("%d",&q->data); 37 for(i=2;i<=n;i++) 38 { 39 q->next=(Node *)malloc(sizeof(Node)); 40 q=q->next; 41 scanf("%d",&q->data); 42 } 43 q->next=NULL; 44 } 45 46 void PrintList() 47 { 48 Node *q; 49 q=head; 50 while (q!=NULL) 51 { 52 printf("%-8d",q->data); 53 q=q->next; 54 } 55 printf("\n"); 56 } 57 58 void main() 59 { 60 CreateList(5); 61 PrintList(); 62 head=ReverseLink(head); 63 PrintList(); 64 } 方法二: 1 #include <iostream> 2 #include <assert.h> 3 using namespace std; 4 5 struct LNode{ 6 char data; 7 LNode * next; 8 }; 9 10 LNode * initList() 11 { 12 LNode *head=new LNode; 13 LNode *curPtr, *newPtr; 14 curPtr=head; 15 int i=0; 16 char ch='A'; 17 while(i++<10) 18 { 19 newPtr=new LNode; 20 newPtr->data=ch++; 21 curPtr->next=newPtr; 22 curPtr=newPtr; 23 } 24 newPtr->next=NULL; 25 return head; 26 } 27 28 void print(LNode *head) 29 { 30 LNode *ptr=head->next; 31 while(ptr != NULL) 32 { 33 cout << ptr->data << " "; 34 ptr=ptr->next; 35 } 36 cout << endl; 37 } 38 39 void reverse(LNode *head) 40 { 41 assert(head != NULL && head->next != NULL); 42 LNode *ptr=head->next->next; 43 head->next->next=NULL; 44 while(ptr != NULL) 45 { 46 LNode *tmp=ptr->next; 47 ptr->next=head->next; 48 head->next=ptr; 49 ptr=tmp; 50 } 51 } 52 53 int main() 54 { 55 LNode *head=initList(); 56 print(head); 57 cout << "After reverse: " << endl; 58 reverse(head); 59 print(head); 60 system("PAUSE"); 61 return 0; 62 } 参考:http://www.cnblogs.com/heyonggang/p/3304838.html http://www.nowamagic.net/librarys/veda/detail/2241 http://blog.csdn.net/hyg0811/article/details/11113623 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3304838.html,如需转载请自行联系原作者