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

leetcode: 40. Combination Sum II

$
0
0

Q

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

Note:

All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8, 
A solution set is: 
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

AC

# Time:  O(k * C(n, k))
# Space: O(k)
class Solution(object):
    """
    :type candidates: List[int]
    :type target: int
    :rtype: List[List[int]]
    """
    def combinationSum2(self, candidates, target):
        result = []
        self.combinationSumRecu(sorted(candidates), result, 0, [], target)
        return result

    def combinationSumRecu(self, candidates, result, start, intermediate, target):
        if target == 0:
            result.append(list(intermediate))
        prev = 0
        while start < len(candidates) and candidates[start] <= target:
            if prev != candidates[start]:
                intermediate.append(candidates[start])
                self.combinationSumRecu(candidates, result, start + 1, intermediate, target - candidates[start])
                intermediate.pop()
                prev = candidates[start]
            start += 1

if __name__ == "__main__":
    candidates, target = [10, 1, 2, 7, 6, 1, 5], 8
    result = Solution().combinationSum2(candidates, target)     
    assert result == [[1, 1, 6], [1, 2, 5], [1, 7], [2, 6]]


作者:JNingWei 发表于2017/11/14 9:13:16 原文链接
阅读:4 评论:0 查看评论

leetcode: 41. First Missing Positive

$
0
0

Q

Given an unsorted integer array, find the first missing positive integer.

For example,
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.

Your algorithm should run in O(n) time and uses constant space.

AC

class Solution(object):
    def firstMissingPositive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        length = len(nums)
        if len(nums) == 0:
            return 1
        lst = range(1, length+2)
        for i in nums:
            if i > 0 and i < length+1 and i in lst:
                lst.remove(i)
        return lst[0]

class Solution2(object):
    def firstMissingPositive(self, A):
        i = 0
        while i < len(A):
            if A[i] > 0 and A[i] - 1 < len(A) and A[i] != A[A[i]-1]:
                A[A[i]-1], A[i] = A[i], A[A[i]-1]
            else:
                i += 1

        for i, integer in enumerate(A):
            if integer != i + 1:
                return i + 1
        return len(A) + 1

if __name__ == "__main__":
    assert Solution().firstMissingPositive([1,2,0]) == 3
    assert Solution().firstMissingPositive([3,4,-1,1]) == 2


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

leetcode: 42. Trapping Rain Water

$
0
0

Q

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

For example, 
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.

这里写图片描述

The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

AC

# Time:  O(n)
# Space: O(1)
class Solution(object):
    """
    :type height: List[int]
    :rtype: int
    """
    def trap(self, height):
        result = 0
        top = 0
        for i in xrange(len(height)):
            if height[top] < height[i]:
                top = i

        second_top = 0
        for i in xrange(top):
            if height[second_top] < height[i]:
                second_top = i
            result += height[second_top] - height[i]

        second_top = len(height) - 1
        for i in reversed(xrange(top, len(height))):
            if height[second_top] < height[i]:
                second_top = i
            result += height[second_top] - height[i]

        return result

# Time:  O(n)
# Space: O(n)
class Solution2:
    def trap(self, height):
        result = 0
        stack = []

        for i in xrange(len(height)):
            mid_height = 0
            while stack:
                [pos, height] = stack.pop()
                result += (min(height, height[i]) - mid_height) * (i - pos - 1)
                mid_height = height

                if height[i] < height:
                    stack.append([pos, height])
                    break
            stack.append([i, height[i]])

        return result

if __name__ == "__main__":
    assert Solution().trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]) == 6


作者:JNingWei 发表于2017/11/14 9:17:01 原文链接
阅读:3 评论:0 查看评论

leetcode: 43. Multiply Strings

$
0
0

Q

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2.

Note:

The length of both num1 and num2 is < 110.
Both num1 and num2 contains only digits 0-9.
Both num1 and num2 does not contain any leading zero.
You must not use any built-in BigInteger library or convert the inputs to integer directly.

AC

# Time:  O(m * n)
# Space: O(m + n)
class Solution(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        num1, num2 = num1[::-1], num2[::-1]
        res = [0] * (len(num1) + len(num2))
        for i in xrange(len(num1)):
            for j in xrange(len(num2)):
                res[i + j] += int(num1[i]) * int(num2[j])
                res[i + j + 1] += res[i + j] / 10
                res[i + j] %= 10
        i = len(res) - 1
        while i > 0 and res[i] == 0:
            i -= 1
        return ''.join(map(str, res[i::-1]))

# Time:  O(m * n)
# Space: O(m + n)
# Using built-in bignum solution.
class Solution2(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        return str(int(num1) * int(num2))

if __name__ == "__main__":
    assert Solution().multiply("123", "1000") == '123000'


作者:JNingWei 发表于2017/11/14 9:18:43 原文链接
阅读:3 评论:0 查看评论

leetcode: 44. Wildcard Matching

$
0
0

Q

Implement wildcard pattern matching with support for ‘?’ and ‘*’.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false

AC

# Time:  O(m + n)
# Space: O(1)
# iteration
class Solution:
    """
    :type s: str
    :type p: str
    :rtype: bool
    """
    def isMatch(self, s, p):
        p_ptr, s_ptr, last_s_ptr, last_p_ptr = 0, 0, -1, -1
        while s_ptr < len(s):
            if p_ptr < len(p) and (s[s_ptr] == p[p_ptr] or p[p_ptr] == '?'):
                s_ptr += 1
                p_ptr += 1
            elif p_ptr < len(p) and p[p_ptr] == '*':
                p_ptr += 1
                last_s_ptr = s_ptr
                last_p_ptr = p_ptr
            elif last_p_ptr != -1:
                last_s_ptr += 1
                s_ptr = last_s_ptr
                p_ptr = last_p_ptr
            else:
                return False

        while p_ptr < len(p) and p[p_ptr] == '*':
            p_ptr += 1

        return p_ptr == len(p)

# dp with rolling window
# Time:  O(m * n)
# Space: O(m + n)
class Solution2:
    def isMatch(self, s, p):
        k = 2
        result = [[False for j in xrange(len(p) + 1)] for i in xrange(k)]

        result[0][0] = True
        for i in xrange(1, len(p) + 1):
            if p[i-1] == '*':
                result[0][i] = result[0][i-1]
        for i in xrange(1,len(s) + 1):
            result[i % k][0] = False
            for j in xrange(1, len(p) + 1):
                if p[j-1] != '*':
                    result[i % k][j] = result[(i-1) % k][j-1] and (s[i-1] == p[j-1] or p[j-1] == '?')
                else:
                    result[i % k][j] = result[i % k][j-1] or result[(i-1) % k][j]

        return result[len(s) % k][len(p)]

# dp
# Time:  O(m * n)
# Space: O(m * n)
class Solution3:
    def isMatch(self, s, p):
        result = [[False for j in xrange(len(p) + 1)] for i in xrange(len(s) + 1)]

        result[0][0] = True
        for i in xrange(1, len(p) + 1):
            if p[i-1] == '*':
                result[0][i] = result[0][i-1]
        for i in xrange(1,len(s) + 1):
            result[i][0] = False
            for j in xrange(1, len(p) + 1):
                if p[j-1] != '*':
                    result[i][j] = result[i-1][j-1] and (s[i-1] == p[j-1] or p[j-1] == '?')
                else:
                    result[i][j] = result[i][j-1] or result[i-1][j]

        return result[len(s)][len(p)]


# recursive, slowest, TLE
class Solution4:
    # @return a boolean
    def isMatch(self, s, p):
        if not p or not s:
            return not s and not p

        if p[0] != '*':
            if p[0] == s[0] or p[0] == '?':
                return self.isMatch(s[1:], p[1:])
            else:
                return False
        else:
            while len(s) > 0:
                if self.isMatch(s, p[1:]):
                    return True
                s = s[1:]
            return self.isMatch(s, p[1:])

if __name__ == "__main__":
    assert Solution().isMatch("aaaabaaaab","a*b*b")
    assert not Solution().isMatch("aaaaaaaaaaaaab", "a*a*a*a*a*a*a*a*a*a*c")
    assert not Solution().isMatch("aa","a")
    assert Solution().isMatch("aa","aa")
    assert not Solution().isMatch("aaa","aa")
    assert Solution().isMatch("aa", "a*")
    assert Solution().isMatch("aa", "?*")
    assert Solution().isMatch("ab", "?*")
    assert not Solution().isMatch("aab", "c*a*b")


作者:JNingWei 发表于2017/11/14 9:20:32 原文链接
阅读:3 评论:0 查看评论

leetcode: 45. Jump Game II

$
0
0

Q

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Your goal is to reach the last index in the minimum number of jumps.

For example:
Given array A = [2,3,1,1,4]

The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)

Note:

You can assume that you can always reach the last index.

AC

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums or len(nums)==1:
            return 0
        candidates = [0]
        step = 0
        while True:
            step += 1
            _min = max(candidates)+1
            _max = _min
            for c in candidates:
                c = c + nums[c]
                if c > _max:
                    _max = c
            if _max>=len(nums)-1:
                return step
            candidates = range(_min, _max+1)

# Time:  O(n^2)
# Space: O(1)
class Solution2:
    # @param A, a list of integers
    # @return an integer
    def jump(self, A):
        result, prev_reachable, reachable = 0, -1, 0
        while reachable > prev_reachable:
            if reachable >= len(A) - 1:
                return result
            result += 1
            prev_reachable = reachable
            for i, length in enumerate(A[:reachable + 1]):
                reachable = max(reachable, i + length)
        return -1

# when you on an index of nums, move to next index which can move farthest in range of this index reachable
# Time: O(log(n))
# Space: O(1)
class Solution3(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums[-1] = 2 ** 31
        nums2, l = [i + j for i, j in enumerate(nums)], len(nums) - 1

        def find_max_index(index):
            tmp = nums2[index:index + nums[index] + 1]
            return index + tmp.index(max(tmp))

        index, steps = 0, 0
        while True:
            index = find_max_index(index)
            if index:
                steps += 1
            if index == l:
                break
        return steps

if __name__ == "__main__":
    assert Solution().jump([2,3,1,1,4]) == 2
    assert Solution().jump([3,2,1,0,4]) == 2


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

数据结构与算法分析(Java语言描述)(18)—— 二叉搜索树最大、最小子节点的搜索、删除

$
0
0
// --------------------------------------------------------------------
    // 搜索 最小节点操作

    // 寻找二叉搜索树的最小 key
    public Key minimum(){
        Node minNode = minimum(root);
        return minNode.key;
    }

    // 返回以node为根的二叉搜索树的最小键值所在的节点
    private Node minimum(Node node){
        if (node.left == null) return node;
        return minimum(node.left);
    }

    // --------------------------------------------------------------------
    // 移除 最小节点操作

    // 移除二叉搜索树中最小 key 节点
    public void removeMin(){
        if (root != null)
            root = removeMin(root);
    }

    // 删除掉以node为根的二叉搜索树中的最小节点
    // 返回删除节点后新的二叉搜索树的根
    private Node removeMin(Node node){
        // 递归到底,获取到二叉搜索树 key 最小的节点
        if (node.left == null){

            // 保存此节点的 右子节点
            Node rightNode = node.right;

            // 移除此节点
            node.right = null;
            count--;

            // 返回 右子节点
            return rightNode;
        }
        // 将被删除的节点替换为该节点的 右子节点
        node.left = removeMin(node.left);
        return node;
    }

    // --------------------------------------------------------------------
    // 搜索 最大节点操作

    // 寻找二叉搜索树的最大 key
    public Key maximum(){
        Node maxNode = maximum(root);
        return maxNode.key;
    }

    // 返回以node为根的二叉搜索树的最大键值所在的节点
    private Node maximum(Node node){
        if (node.right == null) return node;
        return maximum(node.right);
    }

    // --------------------------------------------------------------------
    // 移除 最大节点操作

    // 从二分搜索树中删除最大值所在节点
    public void removeMax(){
        if (root != null)
            root = removeMax(root);
    }

    // 删除掉以node为根的二叉搜索树中的最大节点
    // 返回删除节点后新的二叉搜索树的根
    private Node removeMax(Node node){
        // 递归到底,获取到二叉搜索树 key 最大的节点
        if (node.right == null){
            // 保存该节点的 左子节点
            Node leftNode = node.left;
            // 删除该节点
            node.left = null;
            count--;
            // 返回该节点的 左子节点
            return leftNode;
        }
        node.right = removeMax(node.right);
        return node;
    }
作者:HeatDeath 发表于2017/11/14 17:44:55 原文链接
阅读:190 评论:0 查看评论

python: argparse库 &命令行解析工具

$
0
0

API

ArgumentParser.add_argument(name or flags…[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])

  • name or flags - 选项字符串的名字或者列表,例如 foo 或者 -f, –foo。
  • action - 命令行遇到参数时的动作,默认值是 store。
    • store_const,表示赋值为const;
    • append,将遇到的值存储成列表,也就是如果参数重复则会保存多个值;
    • append_const,将参数规范中定义的一个值保存到一个列表;
    • count,存储遇到的次数;此外,也可以继承 argparse.Action 自定义参数解析;
  • nargs - 应该读取的命令行参数个数,可以是具体的数字,或者是?号,当不指定值时对于 Positional argument 使用 - default,对于 Optional argument 使用 const;或者是 * 号,表示 0 或多个参数;或者是 + 号表示 1 或多个参数。
  • const - action 和 nargs 所需要的常量值。
  • default - 不指定参数时的默认值。
  • type - 命令行参数应该被转换成的类型。
  • choices - 参数可允许的值的一个容器。
  • required - 可选参数是否可以省略 (仅针对可选参数)。
  • help - 参数的帮助信息,当指定为 argparse.SUPPRESS 时表示不显示该参数的帮助信息.
  • metavar - 在 usage 说明中的参数名称,对于必选参数默认就是参数名称,对于可选参数默认是全大写的参数名称.
  • dest - 解析后的参数名称,默认情况下,对于可选参数选取最长的名称,中划线转换为下划线.

实验代码

1.py:

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('integer', type=int, help='display an integer')
parser.add_argument("--square", help="display a square of a given number", type=int)
parser.add_argument("--cubic", help="display a cubic of a given number", type=int)

args = parser.parse_args()

print args.integer
if args.square:
    print args.square**2
if args.cubic:
    print args.cubic**3

bash:

$ python 1.py 10 --square=2 --cubic=3
10
4
27


Ref:



作者:JNingWei 发表于2017/11/14 18:16:04 原文链接
阅读:134 评论:0 查看评论

redis实战教程(一)-分布式锁

$
0
0

主要用到setnx函数,原理如下:

命令格式

SETNX key value

将 key 的值设为 value,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
SETNX 是SET if Not eXists的简写。

返回值

返回整数,具体为
- 1,当 key 的值被设置
- 0,当 key 的值没被设置

例子

redis> SETNX mykey “hello”
(integer) 1
redis> SETNX mykey “hello”
(integer) 0
redis> GET mykey
“hello”
redis>

使用SETNX实现分布式锁

多个进程执行以下Redis命令:

SETNX lock.foo <current Unix time + lock timeout + 1>

如果 SETNX 返回1,说明该进程获得锁,SETNX将键 lock.foo 的值设置为锁的超时时间(当前时间 + 锁的有效时间)。
如果 SETNX 返回0,说明其他进程已经获得了锁,进程不能进入临界区。进程可以在一个循环中不断地尝试 SETNX 操作,以获得锁。



package net.csdn.redis;

import java.util.concurrent.TimeUnit;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisDemo {
	private static JedisPool pool;
	private static String redisServerIp = "192.168.0.43";
	private static String redisPassord = "MMHlive2016";
	private static int connectTimeout = 20 * 1000;// 2秒
	
	/**
	 * 建立连接池 真实环境,一般把配置参数缺抽取出来。
	 * 
	 */
	private static void createJedisPool() {

		// 建立连接池配置参数
		JedisPoolConfig config = new JedisPoolConfig();

		// 设置最大连接数
		config.setMaxActive(10000);

		// 设置最大阻塞时间,记住是毫秒数milliseconds
		config.setMaxWait(connectTimeout);

		// 设置空间连接
		config.setMaxIdle(500);
		// 创建连接池
		pool = new JedisPool(config, redisServerIp, 6379, connectTimeout, redisPassord);
	}

	/**
	 * 在多线程环境同步初始化
	 */
	private static synchronized void poolInit() {
		if (pool == null)
			createJedisPool();
	}

	/**
	 * 获取一个jedis 对象
	 * 
	 * @return
	 */
	private static Jedis getJedis() {
		if (pool == null)
			poolInit();
		return pool.getResource();
	}

	/**
	 * 归还一个连接
	 * 
	 * @param jedis
	 */
	private static void returnRes(Jedis jedis) {
		pool.returnResource(jedis);
	}
	public static long setnx(String key, String val, int timeout) {
		Jedis jedis = getJedis();
		long rst = jedis.setnx(key, val);
		if (rst == 1) {
			jedis.expire(key, timeout);
		}
		returnRes(jedis);
		return rst;
	}
	public static long delete(String sessionId) {
		Jedis jedis = getJedis();
		Long rst = jedis.del(sessionId);
		returnRes(jedis);
		return rst;
	}
	public static boolean tryLock(String key, int timeout) {
		long nano = System.nanoTime();
		do {
			 
			Long i = setnx(key, key, timeout);
//			System.out.println(i);
			if (i == 1) {
				System.out.println(Thread.currentThread().getName()+":获得锁");
				return true;
			}
			if (timeout == 0) {
				break;
			}
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if((System.nanoTime() - nano) > TimeUnit.SECONDS.toNanos(timeout)){
				break;
			}
		} while (true);

		throw new RuntimeException("获取[" + key + "]锁超时");
		
	}
	
	
	public static void main(String[] args) throws Exception {
		String key="wweerrt";
		delete(key);
		int timeout=1000000;
		new Thread(()->{
			System.out.println(Thread.currentThread().getName()+":开始加锁");
			tryLock(key, timeout);
		}) .start();
		new Thread(()->{
			System.out.println(Thread.currentThread().getName()+":开始加锁");
			tryLock(key, timeout);
		}) .start();
		
		Thread.sleep(100000L);
	}
}

控制台输出:
Thread-1:开始加锁
Thread-2:开始加锁
Thread-1:获得锁



作者:yx511500623 发表于2017/11/14 18:31:25 原文链接
阅读:181 评论:0 查看评论

Kakfa源码环境搭建

$
0
0

本文主要讲述的是如何搭建Kafka的源码环境,主要针对的Windows操作系统下IntelliJ IDEA编译器,其余操作系统或者IDE可以类推。

1.安装和配置JDK

确认JDK版本至少为1.7,最好是1.8及以上。使用java -version命令来查看当前JDK的版本,示例如下:

C:\Users\hidden> java -version
java version "1.8.0_112"
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)

2.下载并安装配置Gradle

下载地址为:https://gradle.org/releases/,笔者使用的版本是3.1。一般只需要将下载的包解压,然后再将$GRADLE_HOME/bin的路径添加到环境变量Path中即可,其中$GRADLE_HOME指的是Gradle的根目录。可以使用gradle -v命令来验证Gradle是否已经配置完成,示例如下:

C:\Users\hidden>gradle -v

------------------------------------------------------------
Gradle 3.1
------------------------------------------------------------

Build time:   2016-09-19 10:53:53 UTC
Revision:     13f38ba699afd86d7cdc4ed8fd7dd3960c0b1f97

Groovy:       2.4.7
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_112 (Oracle Corporation 25.112-b15)
OS:           Windows 10 10.0 amd64

3.下载并安装配置Scala

下载地址为:http://www.scala-lang.org/download/all.html,目前最新的版本是2.12.4,不过笔者这里使用的版本是2.11.11。如Gradle一样,只需要解压并将$SCALA_HOME/bin的路径添加到环境变量Path即可,其中$SCALA_HOME指的是Scala的根目录。可以使用scala -version命令来验证scala是否已经配置完成,示例如下:

C:\Users\hidden>scala -version
Scala code runner version 2.11.11 -- Copyright 2002-2017, LAMP/EPFL

4. 构建Kafka源码环境

Kafka下载地址为:http://kafka.apache.org/downloads,目前最新的版本是1.0.0。将下载的压缩包解压,并在Kafka的根目录执行gradle idea命令进行构建,如果你使用的是Eclipse,则只需采用gradle eclipse命令构建即可。构建细节如下所示:

D:\IntelliJ IDEA Files\kafka-sources\kafka-1.0.0-src>gradle idea
Starting a Gradle Daemon, 2 incompatible and 1 stopped Daemons could not be reused, use --status for details
Building project 'core' with Scala version 2.11.11
:ideaModule
:ideaProject
(......省略若干......)
:streams:examples:ideaModule
:streams:examples:idea

BUILD SUCCESSFUL

Total time: 1 mins 11.991 secs

之后将Kafka导入到IDEA中即可。不过这样还没有结束,对于IDEA而言,还需要安装Scala插件,在Setting->Plugin中搜索scala并安装,可以参考下图,笔者这里是已经安装好的状态:

这里写图片描述

5. 配置Kafka源码环境

前面几个步骤执行完成后就可以很舒适的阅读Kafka的源码,但是如果需要启动Kafka的服务还需要一些额外的步骤。

首先确保gradle.properties配置文件中的scalaVersion与安装的一致。gradle.properties配置文件的细节如下:

group=org.apache.kafka
# NOTE: When you change this version number, you should also make sure to update
# the version numbers in tests/kafkatest/__init__.py and kafka-merge-pr.py.
version=1.0.0
scalaVersion=2.11.11
task=build
org.gradle.jvmargs=-XX:MaxPermSize=512m -Xmx1024m -Xss2m

如果更改了scalaVersion,需要重新执行gradle idea命令来重新构建。虽然很多时候在操作系统中安装其他版本的Scala也并没有什么问题,比如安装2.12.4版本。但是有些情况下运行Kafka时会出现一些异常,而这些异常却又是由于Scala版本不一致而引起的,比如会出现下面示例中的报错:

[2017-11-13 17:09:21,119] FATAL  (kafka.Kafka$)
java.lang.NoSuchMethodError: scala.collection.TraversableOnce.$init$(Lscala/collection/TraversableOnce;)V
    at kafka.message.MessageSet.<init>(MessageSet.scala:72)
    at kafka.message.ByteBufferMessageSet.<init>(ByteBufferMessageSet.scala:129)
    at kafka.message.MessageSet$.<init>(MessageSet.scala:32)
    at kafka.message.MessageSet$.<clinit>(MessageSet.scala)
    at kafka.server.Defaults$.<init>(KafkaConfig.scala:52)
    at kafka.server.Defaults$.<clinit>(KafkaConfig.scala)
    at kafka.server.KafkaConfig$.<init>(KafkaConfig.scala:686)
    at kafka.server.KafkaConfig$.<clinit>(KafkaConfig.scala)
    at kafka.server.KafkaServerStartable$.fromProps(KafkaServerStartable.scala:28)
    at kafka.Kafka$.main(Kafka.scala:82)
    at kafka.Kafka.main(Kafka.scala)

所以为了省去一些不必要的麻烦,还是建议读者在安装Scala版本之前先查看下Kafka源码中gradle.properties文件中配置的scalaVersion。

再确保了scalaVersion之后,需要将config目录下的log4j.properties文件拷贝到core/src/main/scala目录下,这样可以让Kafka在运行时能够输出日志信息,可以参考下图:

这里写图片描述

之后还需要配置server.properties文件,一般只需要修改以下一些配置项:

# 是否允许topic被删除,设置为true则topic可以被删除,
# 开启这个功能方便Kafka在运行一段时间之后,能够删除一些不需要的临时topic
delete.topic.enable=true
# 禁用自动创建topic的功能
auto.create.topics.enable=false
# 存储log文件的目录,默认值为/tmp/kafka-logs
# 示例是在Windows环境下运行,所以需要修改这个配置,注意这里的双反斜杠。
log.dir=D:\\kafka\\tmp\\kafka-logs
# 配置kafka依赖的zookeeper路径地址,这里的前提是在本地开启了一个zookeeper的服务
# 如果本地没有zookeeper服务,可以参考下一节中zookeeper的安装、配置及运行
zookeeper.connect=localhost:2181/kafka

之后配置Kafka的启动参数,详细参考下图:

这里写图片描述

这里配置Main class为kafka.Kafka,并制定启动时所需要的配置文件地址,即:config/server.properties。配置JMX_PORT是为了方便搜集Kafka自身的Metrics数据。

如此便可以顺利的运行Kafka服务了(第一次启动时会有一个耗时较长的编译过程),部分启动日志如下:

[2017-11-14 00:24:14,472] INFO KafkaConfig values: 
    advertised.host.name = null
    advertised.listeners = null
    advertised.port = null
    authorizer.class.name = 
(......省略若干......)
[2017-11-14 00:24:35,001] INFO Registered broker 0 at path /brokers/ids/0 with addresses: EndPoint(LAPTOP-1IN9UPT7,9092,ListenerName(PLAINTEXT),PLAINTEXT) (kafka.utils.ZkUtils)
[2017-11-14 00:24:35,019] INFO Kafka version : 1.0.0 (org.apache.kafka.common.utils.AppInfoParser)
[2017-11-14 00:24:35,020] INFO Kafka commitId : e89bffd6b2eff799 (org.apache.kafka.common.utils.AppInfoParser)
[2017-11-14 00:24:35,021] INFO [Kafka Server 0], started (kafka.server.KafkaServer)

6. Zookeeper的安装、配置及启动

Kafka需要使用Zookeeper来管理元数据,比如记录topic、partitions(分区)以及replica(副本)的分配信息。由于这里只是阐述如何构建Kafka的源码环境搭建,所以这里的Zookeeper的安装也以极简为主,即采用单机配置。Zookeeper下载地址为:http://zookeeper.apache.org/releases.html,下载之后解压,然后将$ZOOKEEPER_HOME目录下的conf/zoo_sample.cfg重命名为zoo.cfg,其中$ZOOKEEPER_HOME指的是ZooKeeper的根目录。

修改$ZOOKEEPER_HOME/conf/zoo.cfg配置,示例配置如下(其余配置可以不做修改):

dataDir=D:\\zookeeper-3.4.10\\tmp\\zookeeper\\data

将$ZOOKEEPER_HOME/bin配置到Path中,之后直接运行zkServer命令即可开启Zookeeper服务。示例如下:

C:\Users\hidden>zkServer

C:\Users\hidden>call "C:\Program Files\Java\jdk1.8.0_112"\bin\java "-Dzookeeper.log.dir=D:\zookeeper-3.4.10\bin\.." "-Dzookeeper.root.logger=INFO,CONSOLE" -cp "D:\zookeeper-3.4.10\bin\..\build\classes;D:\zookeeper-3.4.10\bin\..\build\lib\*;D:\zookeeper-3.4.10\bin\..\*;D:\zookeeper-3.4.10\bin\..\lib\*;D:\zookeeper-3.4.10\bin\..\conf" org.apache.zookeeper.server.quorum.QuorumPeerMain "D:\zookeeper-3.4.10\bin\..\conf\zoo.cfg"
2017-11-14 00:44:20,135 [myid:] - INFO  [main:QuorumPeerConfig@134] - Reading configuration from: D:\zookeeper-3.4.10\bin\..\conf\zoo.cfg
2017-11-14 00:44:20,147 [myid:] - INFO  [main:DatadirCleanupManager@78] - autopurge.snapRetainCount set to 3
2017-11-14 00:44:20,147 [myid:] - INFO  [main:DatadirCleanupManager@79] - autopurge.purgeInterval set to 0
2017-11-14 00:44:20,147 [myid:] - INFO  [main:DatadirCleanupManager@101] - Purge task is not scheduled.
2017-11-14 00:44:20,150 [myid:] - WARN  [main:QuorumPeerMain@113] - Either no config or no quorum defined in config, running  in standalone mode
2017-11-14 00:44:20,250 [myid:] - INFO  [main:QuorumPeerConfig@134] - Reading configuration from: D:\zookeeper-3.4.10\bin\..\conf\zoo.cfg
2017-11-14 00:44:20,250 [myid:] - INFO  [main:ZooKeeperServerMain@96] - Starting server
作者:u013256816 发表于2017/11/14 18:45:11 原文链接
阅读:199 评论:0 查看评论

Android 64位变32位

$
0
0

人生最大的改变就是去做自己害怕的事情。

今年的Google I/O大会上Google提出了Android GO,其目的是尽可能的让Android系统能运行在低配的手机设备。其中就提到了为了节省存储空间,Android GO是32位系统。

本篇博文沿着这个思路,介绍将Android改为32系统的方法。修改的地方较少,只用修改两个地方。

修改64位Android系统成32位

  1. 定义TARGET_ARCH跟TARGET_ARCH_VARIANT为32位,TARGET_2ND_ARCH跟TARGET_2ND_ARCH_VARIANT赋空值.
  2. 配置zygote为32位,在项目对应的make文件中添加
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote32

到此修改完毕了,可以收工了。当然如果你还想知道这背后的细节知识,请继续往下看。

TARGET_ARCH是什么

TARGET_ARCH代表的是编译Android的目标CPU架构的名称,比如:arm,x86。利用uname -m可以查看当前手机的的CPU架构,我自己手机运行结果如下:

$ adb shell uname -m
armv7l

TARGET_ARCH_VARIANT是什么

VARIANT英文译为”不同的”,TARGET_ARCH_VARIANT之前被称为TARGET_ARCH_VERSION,其作用是区分相同CPU架构的不同版本,比如arm架构它有很多个版本,我们依靠TARGET_ARCH_VARIANT来进行选取。

TARGET_ARCH_VARIANT在源码中有多个值,比如armv7-a-neon/x86_64/mips64r6。这些分别代表什么含义呢?

arm系列

以armv7-a-neon来举例说明,arm打头代表CPU架构是arm的,v7表示版本,v7以及v7以下的版本均是32位的,从v8开始就是64位了。而v7版本的arm又细分为三种:

  • a:专为Application设计,a代表Applications
  • r:专为实时系统设计,r代表Real-time
  • m:精简版本,m代表Microcontroller

这其中a跟r非常类似。更详细的说明请查考arm官方文档:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c/index.html
我们平时见的多是armv7-a系列。

提下neon, 它是arm公司专为移动消费类设备设计的。它提供了更卓越的视频编码解码,3D图形渲染,语音处理,流媒体处理等功能。

还有vfp,vfp是Vector Floating-Point的缩写,它在处理矢量浮点运算方面表现更好。

明白了这些在看下面这些配置值心里就明白意思了。

armv7-a-neon
armv5te-vfp
armv8-a

mips系列

mips是区别与arm的另一种CPU架构。由MIPS公司开发并授权,它跟arm一样都基于精简指令集处理器架构的思想,常见的有

mips64r6
mips32r2-fp
mips32-fp

x86系列

x86_64中x86表示cpu架构是由因特尔公司开发,而64表示是64位系统。

TARGET_2ND_ARCH和TARGET_2ND_ARCH_VARIANT分别什么含义

TARGET_2ND_ARCH

从Android5.0之后出现了64位系统,Android系统就需要考虑兼容之前大量的32位程序了,如果打算在64位系统上,也具有编译32程序的能力,就该TARGET_2ND_ARCH出场了,它的出现正是Android系统为了兼容64/32的程序而引入的。

这里的目标程序多数情况下指的是库文件,默认系统只会编译出运行在TARGET_ARCH架构下的库文件.

看看下面的例子:

TARGET_ARCH=arm64
TARGET_2ND_ARCH=arm

TARGET_ARCH说明芯片架构是面向64位系统的,并且在这个基础上又定义了TARGET_2ND_ARCH,它表明芯片也是兼容32位程序的。当确定需要编译32位库文件时,需要在库文件模块的Android.mk文件中加入:

LOCAL_MULTILIB := 32 # 只编译32位
LOCAL_MULTILIB := both # 64/32位都编译

TARGET_2ND_ARCH_VARIANT

解释完TARGET_2ND_ARCH,TARGET_2ND_ARCH_VARIANT的含义也就明朗了。它表示兼容cpu架构的版本。

zygote32是什么

zygote32顾名思义,它服务的是32位系统。因为从Android5.0之后蹦出了64位,因此zygote也需要跟着适配,分成32/64的版本。
开篇提到的

PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote32

改动是什么道理呢?
system/core/rootdir/init.rc

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc

我们将ro.zygote赋值为zygote32,所以最终就有import /init.zygote32.rc
init.zygote32.rc所在位置如下图:
这里写图片描述

这里也可以看到zygote有四个版本,不应该是两个吗?(一个32另一个64),查看内容就知道区别了。
system/core/rootdir/init.zygote32_64.rc

service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

它们的区别如下表:

配置文件名称 含义
init.zygote32.rc 只启动一个面向32位的app_process32进程
init.zygote64.rc 只启动一个面向64位的app_process64进程
init.zygote32_64.rc 启动两个app_process进程,其中app_process32为主,app_process64为辅
init.zygote64_32.rc 启动两个app_process进程,其中app_process64为主,app_process32为辅
作者:azhengye 发表于2017/11/14 19:25:13 原文链接
阅读:201 评论:0 查看评论

九.ARM裸机学习之串口通信详解2(S5PV210串行通信编程详解)

$
0
0
1、整个程序流程分析
(1)整个串口通信相关程序包含2部分:uart_init负责初始化串口,uart_putc负责发送一个字节,uart_gec负责接收一个字节。
2、串口控制器初始化关键步骤
(1)初始化串口的Tx和Rx引脚所对应的GPIO(查原理图可知Rx和Rx分别对应GPA0_1和GPA0_0)
(2)GPA0CON(0xE0200000),bit[3:0] = 0b0010 bit[7:4] = 0b0010
(3)初始化这几个关键寄存器UCON0 ULCON0 UMCON0 UFCON0 UBRDIV0 UDIVSLOT0
3、主要的几个寄存器
(1)ULCON0 = 0x3 // 0校验位、8数据位、1停止位
(2)UCON = 0x5 // 发送和接收都是polling mode
(3)UMCON0 = 0x0 // 禁止modem、afc
(4)UFCON0 = 0x0 // 禁止FIFO模式
(5)UBRDIV0和UDIVSLOT0和波特率有关,要根据公式去算的
4、在C源文件中定义访问寄存器的宏
定义好了访问寄存器的宏之后,将来写代码时直接使用即可。
5、串口Tx、Rx对应的GPIO的初始化
给GPA0CON的相应bit位赋值为相应值,用C语言位操作来完成。
6、UCON、ULCON、UMCON、UFCON等主要控制寄存器
依据上节中分析的值进行依次设置即可。
7、波特率的计算和设置
(1)第一步,用PCLK_PSYS和目标波特率去计算DIV_VAL: DIV_VAL = (PCLK / (bps x 16))-1
(2)第二步,UBRDIV0寄存器中写入DIV_VAL的整数部分
(3)第三步,用小数部分*16得到1个个数,查表得uBDIVSLOT0寄存器的设置值
1.7.8.4、串口发送和接收函数的编写
(1)写发送函数,主要发送前要用while循环等待发送缓冲区为空才能发送。
发送接收状态寄存器:UTRSTAT0
uart.c:
/*
   包含串口初始化程序,串口发送程序,串口接收程序
*/

#define GPA0CON		0xE0200000
#define UCON0 		0xE2900004
#define ULCON0 		0xE2900000
#define UMCON0 		0xE290000C
#define UFCON0 		0xE2900008
#define UBRDIV0 	0xE2900028
#define UDIVSLOT0	0xE290002C
#define UTRSTAT0	0xE2900010
#define UTXH0		0xE2900020	
#define URXH0		0xE2900024

#define rGPA0CON	(*(volatile unsigned int *)GPA0CON)
#define rUCON0		(*(volatile unsigned int *)UCON0)
#define rULCON0		(*(volatile unsigned int *)ULCON0)
#define rUMCON0		(*(volatile unsigned int *)UMCON0)
#define rUFCON0		(*(volatile unsigned int *)UFCON0)
#define rUBRDIV0	(*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0	(*(volatile unsigned int *)UDIVSLOT0)
#define rUTRSTAT0		(*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0		(*(volatile unsigned int *)UTXH0)
#define rURXH0		(*(volatile unsigned int *)URXH0)

//串口初始化程序
void uart_init(void)
{
	// 初始化Tx Rx对应的GPIO引脚
	rGPA0CON &=~(0xff<<1);//把寄存器的bit0~7全部清零 
	rGPA0CON |= 0x00000022;			// 0b0010, Rx Tx
	
	//几个主要的寄存器
	rULCON0 = 0x3;  // 0校验位、8数据位、1停止位
	rUCON0 = 0x5;  // 发送和接收都是polling mode
	rUMCON0 = 0;  // 禁止modem、afc
	rUFCON0 = 0; // 禁止FIFO模式
	
	// 波特率设置	DIV_VAL = (PCLK / (bps x 16))-1
	// PCLK_PSYS用66MHz算		余数0.8
	//rUBRDIV0 = 34;	
	//rUDIVSLOT0 = 0xdfdd;
	
	// PCLK_PSYS用66.7MHz算		余数0.18
	// DIV_VAL = (66700000/(115200*16)-1) = 35.18
	rUBRDIV0 = 35;
	// (rUDIVSLOT中的1的个数)/16=上一步计算的余数=0.18
	// (rUDIVSLOT中的1的个数 = 16*0.18= 2.88 = 3
	rUDIVSLOT0 = 0x0888;		// 3个1,查官方推荐表得到这个数字
	
	
}
//串口发送程序,发送一个字节
void uart_putc(char c)
{
	// 串口发送一个字符,其实就是把一个字节丢到发送缓冲区中去
	// 因为串口控制器发送1个字节的速度远远低于CPU的速度,所以CPU发送1个字节前必须
	// 确认串口控制器当前缓冲区是空的(意思就是串口已经发完了上一个字节)
	// 如果缓冲区非空则位为0,此时应该循环,直到位为1
	while (!(rUTRSTAT0 & (1<<1)));
	rUTXH0=c;
	
	
}

//串口接收程序,发送一个字节
char uart_getc(void)
{
	while (!(rUTRSTAT0 & (1<<0)));
	return (rURXH0 & 0x0f);
	
}

Makefile:
uart.bin: start.o led.o clock.o uart.o main.o
	arm-linux-ld -Ttext 0x0 -o uart.elf $^
	arm-linux-objcopy -O binary uart.elf uart.bin
	arm-linux-objdump -D uart.elf > uart_elf.dis
	gcc mkv210_image.c -o mkx210
	./mkx210 uart.bin 210.bin
	
%.o : %.S
	arm-linux-gcc -o $@ $< -c -nostdlib

%.o : %.c
	arm-linux-gcc -o $@ $< -c -nostdlib

clean:
	rm *.o *.elf *.bin *.dis mkx210 -f



作者:wangweijundeqq 发表于2017/11/14 20:15:04 原文链接
阅读:255 评论:0 查看评论

Advanced Programming in UNIX Environment Episode 15

$
0
0

函数stat、fstat、fstatat和lstat

include <sys/stat.h>

int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *buf);
int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);

一旦给出pathname,stat函数将返回与此命名文件有关的信息结构。fstat函数获得已在描述符fd上打开文件的有关信息。lstat函数类似于stat,但是当命名的文件是一个符号链接时,lstat返回该符号链接的有关信息,而不是由该符号链接引用的文件的信息。
fstatat函数为一个相对于当前打开目录(由fd参数指向)的路径名返回文件统计信息。
文件类型
(1)普通文件

二进制可执行文件是一个例外。为了执行程序,内核必须理解其格式。所有二进制可执行文件都遵循一种标准化的格式,这种格式是内核能够确定程序文本和数据的加载位置。

(2)目录文件
(3)快特殊文件
(4)字符特殊文件
(5)FIFO
(6)套接字
(7)符号链接

#include "apue.h"

int main(int argc, char *argv[])
{
    int i;
    struct stat buf;
    char *ptr;

    for(i=1;i<argc;i++)
    {
        printf("%s: ", argv[i]);
        if(lstat(argv[i],&buf)<0)
        {
            err_ret("lstat error");
            continue;
        }
        if(S_ISREG(buf.st_mode))
            ptr="regular";
        else if(S_ISDIR(buf.st_mode))
            ptr="directory";
        else if(S_ISCHR(buf.st_mode))
            ptr="character special";
        else if(S_ISBLK(buf.st_mode))
            ptr="block special";
        else if(S_ISFIFO(buf.st_mode))
            ptr="fifo"
        else if(S_ISLINK(buf.st_mode))
            ptr="symbolic link";
        else if(S_ISSOCK(buf.st_mode))
            ptr="socket";
        else
            ptr="** unknown mode **";
        printf("%s\n",ptr);
    }
    return 0;
}

对每个命令行参数打印文件类型

作者:myfather103 发表于2017/11/14 20:20:02 原文链接
阅读:164 评论:0 查看评论

安卓服务service全解,生命周期,前台服务、后台服务,启动注销、绑定解绑,注册

$
0
0

全栈工程师开发手册 (作者:栾鹏)

python教程全解

定义服务(服务的生命周期)

这里写图片描述

调用context.startService()时依次执行 ->onCreate()- >onStartCommand()->Service running

调用context.stopService()时依次执行 ->onDestroy()

调用context.bindService()时依次执行->onCreate()->onBind()->Service running

调用context.onUnbind()时依次执行 -> onDestroy()

当绑定service和所有客户端解除绑定之后,Android系统将会销毁它,(除非它同时被onStartCommand()方法开启)。

因此,如果你的service是一个纯粹的绑定service,那么你不需要管理它的生命周期。

然而,如果你选择实现onStartCommand()回调方法,那么你必须显式地停止service,因为service此时被看做是开启的。

这种情况下,service会一直运行到它自己调用 stopSelf()或另一个组件调用stopService(),不论它是否和客户端绑定。

另外,如果你的service被开启并且接受绑定,那么当系统调用你的 onUnbind()方法时,如果你想要在下次客户端绑定的时候接受一个onRebind()的调用(而不是调用 onBind()),你可以选择在 onUnbind()中返回true。

onRebind()的返回值为void,但是客户端仍然在它的 onServiceConnected()回调方法中得到 IBinder 对象。

下图展示了这种service(被开启,还允许绑定)的生命周期:
这里写图片描述

代码示例:

代码中设计服务的生命周期,服务设置为前台服务和后台服务。

package com.lp.app.service;


import com.lp.app.Activity1;
import com.lp.app.R;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;


//服务的生命周期
public class Service1 extends Service{

      public final static String action_name = "com.lp.action.service1";
      public final static String key1 = "key1";
      public final static String key2 = "key2"; 

      //当服务被创建时,执行oncreat函数
      @Override
      public void onCreate() {
          Log.v("服务生命周期", "服务第一次被启动");
          pausePlayback();   //将服务放置在后台。默认服务就是后台服务。前台服务是一个通知栏
          startPlayback("显示标题","显示文本");   //打开一个通知栏,点击通知,可以将服务移动至前台
      }

      //onStartCommand为service的重新启动函数
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
        //startBackgroundTask(intent, startId);   //将服务设置到后台运行

        //START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,重新启动后参数Intent将为null。
        //START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
        //START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将原来Intent的值传入。
        //START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。


        //参数flags可以用来确定service的启动方式。START_FLAG_REDELIVERY表示Intent参数是由系统运行时在通过stopSelf显式停止service之前终止它而重新传递的。
                                                //FLAF_RETRY表示service已经在异常终止后重新启动,如果service之前被设为START_STICKY,则会传入这个标志
        Log.v("服务生命周期", "服务被其他窗口通过startService()启动");
        return Service.START_STICKY; 
      }


        public class MyBinder extends Binder {
            Service1 getService() {
              return Service1.this;
            }
          }
        private final IBinder binder = new MyBinder();
        @Override
        public IBinder onBind(Intent intent) {
            // TODO 自动生成的方法存根
            Log.v("服务生命周期", "一个客户端正在通过bindService()函数绑定到本服务");
            return binder;
        }

        @Override
        public void onRebind(Intent intent)
        {
            //在onUnbind()函数已经被调用过后执行
            Log.v("服务生命周期", "一个客户端正在通过bindService()函数绑定到当前服务");
        }

        @Override
        public boolean onUnbind(Intent intent)
        {
            Log.v("服务生命周期", "所有客户端已经通过unbindService()函数脱离绑定");
            return true;  //返回允许绑定
        }


        @Override
        public void onStart(Intent intent,int startId){
            Log.v("服务生命周期", "服务启动");
            super.onStart(intent, startId);
        }

        @Override
        public void onDestroy(){
            Log.v("服务生命周期", "服务销毁");
            super.onDestroy();
        }



      //将一个service移动至前台
      //(前台服务:会在通知一栏显示 ONGOING 的 Notification。当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用)
      //前台服务具有较高的优先级,能在内存不足时,不被杀死
      private void startPlayback(String contenttitle, String contenttext) {
        int NOTIFICATION_ID = 1;

        //创建一个当单击通知时将打开主activity的intent
        Intent intent = new Intent(this, Activity1.class);
        PendingIntent pi = PendingIntent.getActivity(this, 1, intent, 0);

        //设置Notification UI参数
        Notification notification = new Notification(R.drawable.icon,"启动app窗口", System.currentTimeMillis());
        notification.setLatestEventInfo(this, contenttitle, contenttext, pi);

        //设置notification为持续显示
        notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;

        //将service移到前台。
        startForeground(NOTIFICATION_ID, notification);
      }


      //将service移动到后台
      public void pausePlayback() {
        //移动到后台并移除Notification
        stopForeground(true);
      }

}

在manifest文件中注册服务

这里我们hi演示显式启动服务和隐式启动服务。所有这里处理设置服务的名称,还设置了触发条件

<!-- service注册服务,其中permission表示要想外部应用程序使用这个服务,必须要包含的自定义权限(只是个名称) -->
<service 
    android:name="com.lp.app.service.Service1"
    android:permission="com.lp.my_service1_permission">
    <intent-filter>
        <action android:name="com.lp.action.service1"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</service> 

显式的启动和终止服务

  Intent serviceIntent=null;
  //显示启动一个服务
  private void explicitStart() {
    serviceIntent = new Intent(this, Service1.class);
    startService(serviceIntent);
  }

  //显式终止一个服务
  private void explicitStop() {
      if(serviceIntent!=null)  
          stopService(serviceIntent);
  }

隐式的启动和终止服务

隐式启动,相当于把自定义服务注册为系统服务,再以启动系统服务的方式启动自定义服务。

这种方式的和显式的启动和停止服务不同,而是通过intent触发指定名称的事件。而这个事件又触发了注册在manifest文件中的service,所以需要在manifest文件中注册服务时,设定触发源

  //隐式的启动一个Service。相当于把自定义服务注册为系统服务,再以启动系统服务的方式启动自定义服务
  private void implicitStart() {
    Intent intent = new Intent(Service1.action_name);   //在注册服务是设置了intent-filter,所以启动这个,可以启动对应的服务
    intent.putExtra(Service1.key1, "value1"); 
    intent.putExtra(Service1.key2, "value2"); 
    startService(intent);
  }

  //隐式终止一个服务
  private void implicitStop() {
      Intent intent = new Intent(Service1.action_name);
      stopService(intent); 
  }

绑定和解除绑定


 //为Service绑定创建一个service连接
  //service的引用
  private Service1 serviceRef;

  //处理service和 activity之间的连接
  private ServiceConnection mConnection = new ServiceConnection() {
       //当建立连接时调用此函数
       public void onServiceConnected(ComponentName className, IBinder service) {
         serviceRef = ((Service1.MyBinder)service).getService();
         Log.v("服务绑定客户端", "服务绑定建立连接");
       }
       //当service意外断开时执行
       public void onServiceDisconnected(ComponentName className) {
         serviceRef = null;
         Log.v("服务绑定客户端", "服务绑定断开连接");
       }
  };

  Intent bindIntent=null;
  //绑定一个service和activity
  private void bindToService() {
    bindIntent = new Intent(this, Service1.class);
    bindService(bindIntent, mConnection, Context.BIND_AUTO_CREATE);
    //BIND_AUTO_CREATE表示收到绑定请求的时候,如果服务尚未创建,则即刻创建,在系统内存不足需要先摧毁优先级组件来释放内存,且只有驻留该服务的进程成为被摧毁对象时,服务才被摧毁
    //BIND_DEBUG_UNBIND通常用于调试场景中判断绑定的服务是否正确,但容易引起内存泄漏,因此非调试目的的时候不建议使用
    //BIND_NOT_FOREGROUND表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行,该标志位位于Froyo中引入
  }

  //解除一个绑定
  private void unbindToService() {
    if (bindIntent!=null) {
        unbindService(mConnection);
    }
  }
作者:luanpeng825485697 发表于2017/11/14 20:25:34 原文链接
阅读:222 评论:0 查看评论

CCF CSP 2016年12月第2题 工资计算 (模拟 || 打表)

$
0
0

问题描述
试题编号: 201612-2
试题名称: 工资计算
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
问题描述
  小明的公司每个月给小明发工资,而小明拿到的工资为交完个人所得税之后的工资。假设他一个月的税前工资(扣除五险一金后、未扣税前的工资)为S元,则他应交的个人所得税按如下公式计算:
  1) 个人所得税起征点为3500元,若S不超过3500,则不交税,3500元以上的部分才计算个人所得税,令A=S-3500元;
  2) A中不超过1500元的部分,税率3%;
  3) A中超过1500元未超过4500元的部分,税率10%;
  4) A中超过4500元未超过9000元的部分,税率20%;
  5) A中超过9000元未超过35000元的部分,税率25%;
  6) A中超过35000元未超过55000元的部分,税率30%;
  7) A中超过55000元未超过80000元的部分,税率35%;
  8) A中超过80000元的部分,税率45%;
  例如,如果小明的税前工资为10000元,则A=10000-3500=6500元,其中不超过1500元部分应缴税1500×3%=45元,超过1500元不超过4500元部分应缴税(4500-1500)×10%=300元,超过4500元部分应缴税(6500-4500)×20%=400元。总共缴税745元,税后所得为9255元。
  已知小明这个月税后所得为T元,请问他的税前工资S是多少元。
输入格式
  输入的第一行包含一个整数T,表示小明的税后所得。所有评测数据保证小明的税前工资为一个整百的数。
输出格式
  输出一个整数S,表示小明的税前工资。
样例输入
9255
样例输出
10000
评测用例规模与约定
  对于所有评测用例,1 ≤ T ≤ 100000。

解题思路:我的思路是直接计算出对应的区间,然后逆推计算就可以了。网上还有另一种解法,是把税前收入和税后收入当成一个分段函数处理的,感觉思路比较好,程序的可扩展性比较强。解题报告链接

代码如下:

#include <iostream>
#include <algorithm>

using namespace std;

int main(void) {
    int t, salary = 3500, s;
    cin >> t;
    s = t - 3500;
    if(s <= 0) {
        salary += s;
    } else if(0 < s && s <= 1455) {
        salary += (int)(s / 97)*100;
    } else if(1455 < s && s <= 4155) {
        salary += 1500 + (s - 1455) / 90 * 100;
    } else if(4155 < s && s <=7755) {
        salary += 1500 + 3000 + (s - 4155) / 80 * 100;
    } else if(7755 < s && s <= 27255) {
        salary += 1500 + 3000 + 4500 + (s - 7755) / 75*100;
    } else if(27255 < s && s <= 41255) {
        salary += 1500 + 3000 + 4500 + 26000 + (s - 27255) / 70 * 100;
    } else if(41255 < s && s <= 57505) {
        salary += 1500 + 3000 + 4500 + 26000 + 20000 +(s - 41255) / 65 * 100;
    } else if(57505 < s){
        salary += 1500 + 3000 + 4500 + 26000 + 20000 + 25000 + (s - 57505) / 55 * 100;
    }
    cout << salary << endl;
    return 0;
}


作者:qq_26658823 发表于2017/11/14 20:56:19 原文链接
阅读:108 评论:0 查看评论

ElasticSearch环境搭建与运行

$
0
0

安装环境为centos,在安装Elasticsearch之前一定要先安装jdk1.8。因为他需要jdk1.8才可以运行起来。

1.ElasticSearch5.6.1安装包的获取

通过下面Elastic公司的官网获取ElasticSearch的安装包

https://www.elastic.co/

下面就是Elastic公司的主页,在主页上方,点击Products产品,就可以进入该公司的产品列表。

进入Elasticseach的主页,并点击Downloand进入下载页面,选择下载tar压缩包。


Elasticsearch现在做的很棒,还提供了中文版权威指南。

下载完成之后就可以开始解压了。

tar -zxvf elasticsearch-2.3.4.tar.gz 你可以给他解压到其他文件夹下面。

解压后,进入目录,通过 ls -l 命令,我们可以看到目录里的文件。

ElasticSearch包含的主要文件夹及功能如下,logs和data文件夹,在ES启动后生成,而且用户可以自定义他们所在的位置,默认是在主目录里。

bin

含有运行ElasticSearch实例和管理插件的一些脚本

config

主要是一些设置文件,如:elasticsearch.yml和logging.yml等

lib

包含一些相关的包文件等

plugins

包含相关的插件文件

logs

日志文件

data

ElasticSearch中存放数据的地方


通过,bin目录里的elasticsearch命令,即可启动服务。但是如果我们是root用户的话这里是不可能启动成功的。因为es规定了,不可以使用root用户,所以我们这里需要创建一个用户并且给他赋予权限。

useradd es -p es 新增一个用户叫做es 密码也叫es

chown -R es:es elasticsearch-2.3.4/  授权

然后切换es用户运行bin目录里的elasticsearch命令

启动完成之后使用浏览器可以看到http://127.0.0.1:9200


这就代表启动成功了。

3.配置文件elasticsearch.yml的说明


下面一些最常见的配置项。

设置数据路径和日志路径:path.data和path.logs

例如:

path.logs: /var/es_log

path.data: /var/es_data

也可以一次设置多个路径

例如:

path.data:

    - /mnt/ElasticSearch_1

    - /mnt/ElasticSearch_2

    - /mnt/ElasticSearch_3

设置集群的名称:cluster.name

例如:

cluster.name: ruan_ElasticSearch

设置节点的名称:node.name

例如:

node.name: ruan_node

主机IP:network.host

默认值为回环地址127.0.0.1。如果是单节点集群,不需要设置。但多节点集群必须通过此配置,把节点连接成一个集群。

例如:

network.host: 192.168.1.10

关于主机设置,还有一些特殊的属性值,比如_local_,_site_,_global_和一些修饰语如:ip4和ip6。




作者:liaodehong 发表于2017/11/14 20:58:23 原文链接
阅读:120 评论:0 查看评论

git权威指南总结六:git协议和工作协同

$
0
0

git支持的协议

git提供了丰富的协议支持,比如:SSH/GIT/HTTP/HTTPS/FTP等等。所有的协议主要可以分为两大类:智能协议和哑协议
智能协议:在会话中使用智能协议,会在会话的两个版本库的各自一段中打开相应的程序进行数据交换。使用智能协议最直观的印象就是在数据传输过程中会有清晰的进度显示,并且因为是按需传输所以传输量更小,传输速度更快。SSH/GIT及本地协议(file://)等就属于智能协议
哑协议:和智能协议相对的就是哑协议。使用哑协议访问远程版本库的时候,远程版本库不会自动运行辅助程序,而是完全依靠客户端去主动发现。使用哑协议最直观的印象就是传输速度慢,而且传输进度不可见,不知道什么时候才能完成数据传输。FTP等就属于哑协议
以git项目本身为例,看看如何使用不同的协议地址进行版本库克隆的
使用智能git协议:git clone git://git.kernel.org/pub/scm/git/git.git
使用HTTP(S)哑协议:git clone http://www.kernel.org/pub/scm/git.git
使用HTTP(S)智能协议:git clone https://github.com/git/git.git


多用户协同的本地模拟

这里我们使用本地协议模拟多用户操作,本地协议地址为:file:///path/repo.git
首先,创建一个裸版本库git init --bare test/share.git,这里需要注意一点是:创建的裸版本库需要放在gitpath目录下,即bin目录所在包下
然后,我们创建第一个user1用户克隆之前创建的版本库,不过这次克隆和之前的克隆不一样,我们使用本地协议进行克隆:git clone file:///test/share.git user1,即可假设user1为一个用户
可以为用户设置专属用户名和邮箱地址:git config user.name Xxx git config user.email Xxxx,这里只是进行局部配置,不需要使用任何参数
接下来,user1中进行一次提交echo "hello world" > index.txt; git add index.txt; ;git commit -m "async commit test1;",然后将user1用户的提交推送到上游版本库中git push origin master
然后我们创建用户user2克隆版本库,模拟多个用户进行操作git clone file:///test/share.git user2
可以为用户设置专属用户名和邮箱地址:git config user.name Xxx git config user.email Xxxx,这里只是进行局部配置,不需要使用任何参数
然后现在使用命令:git log --pretty=oneline -1查看历史提交版本,可以看到历史提交版本会显示之前在user1中提交ID


强制非快进式推送

首先我们需要知道什么叫做非快进式推送,所谓快进式推送,是指要推送的本地版本库的提交是建立在远程版本库相应分支的现有提交基础上的,简单来说就是远程版本库相应分支的最新提交和本地版本库最新提交的祖先提交相等
比如user1用户修改了readme.txt文件并进行了提交,而user2用户此时也对readme.txt文件进行修改并进行提交,而此时的user2的提交会失败,这是因为非快进式推送导致的,git不能判断提交哪一个推送,所以就默认只会保存第一个提交
如果此时想要强制提交user2用户对readme.txt文件的修改,可以使用强制提交命令:git push -f origin master即可


避免非快进式推送:合并后推送

事实上,理性的工作协同要尽量避免使用非快进式推送,如果在向服务器推送过程中由于他人的提交导致遇到了非快进式推送的警告,可以使用如下操作代替强制推送:执行git pull获取服务器最新数据并和本地的提交进行合并,合并成功后再向服务器进行提交
主要来说,合并后推送主要分为两步:
1.git pull:获取上游版本库最新提交,并和本地的提交进行合并
2.git push:将合并后的数据进行提交


如何禁止非快进式推送

有两种方式来禁止该推送方式:
1.改变版本库的配置变量:receive denyNonFastForwords设置为true可以禁止任何用户的非快进式推送
git config receive.denyNonFastForwords true
2.通过钩子脚本进行设置,这种方式可以设置:只对部分用户进行限制,而允许特定的用户执行非快进式推送


参考文献

git权威指南一书
作者:qq_27905183 发表于2017/11/14 21:18:08 原文链接
阅读:105 评论:0 查看评论

c++多态中关于参数匹配推导与模板参数推导

$
0
0

在调用一个函数的时候,当参数是基类的时候,有时候传子类对象也是能够正常运行;
在调用模板函数的时候,模板有时候能够自动推导出参数的类型,得到理想的结果,但是很多时候模板参数并不会按我们想象的那样进行推导,从而调用错误;下面是自己遇见的一些小的总结

作者:hll174 发表于2017/11/14 21:23:11 原文链接
阅读:122 评论:0 查看评论

haskell基础课:类型系统解读

$
0
0

最近忙成狗了,吭哧吭哧终于把家搬完了,以后就长久的住在新家了,由于刚搬家,网线还没有接,又过了一个星期家里没网的日子。这一段时间又没时间好好整理haskell。甚是遗憾。从上次haskell实现Graham扫描算法到现在已经三周有余,这次分析一下haskell类型系统。

首先回忆一下C语言是怎么构造新类型的。

struct Test {
    int index;
#define NAME_LEN 32
    char name[NAME_LEN];
    void (*get_name)(struct Test *);
};

这就是典型的C语言构造新类型的方法,即所谓的结构体。诸如此类的还有枚举类型、联合体。结构体定义了一个类型名字,成员都有其名字,并且根据名字访问到各个成员。

一、代数数据类型(algebraic data type)与类型构造子(data constructor)

定义类型: data TypeName = TypeConstructor [param] [| TypeConstructor [param]]

其中param可有可无,但是要注意如果param存在,那么其肯定是一种类型。比如data Test = Test Int,表示传给一个Int类型的参数给类型构造子Test,这时候在ghci中执行:t Test可以看到

*Main> :t Test
Test :: Int -> Test

还要注意第一个Test和第二个Test没有任何联系,第一个Test只是表示该类型名字叫Test,在代码中实际使用的是第二个Test(也就是类型构造子)。

二、类型解构与模式匹配

在前面实现Graham扫描算法的例子中,我们使用了很多的函数,基本上都是通过模式匹配实现的。再举个例子,譬如求和函数:

sum (x:xs) = x + sum xs
sum [] = 0

在第一次看到行如(x:xs)的时候,可能会有疑问–为什么有个括号?其实(x:xs)中的冒号(:)是一个类型构造子。在ghci中输入:t (:)可以看到

*Main> :t (:)
(:) :: a -> [a] -> [a]

(:)就是用来构造列表的,而形如[1,2,3]的构造方式其实等价于(1:(2:(3:[])))。

说到这里,其实基本上就清楚了,模式匹配其实就是在对类型进行解构,使用的方法就是通过类型构造子的规定按照顺序进行参数匹配。

现在对前面定义的Test类型进行解构,在ghci中输入如下:

*Main> data Test=Test Int
*Main> getTest (Test a)=a
*Main> getTest (Test 10)
10

三、类型匹配

通过模式匹配得到类型之后,haskell还会进一步检查类型是否匹配。

关于类型匹配,这里可以先简单实验一下,在ghci中输入如下:

*Main> (\x->x+1)1
2
*Main> 
*Main> 
*Main> (\x->x+1)[]

<interactive>:37:1: error:
    • Non type-variable argument in the constraint: Num [a]
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall a. Num [a] => [a]
*Main> 

第一次输入一个lambda表达式紧跟一个数1,这时候ghci给出了我们想要的结果2。当第二次我们入[]时,报的错误有点意思。

类型错误,这里有两点信息:

  • lambda表达式是匿名函数,所以函数参数的匹配似乎和函数名字没有直接关系。
  • 错误的直接原因显示为类型不匹配,其实haskell自己已经通过类型系统推导出了当前输入x的类型是Num [a], 而实际上运算+期待的参数是Num a,所以产生类型错误。

类型匹配就是由haskell的类型推导系统完成的。

作者:abcamus 发表于2017/11/14 21:36:54 原文链接
阅读:121 评论:0 查看评论

arcgis api for js入门开发系列十五台风轨迹

$
0
0

上一篇实现了demo的地图最近设施点路径分析,本篇新增台风轨迹,截图如下:


 下面简单介绍相关知识点:

警戒线

警戒线坐标集合:

var lineArr24=[[127,34],[127,21],[110,15]];//24小时警戒线坐标集合
var lineArr48=[[132,34],[132,15],[105,0]];//48小时警戒线集合

线符号样式SimpleLineSymbol:

var symbol24 = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255,0,0]), 1);
var symbol48 = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_DASHDOTDOT, new dojo.Color([255,255,153]), 1);
台风操作面板

台风路径符号

点符号PictureMarkerSymbol

var TFQ_Symbol=new esri.symbol.PictureMarkerSymbol(getRootPath()+'content/images/weather/typhoon.png', 40, 40)

线符号SimpleLineSymbol:

var T_Symbol=new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID,
new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID,
new dojo.Color([255, 165, 0]), 0.01), new dojo.Color([255,20,147, 0.35])); var Line_symbol= new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_DASHDOTDOT, new dojo.Color([255,215,0]), 1);
扇形风圈

备注:团队承接webgis/gis毕业设计以及webgis项目等业务,欢迎有相关需求的客户来咨询
GIS之家接受webgis开发遇到的技术疑点难点在线咨询,采取在线分答计时收费模式,有需要的加QQ:406503412
欢迎关注我的GIS之家微信公众号(扫描右上角头像):gishome
GIS之家论坛(推荐):GIS之家论坛
GIS作品:GIS之家
GIS之家知乎专栏:GIS之家知乎专栏
GIS之家交流群一:432512093(已满)
GIS之家交流群二:296438295(已满)
GIS之家交流群三:632467934
作者:liguoweioo 发表于2017/11/14 21:41:24 原文链接
阅读:131 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


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