Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

编程实现有关SMS4的2个程序之——编程实现线性变换模块

$
0
0

/**
 * @author 康雨城 北京大学软件与微电子学院
 * @time 2017/11/22
 */

import java.util.Scanner;

public class Main {
    //定义输入字的长度,根据题意,长度为8,也就是用8个16进制的数来表示一个字
    public static int WORD_STRING_LENGTH=8;
    //一个字占32bit,用32位二进制数来表示
    public static int BIT_LIST_LENGTH=4*WORD_STRING_LENGTH;
    //定义二进制与十进制对应的数组
    public static String[] list={
            "0000","0001","0010","0011",
            "0100","0101","0110","0111",
            "1000","1001","1010","1011",
            "1100","1101","1110","1111"};
    public static void main(String[] args) {
        Scanner input =new Scanner(System.in);
        //String str=input.next();//获取输入的字
        String str1="1a2b3c4d";
        String result1=getResult(str1);
        System.out.println("输入 "+str1+" 的线性变换结果为 "+result1);
        String str2="c1000000";
        String result2=getResult(str2);
        System.out.println("输入 "+str2+" 的线性变换结果为 "+result2);
        String str3="80000000";
        String result3=getResult(str3);
        System.out.println("输入 "+str3+" 的线性变换结果为 "+result3);

    }
/*
该方法实现线性变换模块。要求:用户输入一个用16进制表示的数字(例如 1a2b3c4d)
程序输出相应的用16进制表示的字
 */
    private static String getResult(String str){

        int[] B=new int[BIT_LIST_LENGTH];//用于存储输入字转为二进制的数
        int[] LB=new int[BIT_LIST_LENGTH];//用于存储得到的二进制结果
        String LB_16="";//用于存储得到的十六进制结果
        //进行一次循环,将输入的十六进制的数转化为二进制的数
        for(int i=0;i<WORD_STRING_LENGTH;i++){
            int k=Integer.valueOf(str.substring(i,i+1),16);
            for(int j=0;j<4;j++){
                B[4*i+j]=list[k].charAt(j)-48;
            }
        }
        //进行线性变换操作
        for(int p=0;p<BIT_LIST_LENGTH;p++){
            LB[p]=B[p]^
                    B[(p+BIT_LIST_LENGTH-2)%BIT_LIST_LENGTH]^
                    B[(p+BIT_LIST_LENGTH-10)%BIT_LIST_LENGTH]^
                    B[(p+BIT_LIST_LENGTH-18)%BIT_LIST_LENGTH]^
                    B[(p+BIT_LIST_LENGTH-24)%BIT_LIST_LENGTH];
        }
        //将二进制的数转换为十六进制的数
        for(int x=0;x<WORD_STRING_LENGTH;x++){
            String temp="";
            for(int y=0;y<4;y++){
                temp+=LB[x*4+y];
            }
            LB_16+=Integer.toHexString(Integer.parseInt(temp, 2));
        }
        return LB_16;
    }
}





作者:Kangyucheng 发表于2017/11/22 19:19:55 原文链接
阅读:104 评论:0 查看评论

React Native 入门(十三) - StackNavigator 快速入门

$
0
0

RN 版本:0.50
针对平台:Android
操作环境:Windows 10
React Navigation 版本:1.0.0-beta.20

文章同步自简书:http://www.jianshu.com/p/dece7a09c6bf

前言

Navigator(导航器)是用来进行场景(页面)切换的组件,但是由于它的各种缺陷,从 0.44 开始,就被 fb 移除了,并且推荐大家使用更方便的 React Navigation

React Navigation 改进并取代了多个导航库,目前仍然在继续完善中。它包含 StackNavigator、TabNavigator 和 DrawerNavigator,你还可以自定义导航器。由于我也是跟着官方文档刚刚学,打算边学边总结加深印象,同时给大家一个参考(英文文档我看着实在很累)。不出意外,应该会写上好几篇。

StackNavigator 实现最基本的页面跳转

首先安装 React Navigation:

yarn add react-navigation

然后导入到项目中(这里我们只用到了 StackNavigator):

import {StackNavigator} from 'react-navigation';

下面的例子来源于 官网,我在其基础上加以说明,直接上代码。

const HomeScreen = () => (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Home Screen</Text>
    </View>
);

const DetailScreen = () => (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Detail Screen</Text>
    </View>
);

const RootNavigator = StackNavigator({
  Home: {
    screen: HomeScreen
  },
  Detail: {
    screen: DetailScreen
  }
});

export default RootNavigator;

两个 View 分别展示了一行文本,这里主要讲一下 RootNavigator 的定义。

其中 HomeDetail 是自定义的名称,screen 属性是要显示在页面上的视图组件。StackNavigator 顾名思义,栈导航器,这里写的 Home 页面就是第一个入栈的,也是程序运行时第一个显示的。

我们将其导入并注册,

import RootNavigator from './RootNavigator';
AppRegistry.registerComponent('BlogDemo', () => RootNavigator);

运行。

可以看到第一个页面已经显示出来了,并且自带了一个类似 ToolBar 的东西,这个东西怎么去掉,我还没有研究到。

好了,这并不是我这篇文章打算说的东西。

下面说一说如何跳转到 Detail 页面。我们在 HomeScreen 中稍作修改,

const HomeScreen = ({navigation}) => (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Home Screen</Text>
      <Button
          onPress={() => navigation.navigate('Detail')}
          title='Go to Detail'/>
    </View>
);

可以看到在方法的参数中添加了一个 {navigation} 的参数,暂时先不需要知道它的具体工作原理,只要知道在某个页面被 StackNavigator 加载的时候,会自动分配一个 navigation 属性就可以了。这个属性就是用来驱动页面之间的跳转的。navigate(routeName, params, action) 这个方法有三个参数,目前只说第一个。routeName 表示已经注册过的目标路由的名称,也就是我们打算跳转到的页面,这里就是 Detail,由于是自定义的名称,书写的时候不要写错了。

为了美观(大概吧),我们再给两个 ‘ToolBar’ 加上标题。

const RootNavigator = StackNavigator({
  Home: {
    screen: HomeScreen,
    navigationOptions: {
      headerTitle: 'Home'
    }
  },
  Detail: {
    screen: DetailScreen,
    navigationOptions: {
      headerTitle: 'Detail'
    }
  }
});

然后跑起来:

效果图

Detail 页面还自带了一个返回按钮,是不是很神奇?

最后呢,一般来说,每个页面都是单独写在一个 js 文件中的,这样的话,该如何取到 navigation 参数并进行页面跳转呢?

我们之前说过了,在某个页面被 StackNavigator 加载的时候,会自动分配一个 navigation 属性。所以如果我们把 HomeScreen 和 DetailScreen 单独拿出来,可以这么写,以 HomeScreen 为例:

export default class HomeScreen extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Home Screen</Text>
      <Button
          onPress={() => this.props.navigation.navigate('Detail')}
          title='Go to Detail'/>
    </View>;
  }
}

没有错,我们可以直接通过 this.props.navigation 获取到它,然后执行 navigate() 方法。

但是,官网却是这么写的(代码似乎和本节不一致,因为是在另一个地方粘的,请先忽略,这不是重点):

class HomeScreen extends React.Component {
  render() {
    const {navigate} = this.props.navigation;

    return (
      <View>
        <Text>This is the home screen of the app</Text>
        <Button
          onPress={() => navigate('Profile', {name: 'Brent'})}
          title="Go to Brent's profile"
        />
      </View>
     )
   }
}

第一眼看上去我懵逼了, const {navigate} = this.props.navigation; 是个什么鬼?

仔细想想,其实这就是解构赋值嘛。我在 React Native 入门(五) - Props(属性) 这篇文章中,还专门写过,自己都差点忘记了。

它们不过是不同的写法,效果是完全一致的,图就不贴了。先暂时写这么多,等我继续研究研究再更新吧。

作者:qq_24867873 发表于2017/11/22 20:02:01 原文链接
阅读:88 评论:0 查看评论

Java中的synchronized

$
0
0

在Java中synchronized可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。

而synchronized底层是通过使用对象的监视器锁(monitor)来确保同一时刻只有一个线程执行被修饰的方法或者代码块。可以用锁和钥匙来解释,被synchronized修饰的方法或者代码块是一把锁,这把锁是归对象所有的,当一个线程需要执行这些方法或者代码块的时候,锁就被钥匙插上了,所以其他线程就不能执行这些方法或者代码块。(实际情况还要更加复杂,这里只是便于理解,实际上synchronized的锁是可重入的)

下面会用几个示例解释一下:

  1. synchronized修饰方法:

    1. synchronized修饰static方法:

      /**
       * 用于测试synchronized修饰static方法的线程类
       */
      public class SynchronizedStaticMethodThread extends Thread{
      
          private static synchronized void print(){
              //输出调用的线程及调用时的时间戳
              System.out.println(System.currentTimeMillis()+" Call staticSynchronizedMethod by "+Thread.currentThread().getName());
              try {
                  //调用线程休眠5秒,锁竞争效果更加明显
                  Thread.sleep(5000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      
          @Override
          public void run() {
              print();
          }
      
      }
      

      下面是测试用例代码:

      public static void main(String[] args) {
          SynchronizedStaticMethodThread t1=new SynchronizedStaticMethodThread();
          SynchronizedStaticMethodThread t2=new SynchronizedStaticMethodThread();
          SynchronizedStaticMethodThread t3=new SynchronizedStaticMethodThread();
          t1.start();
          t2.start();
          t3.start();
      }
      

      运行结果:

      1511100950366 Call staticSynchronizedMethod by Thread-0
      1511100955368 Call staticSynchronizedMethod by Thread-2
      1511100960368 Call staticSynchronizedMethod by Thread-1
      

      分析:

      从输出结果可以看出,t1、t2和t3三个线程在竞争同一把锁,而这个锁其实SynchronizedStaticMethodThread.class这个Class对象的监视器锁。这是因为每个类都只有一个Class对象,每个类的各个实例对象都共享同一个Class对象。

    2. synchronized修饰非static方法:

      /**
       * 用于测试synchronized修饰非static方法的线程类
       */
      public class SynchronizedMethodThread extends Thread{
          private synchronized void print(){
              //输出调用的线程及调用时的时间戳
              System.out.println(System.currentTimeMillis()+" Call staticSynchronizedMethod by "+Thread.currentThread().getName());
              try {
                  //调用线程休眠5秒,锁竞争效果更加明显
                  Thread.sleep(5000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      
          @Override
          public void run() {
              print();
          }
      }
      

      运行结果:

      1511183399297 Call staticSynchronizedMethod by Thread-0
      1511183399297 Call staticSynchronizedMethod by Thread-1
      

      分析:从运行结果可以看出t1和t2两个线程没有发生锁竞争,这是因为它们上的锁不是同一个锁,即它们的锁分别是两个对象所持有。

  2. synchronized修饰代码块:

    /**
     * 展示了synchronized修饰代码块的例子
     * @author RJH 
     * @date 2017年11月22日 下午8:21:56
     */
    public class SynchronizedObjectDemo {
        /**
         * 类变量
         */
        private static Object staticObj=new Object();
        /**
         * 成员变量
         */
        private Object o=new Object();
        /**
         * 在类变量上锁的方法
         */
        public void printByStaticObj(){
            synchronized (staticObj) {//在类变量上锁
                try {
                    //调用线程休眠5秒,锁竞争效果更加明显
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    //输出表示被调用
                    System.out.println(System.currentTimeMillis()+" printByStaticObj is called");
                }
            }
        }
        /**
         * 在成员变量上锁的方法
         */
        public void printByObj(){
            synchronized (o) {//在成员变量上错
                try {
                    //调用线程休眠5秒,锁竞争效果更加明显
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    //输出表示被调用
                    System.out.println(System.currentTimeMillis()+" printByObj is called");
                }
            }
        }
    
        public static void main(String[] args) {
            //定义一个线程组
            ThreadGroup threadGroup=new ThreadGroup(Thread.currentThread().getThreadGroup(),"SynchronizedObject");
            for(int i=0;i<5;i++){//循环5次,每次都启动一个线程
                SynchronizedObjectDemo objDemo=new SynchronizedObjectDemo();//每次都构造一个新对象
                Thread printByObjThread=new Thread(threadGroup,new Runnable() {//构造新线程的时候把它加入到定义的线程组
    
                    @Override
                    public void run() {
                        objDemo.printByObj();
                    }
                });
                printByObjThread.start();
            }
            while(true){
                if(threadGroup.activeCount()==0){//死循环,直到定义的线程组中的线程都终止才执行后续步骤
                    for(int i=0;i<5;i++){
                        //这里是调用类变量上锁的方法
                        SynchronizedObjectDemo demo=new SynchronizedObjectDemo();
                        Thread printByStaticObjThread=new Thread(new Runnable() {
    
                        @Override
                        public void run() {
                            demo.printByStaticObj();
                        }
                        });
                        printByStaticObjThread.start();
                    }
                    break;
                }
            }
        }
    }
    

    输出结果如下:

    1511354086299 printByObj is called
    1511354086299 printByObj is called
    1511354086299 printByObj is called
    1511354086299 printByObj is called
    1511354086299 printByObj is called
    1511354091301 printByStaticObj is called
    1511354096302 printByStaticObj is called
    1511354101302 printByStaticObj is called
    1511354106302 printByStaticObj is called
    1511354111302 printByStaticObj is called
    

    分析:

    从这个输出结果可以看出,其实对于一个类变量加锁就类似给静态方法加锁,而对于一个成员变量加锁就类似给非静态方法加锁。

    这里需要注意的是,如果把第一次for循环中的SynchronizedObjectDemo对象的构造放到第一次for循环之前的话,输出的结果就会类似第二次for循环了,因为此时锁的是同一个对象。

总结:其实网上说的synchronized的类锁和对象锁都是针对对象进行锁,只是Class对象或者类变量只有一个。

作者:a158123 发表于2017/11/22 20:56:32 原文链接
阅读:88 评论:0 查看评论

Unity Shader 学习笔记(20) 卷积、卷积核、边缘检测算子、边缘检测

$
0
0

Unity Shader 学习笔记(20) 卷积、卷积核、边缘检测算子、边缘检测

参考书籍:《Unity Shader 入门精要》


卷积(convolution)、卷积核(kernel)

  • 卷积:使用卷积核对图像每一个像素进行操作。
  • 卷积核: 四方形网格结构,每个方格都有一个权重值。也称边缘检测算子。

对图像某个像素卷积时,把卷积核中心放置在像素上,依次计算每个元素和重合像素的乘积并求和,得到新的像素值。

边缘检测算子

即用于边缘检测的卷积核。判断边缘可以是颜色、亮度、纹理等变换差异大小,也就是判断相邻像素之间的差值(梯度,gradient)。

每次卷积得到两个方向上的梯度值Gx和Gy,整体梯度值:G = | Gx | + | Gy |。


边缘检测

使用Sobel算子进行边缘检测。

Edges Only从0变化到1:

EdgeDetection类,主要是作为变量的输入:

public class EdgeDetection : PostEffectsBase
{
    [Range(0.0f, 1.0f)]
    public float edgesOnly = 0.0f;              // 1为只显示边缘
    public Color edgeColor = Color.black;       // 边缘色
    public Color backgroundColor = Color.white; // 背景色

    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (TargetMaterial != null)
        {
            TargetMaterial.SetFloat("_EdgeOnly", edgesOnly);
            TargetMaterial.SetColor("_EdgeColor", edgeColor);
            TargetMaterial.SetColor("_BackgroundColor", backgroundColor);
        }
        Graphics.Blit(src, dest, TargetMaterial);
    }
}

Shader:

Properties {
    _MainTex ("Base (RGB)", 2D) = "white" {}
    _EdgeOnly ("Edge Only", Float) = 1.0                // 0:只加边缘,1:只显示边缘,不显示原图
    _EdgeColor ("Edge Color", Color) = (0, 0, 0, 1)
    _BackgroundColor ("Background Color", Color) = (1, 1, 1, 1)
}
Pass {  
    ... 

    struct v2f {
        float4 pos : SV_POSITION;
        half2 uv[9] : TEXCOORD0;    // 对应周围(包括中心)像素纹理坐标
    };

    v2f vert(appdata_img v) {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);

        half2 uv = v.texcoord;

        o.uv[0] = uv + _MainTex_TexelSize.xy * half2(-1, -1);
        o.uv[1] = uv + _MainTex_TexelSize.xy * half2(0, -1);
        o.uv[2] = uv + _MainTex_TexelSize.xy * half2(1, -1);
        o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1, 0);
        o.uv[4] = uv + _MainTex_TexelSize.xy * half2(0, 0);
        o.uv[5] = uv + _MainTex_TexelSize.xy * half2(1, 0);
        o.uv[6] = uv + _MainTex_TexelSize.xy * half2(-1, 1);
        o.uv[7] = uv + _MainTex_TexelSize.xy * half2(0, 1);
        o.uv[8] = uv + _MainTex_TexelSize.xy * half2(1, 1);

        return o;
    }

    // 亮度
    fixed luminance(fixed4 color) {
        return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b; 
    }

    // Sobel算子采样,计算当前像素的梯度值
    half Sobel(v2f i) {
        // 水平卷积核、竖直卷积核
        const half Gx[9] = {-1,  0,  1,
                                -2,  0,  2,
                                -1,  0,  1};
        const half Gy[9] = {-1, -2, -1,
                                0,  0,  0,
                                1,  2,  1};     

        half texColor;
        half edgeX = 0;     // 边缘值越大,越可能是边缘
        half edgeY = 0;
        for (int it = 0; it < 9; it++) {
            texColor = luminance(tex2D(_MainTex, i.uv[it]));
            edgeX += texColor * Gx[it];
            edgeY += texColor * Gy[it];
        }

        // XY越大,最后结果越小,越可能是边缘点
        half edge = 1 - abs(edgeX) - abs(edgeY);

        return edge;
    }

    fixed4 fragSobel(v2f i) : SV_Target {

        half edge = Sobel(i);

        fixed4 withEdgeColor = lerp(_EdgeColor, tex2D(_MainTex, i.uv[4]), edge);    // 混合边缘颜色和原图颜色,edge越小,越判定为边缘
        fixed4 onlyEdgeColor = lerp(_EdgeColor, _BackgroundColor, edge);            // 混合边缘颜色和背景颜色。
        return lerp(withEdgeColor, onlyEdgeColor, _EdgeOnly);                       // 原图混合还是混合背景颜色的插值。
        }

    ENDCG
} 
作者:l773575310 发表于2017/11/22 21:34:32 原文链接
阅读:53 评论:0 查看评论

Leetcode——728. Self Dividing Numbers

$
0
0

题目链接

题面:
A self-dividing number is a number that is divisible by every digit it contains.

For example, 128 is a self-dividing number because 128 % 1 == 0, 128 % 2 == 0, and 128 % 8 == 0.

Also, a self-dividing number is not allowed to contain the digit zero.

Given a lower and upper number bound, output a list of every possible self dividing number, including the bounds if possible.

Example 1:
Input:
left = 1, right = 22
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
Note:

The boundaries of each input argument are 1 <= left <= right <= 10000.

解题:
直接模拟即可。

class Solution {
public:
    bool flag=false,is_ok[10001];
    bool judge(int x)
    {
        int t=x;
        while(x)
        {
            if(x%10==0)return false;
            if(t%(x%10))return false;
            x/=10;
        }
        return true;
    }
    void cal()
    {
        for(int i=1;i<=10000;i++)
        {
            if(judge(i))
                is_ok[i]=1;
            else
                is_ok[i]=0;
        }
        flag=true;
    }
    vector<int> selfDividingNumbers(int left, int right) {
        vector <int> res;
        if(!flag){
            cal();
        }
        for(int i=left;i<=right;i++)
        {
            if(is_ok[i])
            res.push_back(i);
        }
        return res;
    }
};
作者:David_Jett 发表于2017/11/22 21:40:25 原文链接
阅读:76 评论:0 查看评论

visual studio(VS2015)路径和工程属性设置

$
0
0

visual studio(VS2015)路径和工程属性设置
VS 2015新建一个工程,右键属性,打开**工程属性页。
1.常规选项:
这里写图片描述
a)输出目录
输出目录就是.exe,.ilk,*.pdb文件所在目录:(SolutionDir)(Configuration)\
其中:
$(SolutionDir)为解决方案所在目录,D:\MY_Projects\TestDLL1

$(Configuration)如果是debug模式则为Debug,如果是release模式就是Release。

b)中间目录
中间目录就是生成的临时文件目录,$(Configuration)\的意思是临时文件放在当前工程目录的Debug或则Release文件夹下面
c)平台工具集
平台工具集设置成”Visual Studio 2015-Windows XP(v140_xp)”,这样就可以保证编译的程序在windows系统中也能够运行。
d)字符集
unicode和多字节字符集是两种不同的编码方式,不同的编码方式下,所对应的一些函数是不兼容的。一种编码格式,Unicode 2个字节表示所有的字符,多字节是一个字节表示英文,两个就表示汉字。
如果你新的工程是Unicode的,就用Unicode开发,摒弃多字节编码,多字节编码弊端太多了。
其实改起来很简单,你把所有的char都改成TCHAR,如果能用CString,尽量用CString。所有字符串函数都换上带_t的版本,比如_tsprintf()、_tcscpy之类的……因为这些东西都是同时兼容Unicode和ANSI的,所以改起来很容易。
工程到底会以哪种编码方式去编码,是根据根据“项目属性”中配置的预编译宏UNICODE来决定的。
Unicode是一种编码表格,例如,一个汉字规定一个代码,类似GB2312-1980;UTF-8并不是一种编码方式,而只是一种传送和存储的格式,网页文本保存为utf-8格式,就不会出现乱码。传输UTF-8需要一个字节,而unicode传输需要两个字节快,因此,UTF8-8传输速度高于unicode,它是为了传输unicode而想出来的再编码方法。
2.调试选项
a)命令参数
使用调试时从哪里启动exe文件,默认(TargetPath)(SolutionDir)$(Configuration)\。

b)工作目录
默认$(ProjectDir),表示工程文件目录。【工作目录】表示进行某项操作的目的目录,会随着OpenFileDialog、SaveFileDialog等对象所确定的目录而改变。
“工作目录”属性作用是程序运行后唯一识别的默认目录,是程序运行过程中默认读取的目录,代码中用GetCurrentDirectory之类的函数获取,工作后只认识这个目录。
3.C/C++选项
a)常规选项——附加包含目录:引用头文件(*.h)所在的路径
b)预处理器
这里写图片描述
如上图中,在这里,WIN32、_DEBUGE、_UNICODE等其实是一些宏定义,在这里写上这些,相当于在本工程所有的文件中都写上了:

#define WIN32
#define _DEBUG
#define _UNICODE

这样,就可以达到一个多一个同一个代码在不同的配置环境在编译的结果文件不一样,从而实现跨平台。比如,在VC中,因为要有的环境是UNICODE,有些则不是,同一份代码为了在两种环境下都可以用,那么就会有以下宏定义(其实这就是twhar.h中的代码):

#ifdef  _UNICODE
typedef wchar_t     TCHAR;
#define __T(x)      L##x
#define _T(x)       __T(x)
#else
#define __T(x)      x
typedef char            TCHAR;
#endif 

那么,当你的环境中写了UNICODE时,这一段就会编译:

#define __T(x)      L##x
#define _T(x)       __T(x)

如果没有写UNICODE,那么上面这段就不编译,而是下面这段被编译:

#define __T(x)      x

这样,只要你的字符串用了_T(“somechar”),那么,在有UNICODE的时候,就是L”somechar”;在没有UNICODE在时候,就是它本身”somechar”了。
c)预编译头
不使用预编译头,如果使用容易出现各种错误。
4.链接器选项
a)常规——输出文件,默认值为:(OutDir)$(ProjectName){TargetExt}
TargetExt.exe.dll(OutDir)就是配置属性-》常规下面的输出目录路径,本文中配置为:(SolutionDir)(Configuration)\。
注意:输出文件最好配置成根调试路径(调试–》命令参数的属性值)在一个目录。
b)常规——附加库目录为“..\lib”,它指的是引用第三方库lib文件所在目录:
c)高级——导入库,动态链接库项目生成的lib文件所在的目录。
这里写图片描述

作者:haimianjie2012 发表于2017/11/22 21:55:02 原文链接
阅读:76 评论:0 查看评论

LeetCode 分类练习(1)—— 在数组中移动指定元素、删除指定元素、删除重复元素

$
0
0

283. Move Zeroes

Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.

For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].

Note:
You must do this in-place without making a copy of the array.
Minimize the total number of operations.

将数组中的 0 移动到数组末尾,保持非零元素的原有顺序。

必须原地进行。

package com.leetcode.array;

// 283 MoveZeroes

public class MoveZeroes {
    // version-1 时间复杂度 O(n) , 空间复杂度 O(n)
//    public static int[] moveZeroes(int[] nums) {
//        int n = nums.length;
//        int[] aux = new int[n];
//        int k = 0;
//        for (int i = 0; i < n; i++)
//            if (nums[i] != 0)
//                aux[k++] = nums[i];
//        while (k < n)
//            aux[k++] = 0;
//        return aux;
//    }

    // version-2 时间复杂度 O(n),空间复杂度 O(1)
//    public static void moveZeroes(int[] nums) {
//        int n = nums.length;
//        int k = 0;  // nums[0...k) != 0     nums[k...i) == 0
//        for (int i = 0; i < n; i++)
//            if (nums[i] != 0)
//                if (i != k) // 防止整个数组全部是非0元素
//                    swap(nums, i, k++);
//                else
//                    k++;
//
//    }

    public static void moveZeroes(int[] nums) {
//        int n = nums.length;
//        int k = 0;
//        for (int i = 0; i < n; i++) {
//            if (nums[i] != 0)
//                nums[k++] = nums[i];
//        }
//        while (k < n)
//            nums[k++] = 0;

        int k = 0;
        for (int num:nums)
            if (num > 0)
                nums[k++] = num;
        while (k<nums.length)
            nums[k++] = 0;
    }

    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

    public static void main(String[] args) {
        int[] nums = {0, 1, 0, 3, 12};
//        int[] nums = {2, 1};

//        int[] aux = MoveZeroes.moveZeroes(nums);
        MoveZeroes.moveZeroes(nums);
        for (int num : nums)
            System.out.println(num);
    }

}

27. Remove Element

Given an array and a value, remove all instances of that value in-place and return the new length.

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

The order of elements can be changed. It doesn't matter what you leave beyond the new length.

移除数组中全部指定值,返回数组的新长度。

不许使用额外空间。

数组中元素的顺序可以改变。

package com.leetcode.array;

// 27 RemoveElement

public class RemoveElement {
    public int removeElement(int[] nums, int val) {
//        int n = nums.length;
//        int k = 0;
//        for (int i = 0; i < n; i++) {
//            if (nums[i] != val)
//                nums[k++] = nums[i];
//        }
//        return k;

        int k = 0;
        for (int num : nums)
            if (num != val)
                nums[k++] = num;
        return k;
    }

}

26. Remove Duplicates from Sorted Array

Given a sorted array, remove the duplicates in-place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

给出一个已排序的数组,移除重复的元素,保证每个元素只出现一次,返回新的长度。

不允许使用额外空间。

package com.leetcode.array;

// 26 RemoveDuplicates

public class RemoveDuplicates {
    public int removeDuplicates(int[] nums) {
//        int n = nums.length;
//        int k = 0;  // nums[0...k] 为非重复的元素      nums(k...i) 为重复元素
//        for (int i = 0; i < n; i++) {
//            if (nums[i] != nums[k]) {
//                nums[++k] = nums[i];
//            }
//        }
//        return k + 1;

        int k = 0;  // nums[0...k) 元素非重复
        for (int num : nums)
            if (k < 1 || num > nums[k - 1])
                nums[k++] = num;
        return k;
    }

    public static void main(String[] args) {
        int[] nums = {1, 1, 1, 1, 2, 3, 4, 4, 4, 4, 6};
        RemoveDuplicates removeDuplicates = new RemoveDuplicates();
        System.out.println(removeDuplicates.removeDuplicates(nums));
        for (int num : nums)
            System.out.print(num + " ");
    }
}

80. Remove Duplicates from Sorted Array II

Follow up for "Remove Duplicates":
What if duplicates are allowed at most twice?

For example,
Given sorted array nums = [1,1,1,2,2,3],

Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3. It doesn't matter what you leave beyond the new length.

和上一道题差不多,不过每个元素至多出现两次

package com.leetcode.array;

public class RemoveDuplicatesII {

    public int removeDuplicatesII(int[] nums) {
//        int n = nums.length;
//        int k = 0;
//        int count = 0;
//        for (int i = 0; i < n; i++) {
//            if (nums[i] != nums[k]) {
//                nums[++k] = nums[i];
//                count = 1;
//            } else if (nums[i] == nums[k] && count == 0) {
//                count++;
//            } else if (nums[i] == nums[k] && count < 2) {
//                nums[++k] = nums[i];
//                count++;
//            }
//        }
//        return k + 1;

        int i = 0;
        for (int n : nums)
            if (i < 2 || n > nums[i-2])
                nums[i++] = n;
        return i;

    }

    public static void main(String[] args) {
//        int[] nums = {1, 1, 1, 1, 2, 3, 4, 4, 4, 4, 6};
        int[] nums = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4};
//        int[] nums = {};
        RemoveDuplicatesII removeDuplicates = new RemoveDuplicatesII();
        System.out.println(removeDuplicates.removeDuplicatesII(nums));
        for (int num : nums)
            System.out.print(num + "");
    }
}

作者:HeatDeath 发表于2017/11/22 23:32:26 原文链接
阅读:44 评论:0 查看评论

LeetCode 分类练习(2)—— 三向切分 partition 思想的应用

$
0
0

75. Sort Colors

Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.

Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.

Note:
You are not suppose to use the library's sort function for this problem.

假定数组中只有 0,1,2,对此数组进行排序。

package com.leetcode.sort;

public class SortColors {
    // 使用 计数排序
//    public void sortColors(int[] nums) {
//        int[] count = {0, 0, 0};
//        for (int num : nums)
//            count[num]++;
//        int index = 0;
//        int k = 0;
//        for (int n : count) {
//            while (n != 0) {
//                nums[index++] = k;
//                n--;
//            }
//            k++;
//        }
//    }
    // 使用 快速排序的三向切分思想
    public void sortColors(int[] nums) {
        // 假设在 nums[] 的最前端加上一个 nums[-1] = 1
        int lt = -1, i = 0, gt = nums.length;    // [0...lt] == 0  [gt...n-1] == 2
        while (i < gt) {
            if (nums[i] == 0)
                swap(nums, i++, ++lt);
            else if (nums[i] == 1)
                i++;
            else // nums[i] == 2
                swap(nums, i, --gt);
        }
    }

    public void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
//        int[] nums = {1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0};
        int[] nums = {2, 1};
        SortColors sortColors = new SortColors();
        sortColors.sortColors(nums);
        for (int num : nums)
            System.out.print(num + " ");
    }


}

88. Merge Sorted Array

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.

Note:
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively.
package com.leetcode.sort;

import java.util.Arrays;

// 88 Merge Sorted Array

public class MergeSortedArray {
    // 简单的归并排序思路
    public void merge(int[] nums1, int m, int[] nums2, int n) {

//        int[] aux = Arrays.copyOfRange(nums1, 0, m);
//        int i = 0, j = 0;
//        for (int k = 0; k < m + n; k++) {
//            if (i >= m) {
//                nums1[k] = nums2[j];
//                j++;
//            }else if (j >= n){
//                nums1[k] = aux[i];
//                i++;
//            }else if (aux[i] > nums2[j]) {
//                nums1[k] = nums2[j];
//                j++;
//            } else if(aux[i] <= nums2[j]){
//                nums1[k] = aux[i];
//                i++;
//            }
//        }

        int i = m - 1;  // 指向 nums1[] 中数据的末尾
        int j = n - 1;  // 指向 nums2[] 中数据的末尾
        int k = m + n - 1;  // 指向 nums1[] 中需要写入数据的最后一个下标
        while (i >= 0 && j >= 0) {
            if (nums1[i] > nums2[j])
                nums1[k--] = nums1[i--];
            else
                nums1[k--] = nums2[j--];
        }
        while (j >= 0)
            nums1[k--] = nums2[j--];
    }

    // 从后向前 向 nums1[] 数组[m...m+n-1]区间内填充数据,不需要额外空间
    // 即使 nums2[] 中的数据先被用尽,nums2[] 中原有的数据也是相对有序的
//    public void merge(int nums1[], int m, int nums2[], int n) {
//        int i = m - 1;  // 指向 nums1[] 中数据的末尾
//        int j = n - 1;  // 指向 nums2[] 中数据的末尾
//        int k = m + n - 1;  // 指向 nums1[] 中需要写入数据的最后一个下标
//        while (i >= 0 && j >= 0)    // 当 nums1 和 nums2 中还有数据时,向 num1[k] 中存入较大的数据
//            nums1[k--] = (nums1[i] > nums2[j]) ? nums1[i--] : nums2[j--];
//        while (j >= 0)  // 当原来 nums1[] 中的数据用尽后,将 nums2 中剩下的数据存入 nums1 中
//            nums1[k--] = nums2[j--];
//    }

    public static void main(String[] args) {
        int[] nums1 = {6, 7, 0, 0, 0};
        int m = 2;
        int[] nums2 = {2};
        int n = 1;
//        int[] nums1 = {1};
//        int m = 1;
//        int[] nums2 = {};
//        int n = 0;
        MergeSortedArray mergeSortedArray = new MergeSortedArray();
        mergeSortedArray.merge(nums1, m, nums2, n);
        for (int num : nums1)
            System.out.print(num + " ");
    }
}

215. Kth Largest Element in an Array

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,
Given [3,2,1,5,6,4] and k = 2, return 5.

Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.
package com.leetcode.sort;

// 215 FindKthLargest

public class FindKthLargest {
    public int findKthLargest(int[] nums, int k) {
        int n = nums.length;
        return solve(nums, 0, n - 1, k-1);
    }

    private int solve(int[] nums, int l, int r, int target) {
        int p = partition(nums, l, r);
        if (p == target)
            return nums[p];
        else if (p > target)
            return solve(nums, l, p-1, target);
        else
            return solve(nums, p+1, r, target);
    }

    private int partition(int[] nums, int l, int r) {
        int temp = nums[l];
        int i = l + 1, j = l;
        for (; i <= r; i++) {
            if (nums[i] > temp)
                swap(nums, i, ++j);
        }
        swap(nums, l, j);
        return j;
    }

    private void swap(int[] nums, int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }

    public int[] generateRandomArray(int n, int rangeL, int rangeR) {
        int[] arr = new int[n];
        for (int i = 0; i < n; i++)
            arr[i] = ((int)(Math.random() * (rangeR - rangeL + 1) + rangeL));
        return arr;
    }

    public static void main(String[] args){
        FindKthLargest findKthLargest = new FindKthLargest();
        int[] nums = findKthLargest.generateRandomArray(10, 0, 30);
        for (int num: nums)
            System.out.print(num + " ");
        System.out.println();

        int target = 3;
        System.out.print(findKthLargest.findKthLargest(nums, target));
        System.out.println();

//        QuickSort.sort(nums);
//        for (int num: nums)
//            System.out.print(num + " ");
//        System.out.println();

    }

}
作者:HeatDeath 发表于2017/11/22 23:53:46 原文链接
阅读:46 评论:0 查看评论

【YFMemoryLeakDetector】人人都能理解的 iOS 内存泄露检测工具类

$
0
0

背景

即使到今天,iOS 应用的内存泄露检测,仍然是一个很重要的主题。我在一年前,项目中随手写过一个简单的工具类,当时的确解决了大问题。视图和控制器相关的内存泄露,几乎都不存在了。后来想着一直就那个工具,写一篇文章,不过一直没有写。

时过境迁,今天在网上搜了下 “iOS 内存泄露检测”,各种讨论技术文章,有点头大。我忍不住看了下自己当时的代码,突然感觉自己的思路好特别,好有创意。我真的就是在“创建”时把数据记录到一个字典里,在“释放”时,从字典里移出对象;所谓的检测,其实就是打印那个字典,仍然在字典中的很有可能就是泄露喽。

当然,还是有一些技术细节的。我把旧代码适度拆分整理为一个开源库了,取名为 YFMemoryLeakDetector。本篇,将着重讲述简洁之下,可能不易察觉的一些考量。

注意:这个库,相当程度上是为当时的项目量身定制的,你可能需要适当修改,才能在自己的项目中真正发挥出它的力量。

核心技术分析

AOP 机制,借助 Aspects 库实现

Aspects 这个库的基本用法,我专门说过,大家可以参考 Aspects– iOS的AOP面向切面编程的库。当然,用黑魔法直接操作运行时,也是很酷的。不过我当时的确是因为偷懒,才用的 Aspects。一直到现在,我依然觉得,它可能比黑魔法更可靠些。

在字典中直接存储指针地址,而不是直接存储对象自身

存储指针地址的好处是,就是不会因为存储本身影响对象的引用计数。当然,指针地址本身,在 OC 中,其实就是对象自身。而要想得到存地址,不存对象的效果,就要祭出整个工具库的灵魂函数:

NSValue * key = [NSValue valueWithPointer: (__bridge const void * _Nullable)(info.instance)];

将对象转换为 NSValue,直接以 NSValue 为键,来标记对象。这句代码,是整个机制的灵魂所在,也是比其他类似的内存泄露分析库更简洁的重要原因之一。我当时也是搜遍的整个网络,才知道自己要的究竟是什么。

另外,还有一点必须提一下, NSValue 是可以在反向转换为 oc 对象的,这有利于你在拿到工具库提供的泄露信息后,进一步定位和分析问题:

UIViewController * vc = (UIViewController *)[key pointerValue];

对控制器和视图,采用不同的拦截策略

  • 对象销毁,统一拦截的是 dealloc。现在网上的很多策略,基本也是这样。
  • 对象创建,对于视图,拦截的是 willMoveToSuperview: ;对于控制器拦截的是 viewDidLoad 。直到现在,我依然以为,没有调用过这两个方法的视图或控制器对象,本身没有多大的拦截价值。当然,这依然因项目而异。作为一个工具类,只要它能解决大多数场景下的问题,我觉得就可以了。

load 时,自动开启监测

所以,你只要把工具库源码拖拽到项目中,不需要任何修改,就可以自动监测内存泄露情况了。然后在需要的地方,在合适的时候,去读取 YFMemoryLeakDetector 的单例属性,分析结果即可。当然,这是我今天重构优化过的版本。原来是需要手动初始化的,好 Low,当时写的!

+ (void)load
{
    [[YFMemoryLeakDetector sharedInstance] setup];
}

“见码如晤”

YFMemoryLeakDetector.h 头文件部分,主要简化为暴露了存储可能有内存泄露情况的视图和控制器的字典属性;同时提供了一个单例方法,以便于具体分析和操作内存分析情况。

#import <Foundation/Foundation.h>

/**
 *  分析页面和页面内视图是否有内存泄露的情况.
 */
@interface  YFMemoryLeakDetector: NSObject

#pragma mark - 属性.

/*
  已加载,但尚未正确释放,有内存风险的控制器对象.

 以指针地址为key,以对象字符串为值.所以不用担心因为记录本身而引起的内存泄露问题.

 必要时,可以使用类似 (UIViewController *)[key pointerValue] 的语法来获取原始的 OC对象来进一步做些过滤操作.
 */
@property (strong, atomic) NSMutableDictionary * loadedViewControllers;

/*
 已加载,但尚未正确释放,有内存风险的视图对象.

 以指针地址为key,以对象字符串为值.所以不用担心因为记录本身而引起的内存泄露问题.

 必要时,可以使用类似 (UIView *)[key pointerValue] 的语法来获取原始的 OC对象来进一步做些过滤操作.
 */
@property (strong, atomic) NSMutableDictionary * loadedViews; //!< 已加载的视图.



#pragma mark - 单例方法.
+(YFMemoryLeakDetector *) sharedInstance;
@end

YFMemoryLeakDetector.m 实现,借助于 AspectsvalueWithPointer: 代码大大简化。

#import <objc/runtime.h>
#import <UIKit/UIKit.h>

#import "YFMemoryLeakDetector.h"
#import "Aspects.h"

@interface  YFMemoryLeakDetector()
@end

@implementation  YFMemoryLeakDetector

static YFMemoryLeakDetector * sharedLocalSession = nil;

+ (void)load
{
    [[YFMemoryLeakDetector sharedInstance] setup];
}

+(YFMemoryLeakDetector *) sharedInstance{
    @synchronized(self){
        if (sharedLocalSession == nil) {
            sharedLocalSession = [[self alloc] init];
        }
    }
    return  sharedLocalSession;
}


- (void)setup
{
    self.loadedViewControllers = [NSMutableDictionary dictionaryWithCapacity: 42];
    self.loadedViews = [NSMutableDictionary dictionaryWithCapacity:42];

    /* 控制器循环引用的检测. */
    [UIViewController aspect_hookSelector:@selector(viewDidLoad) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> info) {
        NSValue * key = [NSValue valueWithPointer: (__bridge const void * _Nullable)(info.instance)];

        [self.loadedViewControllers setObject:[NSString stringWithFormat:@"%@", info.instance] forKey:key];
    }error:NULL];

    [UIViewController aspect_hookSelector:NSSelectorFromString(@"dealloc") withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info) {
        NSValue * key = [NSValue valueWithPointer: (__bridge const void * _Nullable)(info.instance)];

        [self.loadedViewControllers removeObjectForKey: key];
    }error:NULL];

    /* 视图循环引用的检测. */
    /* 只捕捉已经从父视图移除,却未释放的视图.以指针区分. */
    [UIView aspect_hookSelector:@selector(willMoveToSuperview:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info, UIView * superview){
        /* 过滤以 _ 开头的私有类. */
        NSString * viewClassname = NSStringFromClass(object_getClass(info.instance));
        if ([viewClassname hasPrefix:@"_"]) {
            return;
        }

        /* 兼容处理使用了KVO机制监测 delloc 方法的库,如 RAC. */
        if ([viewClassname hasPrefix:@"NSKVONotifying_"]) {
            return;
        }

        NSValue * key = [NSValue valueWithPointer: (__bridge const void * _Nullable)(info.instance)];

        /* 从父视图移除时,就直接判定为已释放.
         这样做的合理性在于:当视图从父视图移除后,一般是很难再出发循环引用的条件了,所以可适度忽略.
         */
        if (!superview) {
            [self.loadedViews removeObjectForKey: key];
        }

        NSMutableDictionary * obj = [self.loadedViews objectForKey: key];

        if (obj) { /* 一个 UIView 视图,只记录一次即可.因为一个UIView,最多只被 delloc 一次. */
            return;
        }

        [self.loadedViews setObject: [NSString stringWithFormat:@"%@", info.instance] forKey:key];

        /* 仅对有效实例进行捕捉.直接捕捉类对象,会引起未知崩溃,尤其涉及到和其他有KVO机制的类库配合使用时. */
        [info.instance aspect_hookSelector:NSSelectorFromString(@"dealloc") withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info){
            [self.loadedViews removeObjectForKey: key];
        }error:NULL];
    }error:NULL];
}
@end

使用示例:

这里展示一个基于工具类,二次分析的示例:

YFMemoryLeakDetector * memoryLeakDetector = [YFMemoryLeakDetector sharedInstance];

/* 控制器检测结果的输出. */
[memoryLeakDetector.loadedViewControllers enumerateKeysAndObjectsUsingBlock:^(NSValue *  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
    UIViewController * vc = (UIViewController *)[key pointerValue];
    if (!vc.parentViewController) { /* 进一步过滤掉有父控制器的控制器. */
        NSLog(@"有内存泄露风险的控制器: %@", obj);
    }
}];

/* 视图检测结果的输出. */
[memoryLeakDetector.loadedViews enumerateKeysAndObjectsUsingBlock:^(NSValue *  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
    UIView * view = (UIView *)[key pointerValue];
    if (!view.superview) { /* 进一步过滤掉有父视图的视图,即只输出一组视图的根节点,这样便于更进一步定位问题. */
        NSLog(@"有内存泄露风险的视图: %@", obj);
    }
}];

参考文章

作者:sinat_30800357 发表于2017/11/23 1:27:54 原文链接
阅读:53 评论:0 查看评论

剑指offer 反转链表

$
0
0

对于链表的反转,同样需要考虑一些问题:

  • 代码的鲁棒性,输入链表头指针是否为NULL
  • 修改链表中指针的指向时,千万不要发生链表断裂的情况,导致下一个结点丧失
  • 仔细考虑问题解决的逻辑,不要急于下笔
  • 写完代码之后花时间进行简单的测试用例(单元测试),确保万无一失
#include <iostream>  
#include <string>  
#include <vector>  
#include <stack>
using namespace std;  

typedef int datatype;

struct Node
{
	datatype value;
	Node* Next_Node;
};

//反转链表
//这样做修改了传入的链表
Node* Reverse_List(Node* first)
{

	Node* m_Node = first;
	Node* previous_Node = nullptr;
	Node* Reverse_Head = nullptr;

	//传入参数鲁棒性考虑
	if (first == nullptr)
	{
		return nullptr;
	}
	//只有一个结点的情况
	if (first->Next_Node == nullptr)
	{
		Reverse_Head = first;
		return Reverse_Head;
	}


	while (m_Node != nullptr)
	{
		Node* Next_Node = m_Node->Next_Node;
		if (m_Node == nullptr)
		{
			Reverse_Head = m_Node;
		}

		m_Node->Next_Node = previous_Node;
		previous_Node = m_Node;
		m_Node = Next_Node;

	}
}

void main()  
{     

	system("pause");
}  


作者:misayaaaaa 发表于2017/11/23 8:54:03 原文链接
阅读:45 评论:0 查看评论

leetcode: 98. Validate Binary Search Tree

$
0
0

Q

Given a binary tree, determine if it is a valid binary search tree (BST).

Assume a BST is defined as follows:

The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.

Example 1:

    2
   / \
  1   3

Binary tree [2,1,3], return true.

Example 2:

    1
   / \
  2   3

Binary tree [1,2,3], return false.

AC

# Definition for a binary tree node.
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def isValidBST(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        if not root:
            return True
        a, b, c= self.recurse(root)
        return c

    def recurse(self, root):
        if not root.left and not root.right:
            return (root.val, root.val, True)
        min_ = root.val
        max_= root.val
        if root.left:
            if root.val<=root.left.val:
                return (None, None, False)
            else:
                _min, _max, ok = self.recurse(root.left)
                if not ok:
                    return (None, None, False)
                if _max>=root.val:
                    return (None, None, False)
                min_= min(min_, _min)
        if root.right:
            if root.val>=root.right.val:
                return (None, None, False)
            else:
                _min, _max, ok = self.recurse(root.right)
                if not ok:
                    return (None, None, False)
                if _min<=root.val:
                    return (None, None, False)
                max_= max(max_, _max)
        return (min_, max_, True)


# Time:  O(n)
# Space: O(1)
# Definition for a  binary tree node
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

# Morris Traversal Solution
class Solution2(object):
    def isValidBST(self, root):
        prev, cur = None, root
        while cur:
            if cur.left is None:
                if prev and prev.val >= cur.val:
                    return False
                prev = cur
                cur = cur.right
            else:
                node = cur.left
                while node.right and node.right != cur:
                    node = node.right

                if node.right is None:
                    node.right = cur
                    cur = cur.left
                else:
                    if prev and prev.val >= cur.val:
                        return False
                    node.right = None
                    prev = cur
                    cur = cur.right
        return True


# Time:  O(n)
# Space: O(h)
class Solution3(object):
    def isValidBST(self, root):
        return self.isValidBSTRecu(root, float("-inf"), float("inf"))

    def isValidBSTRecu(self, root, low, high):
        if root is None:
            return True

        return low < root.val and root.val < high \
               and self.isValidBSTRecu(root.left, low, root.val) \
               and self.isValidBSTRecu(root.right, root.val, high)


if __name__ == "__main__":
    root, root.left, root.right = TreeNode(2), TreeNode(1), TreeNode(3)
    assert Solution().isValidBST(root) == True


作者:JNingWei 发表于2017/11/23 9:00:14 原文链接
阅读:22 评论:0 查看评论

剑指offer 合并链表

$
0
0

合并排序好的两个链表,同样需要注意一下问题:

  • 代码鲁棒性(对NULL等特殊输入有对应)
  • 代码正确性(没有链表断裂的情况)
  • 对于链表的大量指针操作,一定要将指针的命名对应其意义,尽量不出错
  • 合并链表还可以用递归的方式进行

#include <iostream>  
#include <string>  
#include <vector>  
#include <stack>
using namespace std;  

typedef int datatype;

struct Node
{
	datatype value;
	Node* Next_Node;
};

//合并链表
//确定是从大到小还是从小到大?(从小打大)
Node* Reverse_List(Node* ListHead1,Node *ListHead2)
{
	//特殊输入考虑
	if (ListHead1 == nullptr || ListHead2 == nullptr)
	{
		return nullptr;
	}

	if (ListHead1 == nullptr && ListHead2 != nullptr)
	{
		return ListHead2;
	}
	if (ListHead1 != nullptr && ListHead2 == nullptr)
	{
		return ListHead1;
	}

	//临时结点生成
	Node* List1_temp = ListHead1;
	Node* List2_temp = ListHead2;
	Node* List3_temp = nullptr;
	Node* ListHead3 = nullptr;

	if (List1_temp->value > List2_temp->value)
	{
		ListHead3 = List2_temp;
		List2_temp = List2_temp->Next_Node;
	}
	else
	{
		ListHead3 = List1_temp;
		List1_temp = List1_temp->Next_Node;
	}
	ListHead3->Next_Node = List3_temp;

	while (List1_temp->Next_Node != nullptr && List2_temp->Next_Node != nullptr)
	{
		if (List1_temp->value > List2_temp->value)
		{
			List3_temp = List2_temp;
			List2_temp = List2_temp->Next_Node;
		}
		else
		{
			List3_temp = List1_temp;
			List1_temp = List1_temp->Next_Node;
		}
	}

	return ListHead3;
	
}

void main()  
{     

	system("pause");
}  

作者:misayaaaaa 发表于2017/11/23 9:00:17 原文链接
阅读:16 评论:0 查看评论

leetcode: 99. Recover Binary Search Tree

$
0
0

Q

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

AC

# Definition for a binary tree node.
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def recoverTree(self, root):
        """
        :type root: TreeNode
        :rtype: void Do not return anything, modify root in-place instead.
        """
        self.lefty = None
        self.righty = None
        self._minnode = None
        self._maxnode = None
        self.preorder_visit(root)
        self.postorder_visit(root)
        # print self.lefty, self.righty
        self.lefty.val, self.righty.val = self.righty.val, self.lefty.val

    def preorder_visit(self, node):
        # first check left and right trees
        if node.left:
            self.preorder_visit(node.left)
            if self.lefty:
                return
        if self._maxnode and node.val<self._maxnode.val:
            self.lefty = self._maxnode
            return
        if not self._maxnode or node.val > self._maxnode.val:
            self._maxnode = node
        if node.right:
            self.preorder_visit(node.right)

    def postorder_visit(self, node):
        # first check left and right trees
        if node.right:
            self.postorder_visit(node.right)
            if self.righty:
                return
        if self._minnode and node.val > self._minnode.val:
            self.righty = self._minnode
            return
        if not self._minnode or node.val < self._minnode.val:
            self._minnode = node
        if node.left:
            self.postorder_visit(node.left)


# Time:  O(n)
# Space: O(1)
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

    def __repr__(self):
        if self:
            serial = []
            queue = [self]

            while queue:
                cur = queue[0]

                if cur:
                    serial.append(cur.val)
                    queue.append(cur.left)
                    queue.append(cur.right)
                else:
                    serial.append("#")

                queue = queue[1:]

            while serial[-1] == "#":
                serial.pop()

            return repr(serial)

        else:
            return None

class Solution2(object):
    def recoverTree(self, root):
        return self.MorrisTraversal(root)

    def MorrisTraversal(self, root):
        if root is None:
            return
        broken = [None, None]
        pre, cur = None, root

        while cur:
            if cur.left is None:
                self.detectBroken(broken, pre, cur)
                pre = cur
                cur = cur.right
            else:
                node = cur.left
                while node.right and node.right != cur:
                    node = node.right

                if node.right is None:
                    node.right =cur
                    cur = cur.left
                else:
                    self.detectBroken(broken, pre, cur)
                    node.right = None
                    pre = cur
                    cur = cur.right

        broken[0].val, broken[1].val = broken[1].val, broken[0].val

        return root

    def detectBroken(self, broken, pre, cur):
        if pre and pre.val > cur.val:
            if broken[0] is None:
                broken[0] = pre
            broken[1] = cur


if __name__ == "__main__":
    root, root.left = TreeNode(0), TreeNode(1)
    assert Solution().recoverTree(root) == None


作者:JNingWei 发表于2017/11/23 9:01:40 原文链接
阅读:26 评论:0 查看评论

leetcode: 100. Same Tree

$
0
0

Q

Given two binary trees, write a function to check if they are the same or not.

Two binary trees are considered the same if they are structurally identical and the nodes have the same value.

Example 1:

Input:     1         1
      / \       / \
     2   3     2   3

    [1,2,3],   [1,2,3]

Output: true

Example 2:

Input:     1         1
      /           \
     2             2

    [1,2],     [1,null,2]

Output: false

Example 3:

Input:     1         1
      / \       / \
     2   1     1   2

    [1,2,1],   [1,1,2]

Output: false

AC

# Definition for a binary tree node.
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """
        stack = [(p, q)]
        while stack:
            node1, node2 = stack.pop()
            if not node1 and not node2:
                continue
            if None in (node1, node2) or node1.val != node2.val:
                return False
            if node1.val == node2.val:
                stack.append((node1.left, node2.left))
                stack.append((node1.right, node2.right))
        return True


# Time:  O(n)
# Space: O(h), h is height of binary tree
# Definition for a  binary tree node
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution2(object):
    def isSameTree(self, p, q):
        if p is None and q is None:
            return True
        if p is not None and q is not None:
            return p.val == q.val and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
        return False


if __name__ == "__main__":
    root1, root1.left, root1.right = TreeNode(1), TreeNode(2), TreeNode(3)
    root2, root2.left, root2.right = TreeNode(1), TreeNode(2), TreeNode(3)
    assert Solution().isSameTree(root1, root2) == True


作者:JNingWei 发表于2017/11/23 9:02:15 原文链接
阅读:28 评论:0 查看评论

Qt--JSON

$
0
0

JSON是一种来自Javascript的对象数据的编码格式,现在被广泛用作互联网上的数据交换格式。

json数据类型有bool、double、string、object、array、null
json对象使用{key:value,…}格式保存
json数组以[]括起来表示

Qt自然也提供了对json的读写支持
相关的类有

#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>

下面以一个实例给出这几个类的用法

例子中假设我们需要保存一个4画面的ui布局,还有其他一些相关信息。
保存json格式如下:

{
"bShowTitle": true,
"fps": 25,
"username": "admin",
"wnds": [
    {
        "bVisible": true,
        "h": 300,
        "w": 400,
        "wndid": 1,
        "x": 0,
        "y": 0
    },
    {
        "bVisible": true,
        "h": 300,
        "w": 400,
        "wndid": 2,
        "x": 400,
        "y": 0
    },
    {
        "bVisible": true,
        "h": 300,
        "w": 400,
        "wndid": 3,
        "x": 0,
        "y": 300
    },
    {
        "bVisible": true,
        "h": 300,
        "w": 400,
        "wndid": 4,
        "x": 400,
        "y": 300
    }
]
}

我们使用Qt提供的json类来解析和生成这个json文件

#ifndef HSAVEUI_H
#define HSAVEUI_H

#include <QString>
#include <QFile>

#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>

struct WndInfo{
    int wndid;
    int x;
    int y;
    int w;
    int h;
    bool bVisible;
};

struct MonitorUI{
    QString username;
    int fps;
    bool bShowTitle; // 是否显示标题
    WndInfo wnds[4];
};

class HSaveUI
{
public:
    HSaveUI(QString filepath){
        m_filepath = filepath;
    }

public:
   bool read(MonitorUI& ui){
        QFile file(m_filepath);
        if (!file.open(QIODevice::ReadOnly)){
            qWarning("could not open file:%s!", m_filepath.toLocal8Bit().data());
            return false;
        }


        QJsonParseError err;
        QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err);
        if (err.error != QJsonParseError::NoError){
            qWarning("Parse err:%d %s!", err.error, err.errorString().toLocal8Bit().data());
            return false;
        }

        QJsonObject obj = doc.object();
        ui.username = obj["username"].toString();
        ui.bShowTitle = obj["bShowTitle"].toBool();
        ui.fps = obj["fps"].toInt();
        QJsonArray arr = obj["wnds"].toArray();
        for (int i = 0; i < arr.size(); ++i){
            QJsonObject wnd = arr[i].toObject();
            ui.wnds[i].wndid = wnd["wndid"].toInt();
            ui.wnds[i].bVisible = wnd["bVisible"].toBool();
            ui.wnds[i].x = wnd["x"].toInt();
            ui.wnds[i].y = wnd["y"].toInt();
            ui.wnds[i].w = wnd["w"].toInt();
            ui.wnds[i].h = wnd["h"].toInt();
        }

        return true;
   }

   bool write(MonitorUI& ui){
        QJsonArray wnds;
        for (int i = 0; i < 4; ++i){
            QJsonObject wnd;
            wnd["wndid"] = ui.wnds[i].wndid;
            wnd["bVisible"] = ui.wnds[i].bVisible;
            wnd["x"] = ui.wnds[i].x;
            wnd["y"] = ui.wnds[i].y;
            wnd["w"] = ui.wnds[i].w;
            wnd["h"] = ui.wnds[i].h;
            wnds.append(wnd);
        }

        QJsonObject obj;
        obj["username"] = ui.username;
        obj["bShowTitle"] = ui.bShowTitle;
        obj["fps"] = ui.fps;
        obj["wnds"] = wnds;

        QJsonDocument doc;
        doc.setObject(obj);

        QByteArray json = doc.toJson();

        QFile file(m_filepath);
        if (!file.open(QIODevice::WriteOnly)){
            qWarning("could not save file!");
            return false;
        }
        file.write(json);
        return true;
   }

private:
   QString m_filepath;
};

#endif // HSAVEUI_H

QJsonDocment的fromJson方法可以解析json字符串,object方法返回json对象,toJson方法构造一个json格式字符串

QJsonObject通过key索引即可得到value,如obj[“username”]
QJsonValue用来封装json的value,QJsonValue类中提供了如下转换方法

bool toBool(bool defaultValue = false) const;
int toInt(int defaultValue = 0) const;
double toDouble(double defaultValue = 0) const;
QString toString() const;
QString toString(const QString &defaultValue) const;
QJsonArray toArray() const;
QJsonArray toArray(const QJsonArray &defaultValue) const;
QJsonObject toObject() const;

QJsonArray表示json数组,通过size方法可以获取到数组大小,[]索引方法获取到每一个数组元素

作者:GG_SiMiDa 发表于2017/11/23 15:49:44 原文链接
阅读:176 评论:0 查看评论

Spring之—— java.sql.SQLException: Lock wait timeout exceeded | CannotAcquireLockException 的解决

$
0
0

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/78615736

一、错误信息

错误日志如下:

2017-11-23 15:20:31 XmlBeanDefinitionReader [INFO] Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
2017-11-23 15:20:31 SQLErrorCodesFactory [INFO] SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
2017-11-23 15:20:31 ExceptionUtil [ERROR] SqlMapClient OrderItem; SQL [];   
--- The error occurred in com/defonds/syncpath/dao/OrderItem.xml.  
--- The error occurred while applying a parameter map.  
--- Check the OrderItem.updateShareStatus-InlineParameterMap.  
--- Check the statement (update failed).  
--- Cause: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:   
--- The error occurred in com/defonds/syncpath/dao/OrderItem.xml.  
--- The error occurred while applying a parameter map.  
--- Check the OrderItem.updateShareStatus-InlineParameterMap.  
--- Check the statement (update failed).  
--- Cause: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
org.springframework.dao.CannotAcquireLockException: SqlMapClient OrderItem; SQL [];   
--- The error occurred in com/defonds/syncpath/dao/OrderItem.xml.  
--- The error occurred while applying a parameter map.  
--- Check the OrderItem.updateShareStatus-InlineParameterMap.  
--- Check the statement (update failed).  
--- Cause: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:   
--- The error occurred in com/defonds/syncpath/dao/OrderItem.xml.  
--- The error occurred while applying a parameter map.  
--- Check the OrderItem.updateShareStatus-InlineParameterMap.  
--- Check the statement (update failed).  
--- Cause: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
  at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:244)
  at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
  at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:212)
  at com.defonds.frameworkcommons.dao.BaseDaoImpl.execute(BaseDaoImpl.java:31)
  at com.defonds.frameworkcommons.dao.BaseDaoImpl.update(BaseDaoImpl.java:97)
  at com.defonds.syncpath.service.OrderItem.impl.OrderItemServiceImpl.revokeSharedFolder(OrderItemServiceImpl.java:287)
  at com.defonds.syncpath.service.share.impl.ShareServiceImpl.handleRevokeSharedFolder(ShareServiceImpl.java:312)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  at java.lang.reflect.Method.invoke(Method.java:597)
  at com.defonds.interfaceframework.controller.Action.invokeMethod(Action.java:256)
  at com.defonds.interfaceframework.controller.Action.execute(Action.java:206)
  at com.defonds.interfaceframework.controller.DispatcherServlet.service(DispatcherServlet.java:144)
  at com.defonds.syncpath.common.ArcSyncDispatcherServlet.service(ArcSyncDispatcherServlet.java:51)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
  at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
  at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
  at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
  at java.lang.Thread.run(Thread.java:619)

二、分析原因

Spring 事务嵌套造成死锁。OrderServiceImpl 里嵌入了 OrderItemService:

private OrderItemService orderItemService;
OrderServiceImpl 的 delete 方法里对 MySQL 的 Order 表有操作,而 OrderItemService 里的 revokeSharedFolder 方法也对同一张表有更新操作。事务嵌套,造成死锁。

三、解决方案

当前调用事务的方法设置为 Propagation.SUPPORTS:

@Transactional(propagation=Propagation.SUPPORTS)//by Defonds,for BUG094537
@Override
public void delete(int uid, int[] itemIds) {
  if (itemIds != null && itemIds.length > 0) {


作者:l1028386804 发表于2017/11/23 15:59:55 原文链接
阅读:212 评论:0 查看评论

UE4实现纹理不随物体缩放(WorldAlignedTexture)

$
0
0
UE4编辑器蓝图实现物体缩放,纹理不随着物体缩放:

一般情况下,纹理会跟着物体的缩放而缩放:


那么如果不想纹理跟着物体缩放而缩放,可以通过蓝图来实现:基本思路是让贴图在世界坐标中进行重叠,所以无论物体如何缩放,贴图都会保持与原来大小基本一致。

效果如下:

本文地址:http://blog.csdn.net/u011417605/article/details/78615730

作者:u011417605 发表于2017/11/23 16:00:07 原文链接
阅读:138 评论:0 查看评论

Hadoop完全分布式安装Kafka

$
0
0

应用场景

按照搭建hadoop完全分布式集群博文搭建完hadoop集群后,发现hadoop完全分布式集群自带了HDFS,MapReduce,Yarn等基本的服务,一些其他的服务组件需要自己重新安装,比如Hive,Hbase,sqoop,zookeeper,spark等,这些组件集群模式都在前面相关博文中有介绍,今天我们需要安装另外一个组件,它就是分布式消息系统Kafka。

Kafka介绍

Kafka是由LinkedIn开发的一个分布式基于发布/订阅的消息系统,使用Scala编写,它以可水平扩展和高吞吐率而被广泛使用。
Kafka是什么?举个例子,生产者消费者,生产者生产鸡蛋,消费者消费鸡蛋,生产者生产一个鸡蛋,消费者就消费一个鸡蛋,假设消费者消费鸡蛋的时候噎住了(系统宕机了),生产者还在生产鸡蛋,那新生产的鸡蛋就丢失了。再比如生产者很强劲(大交易量的情况),生产者1秒钟生产100个鸡蛋,消费者1秒钟只能吃50个鸡蛋,那要不了一会,消费者就吃不消了(消息堵塞,最终导致系统超时),消费者拒绝再吃了,”鸡蛋“又丢失了,这个时候我们放个篮子在它们中间,生产出来的鸡蛋都放到篮子里,消费者去篮子里拿鸡蛋,这样鸡蛋就不会丢失了,都在篮子里,而这个篮子就是”kafka“。鸡蛋其实就是“数据流”,系统之间的交互都是通过“数据流”来传输的(就是tcp、http什么的),也称为报文,也叫“消息”。消息队列满了,其实就是篮子满了,”鸡蛋“放不下了,那赶紧多放几个篮子,其实就是kafka的扩容。
就类似微博,有人发布消息,有人消费消息,这就是一个Kafka的场景。

Kafka和其他主流分布式消息系统的对比

这里写图片描述

定义:
1、Java 和 scala都是运行在JVM上的语言。
2、erlang和最近比较火的和go语言一样是从代码级别就支持高并发的一种语言,所以RabbitMQ天生就有很高的并发性能,但是 有RabbitMQ严格按照AMQP进行实现,受到了很多限制。kafka的设计目标是高吞吐量,所以kafka自己设计了一套高性能但是不通用的协议,他也是仿照AMQP( Advanced Message Queuing Protocol 高级消息队列协议)设计的。
3、事物的概念:在数据库中,多个操作一起提交,要么操作全部成功,要么全部失败。举个例子, 在转账的时候付款和收款,就是一个事物的例子,你给一个人转账,你转成功,并且对方正常行收到款项后,这个操作才算成功,有一方失败,那么这个操作就是失败的。
对应消在息队列中,就是多条消息一起发送,要么全部成功,要么全部失败。3个中只有ActiveMQ支持,这个是因为,RabbitMQ和Kafka为了更高的性能,而放弃了对事物的支持 。
4、集群:多台服务器组成的整体叫做集群,这个整体对生产者和消费者来说,是透明的。其实对消费系统组成的集群添加一台服务器减少一台服务器对生产者和消费者都是无感之的。
5、负载均衡,对消息系统来说负载均衡是大量的生产者和消费者向消息系统发出请求消息,系统必须均衡这些请求使得每一台服务器的请求达到平衡,而不是大量的请求,落到某一台或几台,使得这几台服务器高负荷或超负荷工作,严重情况下会停止服务或宕机。
6、动态扩容是很多公司要求的技术之一,不支持动态扩容就意味着停止服务,这对很多公司来说是不可以接受的。

操作步骤

1. 安装Kafka之前需要安装zookeeper集群

参考zookeeper集群搭建博文

2. 下载Kafka安装压缩包

Kafka2.11安装包下载地址,下载完毕后,上传到主节点的/opt目录下
Kafka其他版本安装包下载地址

3. 解压Kafka并更换目录名

 # cd /opt
 # tar -xzvf kafka_2.11-0.10.2.1.tgz
 # mv kafka_2.11-0.10.2.1 kafka2.11

 # chmod 777 -R /opt/kafka2.11    #为kafka目录进行授权

4. 配置环境变量

 # vim /etc/profile

export KAFKA_HOME=/opt/kafka2.11
export PATH=$PATH:$KAFKA_HOME/bin            #在最后添加这两行Kafka的配置

 # source /etc/profile                 #使配置生效

5. 修改Kafka的server.properties配置

 # cd /opt/kafka2.11/config
 # vim server.properties

修改如下:

broker.id=1             #每台服务器的broker.id都不能相同

message.max.byte=5242880    #在log.retention.hours=168属性下加上如下三行配置
default.replication.factor=3
replica.fetch.max.bytes=5242880

zookeeper.connect=192.168.210.70:2181,192.168.210.71:2181,192.168.210.72:2181   #修改zookeeper引用外部的zookeeper

6. 将上述在其余节点也布置一下

 # cd /opt
 # scp -r kafka2.11  root@hadoop1:/opt/
 # scp -r kafka2.11  root@hadoop2:/opt/

注意:修改环境变量,修改配置文件的broker.id

7. 启动服务

#从后台启动Kafka集群(3台都需要启动)

 # cd /opt/kafka2.11/bin         #进入到kafka的bin目录 
 # ./kafka-server-start.sh -daemon ../config/server.properties

主节点:

这里写图片描述

两个从节点:

这里写图片描述

这里写图片描述

作者:bingoxubin 发表于2017/11/23 16:06:55 原文链接
阅读:105 评论:0 查看评论

简易的组装Json工具类

$
0
0

简易的组装Json工具类

// 设置业务参数
aliPayRequest.setBizContent("{" +
                            "    \"out_trade_no\":\"" + orderInfoId + "\"," +
                            "    \"total_amount\":\"" + retainage + "\"," +
                            "    \"subject\":\"" + orderInfoNum + "\"," +
                            "    \"store_id\":\"" + ALI_PAY_STORE_ID + "\"," +
                            "    \"timeout_express\":\"" + ALI_PAY_PAY_TIME_OUT + "m\"}");


// 组装工具类
public class JsonAssembleUtils {

    private String jsonString;

    private static final String PREFIX = "{";
    private static final String SUFFIX = "}";
    private static final String QUOTES = "\"";
    private static final String ATTRIBUTE_DELIMITER = ":";
    private static final String DELIMITER = ",";

    public JsonAssembleUtils() {
        jsonString = "";
    }


    public void set(String key, Object value) {
        int length = jsonString.length();
        StringBuffer buffer = length == 0 ? new StringBuffer() : new StringBuffer(jsonString);
        buffer.append(QUOTES);
        buffer.append(key);
        buffer.append(QUOTES);
        buffer.append(ATTRIBUTE_DELIMITER);
        if (value == null)
            buffer.append("null");
        else if (value instanceof String) {
            buffer.append(QUOTES);
            buffer.append((String) value);
            buffer.append(QUOTES);
        } else if (value instanceof Integer)
            buffer.append((Integer) value);
        else if (value instanceof Long)
            buffer.append((Long) value);
        else if (value instanceof Float)
            buffer.append((Float) value);
        else if (value instanceof Double)
            buffer.append((Double) value);
        else if (value instanceof Boolean)
            buffer.append((Boolean) value);
        else if (value instanceof Date) {
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            format.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            buffer.append(QUOTES);
            buffer.append(format.format((Date) value));
            buffer.append(QUOTES);
        } else {
            buffer.append(QUOTES);
            buffer.append(value.toString());
            buffer.append(QUOTES);
        }
        buffer.append(DELIMITER);
        jsonString = buffer.toString();
    }


    public String getJsonString() {
        if (jsonString.length() == 0)
            return PREFIX + SUFFIX;
        else
            return PREFIX + jsonString.substring(0, jsonString.length() - 1) + SUFFIX;
    }


}


// 组装业务参数
JsonAssembleUtils assembleUtils = new JsonAssembleUtils();
assembleUtils.set("out_trade_no", orderInfoId);
assembleUtils.set("total_amount", retainage);
assembleUtils.set("subject", orderInfoNum);
assembleUtils.set("store_id", ALI_PAY_STORE_ID);
assembleUtils.set("timeout_express", ALI_PAY_PAY_TIME_OUT);
aliPayRequest.setBizContent(assembleUtils.getJsonString());
作者:qq_15071263 发表于2017/11/23 16:19:42 原文链接
阅读:161 评论:0 查看评论

Kafka集群的测试和简单试用

$
0
0

应用场景

按照Hadoop完全分布式安装Kafka博文搭建完Kafka2.11集群后,需要简单试用,来体会Kafka的工作原理,以及如何进行使用,感受分布式消息队列系统。

操作步骤

思路:搭建了三个节点的Kafka集群,在主节点创建一个topic,作为生产者,两个从节点作为消费者分别看看能否接收数据,进行验证

步骤一,在主节点执行

创建topic及查看topic命令

#查看所有topic命令如下
 # kafka-topics.sh -list -zookeeper 192.168.210.70:2181,192.168.210.71:2181,192.168.210.72:2181

# (rf参数副本数,par参数分区数,xubintopic的名称)创建topic命令如下  
 # kafka-topics.sh --create --zookeeper 192.168.210.70:2181,192.168.210.71:2181,192.168.210.72:2181 --replication-factor 3 --partitions 1 --topic xubin    

在主节点查看topic,发现没有,进行创建topic为xubin,重新进行查看topic,发现存在了!

这里写图片描述

同理,一开始在从节点上看不到topic,当在主节点上创建了topic后,在从节点也能查到topic!

这里写图片描述

步骤二,在主节点创建生产者,在两个从节点分别创建消费者

开启生产者以及消费者

#开启生产者命令如下:
 # kafka-console-producer.sh --broker-list 192.168.210.70:9092,192.168.210.71:9092,192.168.210.72:9092 --topic xubin     

#开启生产者命令如下:     
 # kafka-console-consumer.sh --zookeeper 192.168.210.70:2181,192.168.210.71:2181,192.168.210.72:2181 --topic xubin --from-beginning  消费者  

在主节点开启生产者:

这里写图片描述

在两个从节点分别开启消费者:

这里写图片描述

这里写图片描述

步骤三,在生产者中输入信息,看消费者中是否能拿到数据

生产者:

这里写图片描述

消费者:

这里写图片描述

这里写图片描述

作者:bingoxubin 发表于2017/11/23 16:34:08 原文链接
阅读:103 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>