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

leetcode: 55. Jump Game

$
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.

Determine if you are able to reach the last index.

For example:
A = [2,3,1,1,4], return true.

A = [3,2,1,0,4], return false.

AC

class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """

        m = 0
        for i, n in enumerate(nums):
            if i > m:
                return False
            m = max(m, i+n)
        return True


作者:JNingWei 发表于2017/11/18 16:40:10 原文链接
阅读:8 评论:0 查看评论

leetcode: 56. Merge Intervals

$
0
0

Q

Given a collection of intervals, merge all overlapping intervals.

For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

AC

class Interval(object):
    def __init__(self, s=0, e=0):
        self.start = s
        self.end = e

class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[Interval]
        :rtype: List[Interval]
        """
        if not intervals:
            return []

        intervals.sort(key = lambda x: x.start, reverse=True)
        stack = []
        tmp = intervals.pop()
        while intervals:
            x = intervals.pop()
            if tmp.end >= x.start:
                tmp.end = max(tmp.end, x.end)
            else:
                stack.append(tmp)
                tmp = x
        stack.append(tmp)
        return stack


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

leetcode: 57. Insert Interval

$
0
0

Q

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).

You may assume that the intervals were initially sorted according to their start times.

Example 1:
Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9].

Example 2:
Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16].

This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].

AC

# Definition for an interval.
class Interval(object):
    def __init__(self, s=0, e=0):
        self.start = s
        self.end = e

class Solution(object):
    def insert(self, intervals, newInterval):
        """
        :type intervals: List[Interval]
        :type newInterval: Interval
        :rtype: List[Interval]
        """
        i = 0
        while i<len(intervals) and intervals[i].end<newInterval.start:
            i+=1
        j = i
        while j<len(intervals) and intervals[j].start<=newInterval.end:
            j+=1
        if i<j:
            newInterval.start = min(newInterval.start, intervals[i].start)
            newInterval.end = max(newInterval.end, intervals[j-1].end)
            del intervals[i:j]
        intervals.insert(i, newInterval)
        return intervals


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

leetcode: 58. Length of Last Word

$
0
0

Q

Given a string s consists of upper/lower-case alphabets and empty space characters ’ ‘, return the length of last word in the string.

If the last word does not exist, return 0.

Note: A word is defined as a character sequence consists of non-space characters only.

Example:

Input: "Hello World"
Output: 5

AC

class Solution(object):
    def lengthOfLastWord(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0

        tmp = s.strip().split(' ')[-1]
        return len(tmp)


作者:JNingWei 发表于2017/11/18 16:44:47 原文链接
阅读:12 评论:0 查看评论

leetcode: 59. Spiral Matrix II

$
0
0

Q

Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order.

For example,
Given n = 3,

You should return the following matrix:

[
 [ 1, 2, 3 ],
 [ 8, 9, 4 ],
 [ 7, 6, 5 ]
]

AC

class Solution(object):
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        dirs = [(1,0),(0,1),(-1,0), (0,-1)]

        steps = [n, n-1, n-1, n-2]

        m = [[0] *n for i in range(n)]

        dindex = 0
        x, y = -1, 0
        moves = 0
        for i in range(1, n*n+1):
            dx, dy = dirs[dindex]
            x, y = x+dx, y+ dy
            m[y][x] = i
            moves += 1
            if moves == steps[dindex]:
                moves = 0
                dindex = (dindex+1)%4
                if dindex==0:
                    steps =[step-2 for step in steps]
        return m


作者:JNingWei 发表于2017/11/18 16:46:13 原文链接
阅读:8 评论:0 查看评论

leetcode: 60. Permutation Sequence

$
0
0

Q

The set [1,2,3,…,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

"123"
"132"
"213"
"231"
"312"
"321"

Given n and k, return the kth permutation sequence.

Note: Given n will be between 1 and 9 inclusive.

AC

class Solution(object):
    def getPermutation(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: str
        """
        def factorial(m):
            if m==1:return 1
            return m*factorial(m-1)
        if n==1:
            return "1"
        units = [factorial(m) for m in range(n-1, 0, -1)]
        i=0
        result = ""
        s = range(1,n+1)
        while k:
            m = k/units[i]
            k = k%units[i]
            if k:
                num = s[m]
            else:
                num = s[m-1]
            result += str(num)
            s.remove(num)
            i+=1
        result += ''.join(map(str, sorted(list(s), reverse=True)))
        return result


作者:JNingWei 发表于2017/11/18 16:47:53 原文链接
阅读:1 评论:0 查看评论

Python3与OpenCV3.3 图像处理(补)--第三节补充

$
0
0

       第三节有一段代码是操作像素,将图像呈现出负片的效果,也就是像素取反。这段代码本身是没有问题的,但是运行起来后会发现你所提供的图片越大,处理起来速度越慢,这是因为我们在代码里使用了嵌套多层for循环,对于我们练习这样是没问题的,但是如果在实际项目中这样使用,会导致系统运行特别慢。那么我们该怎么办呢,其实OpenCV中有像素取反的方法,只需把for循环代码改为如下一行代码,就可以了。这样即能实现负片效果,也缩短了处理图片像素的时间

cv.bitwise_not(image)


作者:gangzhucoll 发表于2017/11/18 16:48:44 原文链接
阅读:0 评论:0 查看评论

poj1068 Parencodings【模拟】【刷题计划】

$
0
0
Parencodings
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 27375   Accepted: 16094

Description

Let S = s1 s2...s2n be a well-formed string of parentheses. S can be encoded in two different ways: 
q By an integer sequence P = p1 p2...pn where pi is the number of left parentheses before the ith right parenthesis in S (P-sequence). 
q By an integer sequence W = w1 w2...wn where for each right parenthesis, say a in S, we associate an integer which is the number of right parentheses counting from the matched left parenthesis of a up to a. (W-sequence). 

Following is an example of the above encodings: 

S (((()()())))
P-sequence 4 5 6666
W-sequence 1 1 1456

Write a program to convert P-sequence of a well-formed string to the W-sequence of the same string. 

Input

The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case is an integer n (1 <= n <= 20), and the second line is the P-sequence of a well-formed string. It contains n positive integers, separated with blanks, representing the P-sequence.

Output

The output file consists of exactly t lines corresponding to test cases. For each test case, the output line should contain n integers describing the W-sequence of the string corresponding to its given P-sequence.

Sample Input

2
6
4 5 6 6 6 6
9 
4 6 6 6 6 8 9 9 9

Sample Output

1 1 1 4 5 6
1 1 2 4 5 1 1 3 9

Source

题意:给你t组数据,每组数据输入一个n,再输入n个数,表示第i个右括号的左边有pi个左括号,比如题目上的 4 5 6 6 6 6,第1个右括号的左边有4个左括号,第2个右括号的左边有5个左括号,以此类推,要求输出的是,第i个右括号的左边包含多少个已经与左括号匹配好的完整括号,比如题目上的1 1 1 4 5 6 ,在第1个右括号的左边有1个左括号与之匹配,所以第1个右括号的左边有1个完整匹配的括号,后边两个1也是这样推出来的,直到第4个右括号,它和从左到右数的第3个左括号匹配,而它们中间包括了3个已经匹配好的完整括号,最后加上自身匹配好的完整括号,总共有4个已经完整匹配好的括号。

(为神魔感觉我的翻译这么辣鸡啊。。嘤嘤嘤)

思路:模拟大法好咯。看到数据量比较小,我就放心大胆的用数组模拟好了,左括号为0,右括号为1,完整括号为-1,读入的时候,模拟括号的排列顺序,最后进行统计,将统计的完整括号匹配的值存入一个新的数组,最后输出就好啦。

统计-1的总数除以2才是完整括号数。

#include<stdio.h>
#include<string.h>

int main()
{
    int str[50],num[50];
    int t,n,i,j,number,count,sum;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(str,0,sizeof(str));
        for(i = 0; i < n; i ++)
        {
            scanf("%d",&number);
            str[number+i] = 1;//右括号处赋值为1 
        }
        sum = 0;//记录下标
        for(i = 0; i < 2*n; i ++)
        {
            count = 0;//统计完整括号数 
            if(str[i]== 1)//遇到右括号时 
            {
                for(j = i; j >= 0; j --)//从遇到的右括号处向左统计,共有多少个完整括号 
                {
                    if(str[j] == -1)//遇到完整括号,总数加1 
                        count ++;
                    if(str[j] == 0)//如果遇到与之匹配的左括号,结束循环 
                        break;
                }
                count /=2;//总数除以2才是完整括号数 
                str[i] = str[j] = -1;//将匹配好的左右括号标记为-1 
                num[sum++] = count +1; //最后加上自身 
            }
        }
        for(i = 0; i < n-1; i ++)
            printf("%d ",num[i]);
        printf("%d\n",num[n-1]);
    }
    return 0;
}


作者:hello_sheep 发表于2017/11/18 15:31:21 原文链接
阅读:51 评论:0 查看评论

JS获取节点的兄弟,父级,子级元素的方法

$
0
0

先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比。

JS的方法会比JQUERY麻烦很多,主要则是因为FF浏览器,FF浏览器会把你的换行也当最DOM元素

复制代码代码如下:

<div id="test">
<div></div>
<div></div>
</div>

原生的JS获取ID为test的元素下的子元素。可以用:

var a = docuemnt.getElementById("test").getElementsByTagName("div");  这样是没有问题的

此时a.length=2;

但是如果我们换另一种方法

var b =document.getElementById("test").childNodes; 

此时b.length 在IE浏览器中没问题,其依旧等于2,但是在FF浏览器中则会使4,是因为FF把换行也当做一个元素了。

所以,在此,我们就要做处理了,需遍历这些元素,把元素类型为空格而且是文本都删除。

复制代码代码如下:

function del_ff(elem){
var elem_child = elem.childNodes;
for(var i=0; i<elem_child.length;i++){
if(elem_child[i].nodeName == "#text" && !/\s/.test(elem_child.nodeValue))
{elem.removeChild(elem_child)
}
}
}

上述函数遍历子元素,当元素里面有节点类型是文本并且文本类型节点的节点值是空的。就把他删除。

nodeNames可以得到一个节点的节点类型,/\s/是非空字符在JS里的正则表达式。前面加!,则表示是空字符

test() 方法用于检测一个字符串是否匹配某个模式.语法是: RegExpObject.test(string)

如果字符串 string 中含有与 RegExpObject 匹配的文本,则返回 true,否则返回 false。

nodeValue表示得到这个节点里的值。

removeChild则是删除元素的子元素。

之后,在调用子,父,兄,这些属性之前,调用上面的函数把空格清理一下就可以了

复制代码代码如下:

<div id="test">
<div></div>
<div></div>
</div>
<script>
function dom() {
var s= document.getElementById("test");
del_ff(s);    //清理空格
var chils= s.childNodes;  //得到s的全部子节点
var par=s.parentNode;   //得到s的父节点
var ns=s.nextSbiling;   //获得s的下一个兄弟节点
var ps=s.previousSbiling;  //得到s的上一个兄弟节点
var fc=s.firstChild;   //获得s的第一个子节点
var lc=s.lastChile;   //获得s的最后一个子节点

}
</script>


下面介绍JQUERY的父,子,兄弟节点查找方法

jQuery.parent(expr)  找父亲节点,可以传入expr进行过滤,比如$("span").parent()或者$("span").parent(".class")

jQuery.parents(expr),类似于jQuery.parents(expr),但是是查找所有祖先元素,不限于父元素

jQuery.children(expr).返回所有子节点,这个方法只会返回直接的孩子节点,不会返回所有的子孙节点

jQuery.contents(),返回下面的所有内容,包括节点和文本。这个方法和children()的区别就在于,包括空白文本,也会被作为一个

jQuery对象返回,children()则只会返回节点

jQuery.prev(),返回上一个兄弟节点,不是所有的兄弟节点

jQuery.prevAll(),返回所有之前的兄弟节点

jQuery.next(),返回下一个兄弟节点,不是所有的兄弟节点

jQuery.nextAll(),返回所有之后的兄弟节点

jQuery.siblings(),返回兄弟姐妹节点,不分前后

jQuery.find(expr),跟jQuery.filter(expr)完全不一样。jQuery.filter()是从初始的jQuery对象集合中筛选出一部分,而jQuery.find()的返回结果,不会有初始集合中的内容,比如$("p"),find("span"),是从<p>元素开始找<span>,等同于$("p span")

作者:guo13313 发表于2017/11/18 18:43:34 原文链接
阅读:42 评论:0 查看评论

jQuery中off()方法函数的使用,单击一次,响应了两次

$
0
0

项目在测试阶段,页面中有这么一个bug,绑定的单击事件,单击一次,却触发了两次单击的响应。

网上搜了一下相关的资料,发现是js中绑定的事件太多了,使用的是 .on(),在这里需要使用 .off()进行解绑即可。


off()函数用于移除元素上绑定的一个或多个事件的事件处理函数

off()函数主要用于解除由on()函数绑定的事件处理函数。

该函数属于jQuery对象(实例)。

off()函数的介绍:

语法

jQuery 1.7 新增该函数。其主要有以下两种形式的用法:

用法一

jQueryObject.off( [ events [, selector ] [, handler ] ] )

用法二

jQueryObject.off( eventsMap [, selector ] )

参数

参数 描述
events 可选/String类型一个或多个用空格分隔的事件类型和可选的命名空间,例如"click"、"focus click"、"keydown.myPlugin"。
eventsMap Object类型一个Object对象,其每个属性对应事件类型和可选的命名空间(参数events),属性值对应绑定的事件处理函数(参数handler)。
selector 可选/String类型一个jQuery选择器,用于指定哪些后代元素可以触发绑定的事件。如果该参数为null或被省略,则表示当前元素自身绑定事件(实际触发者也可能是后代元素,只要事件流能到达当前元素即可)。
handler 可选/Function类型指定的事件处理函数。

off()函数将会移除当前匹配元素上为后代元素selector绑定的events事件的事件处理函数handler

如果省略参数selector,则移除为任何元素绑定的事件处理函数。

参数selector必须与通过on()函数添加绑定时传入的选择器一致。

如果省略参数handler,则移除指定元素指定事件类型上绑定的所有事件处理函数。

如果省略了所有参数,则表示移除当前元素上为任何元素绑定的任何事件类型的任何事件处理函数。

返回值

off()函数的返回值为jQuery类型,返回当前jQuery对象本身。

实际上,off()函数的参数全是筛选条件,只有匹配所有参数条件的事件处理函数才会被移除。参数越多,限定条件就越多,被移除的范围就越小。

示例&说明

请参考下面这段初始HTML代码:

<input id="btn1" type="button" value="点击1" />
<input id="btn2" type="button" value="点击2" />
<a id="a1" href="#">CodePlayer</a>

首先,我们为上述button和<a>元素绑定事件,然后使用off()函数解除事件绑定,相应的代码如下:

function btnClick1(){
    alert( this.value + "-1" );
}

function btnClick2(){
    alert( this.value + "-2" );
}

var $body = $("body");

// 为所有button元素的click事件绑定事件处理函数btnClick1
$body.on("click", ":button", btnClick1 );

// 为所有button元素的click事件绑定事件处理函数btnClick2
$body.on("click", ":button", btnClick2 );

//为所有a元素绑定click、mouseover、mouseleave事件
$body.on("click mouseover mouseleave", "a", function(event){
    if( event.type == "click" ){
        alert("点击事件");
    }else if( event.type == "mouseover" ){
        $(this).css("color", "red");
    }else{
        $(this).css("color", "blue");       
    }
});


// 移除body元素为所有button元素的click事件绑定的事件处理函数btnClick2
// 点击按钮,btnClick1照样执行
$body.off("click", ":button", btnClick2);


// 移除body元素为所有button元素的click事件绑定的所有事件处理函数(btnClick1和btnClick2)
// 点击按钮,不会执行任何事件处理函数
// $body.off("click", ":button");


// 注意: $body.off("click", "#btn1"); 无法移除btn1的点击事件,off()函数指定的选择器必须与on()函数传入的选择器一致。


// 移除body元素为所有元素(包括button和<a>元素)的click事件绑定的所有处理函数
// 点击按钮或链接,都不会触发执行任何事件处理函数
// $("body").off("click");


// 移除body元素为所有元素的任何事件绑定的所有处理函数
// 点击按钮,或点击链接或者鼠标移入/移出链接,都不会触发执行任何事件处理函数
// $("body").off( );

运行代码(其他代码请自行复制到演示页面运行)

此外off()函数还可以只移除指定命名空间的事件绑定。

var $btn1 = $("#btn1");

$btn1.on("click.foo.bar", function(event){
    alert("click-1");
});
$btn1.on("click.test", function(event){
    alert("click-2");
});
$btn1.on("click.test.foo", function(event){
    alert("click-3");
});

$btn1.off("click.test"); // 移除click-2、click-3

// $btn1.off("click.foo");  // 移除click-1、click-3

// $btn1.off("click.foo.bar");  // 移除click-1

// $btn1.off("click");  // 移除所有click事件处理函数(click-1、click-2、click-3)

// $btn1.off(".foo");  // 移除所有包含命名空间foo的事件处理函数,不仅仅是click事件

原文链接:http://www.365mini.com/page/jquery-off.htm



作者:guo13313 发表于2017/11/18 18:59:58 原文链接
阅读:44 评论:0 查看评论

BZOJ1305: [CQOI2009]dance跳舞

$
0
0

Description

一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

Input

第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为’Y’当且仅当男孩i和女孩j相互喜欢。

Output

仅一个数,即舞曲数目的最大值。

Sample Input

3 0

YYY

YYY

YYY

Sample Output

3
HINT

N<=50 K<=30

题目传送门

嗯…当时的第一个想法是最大二分图匹配,可是…欸?他好像跑不过去??
然后把当时学过的能用的算法都列了一遍,于是选中了网络流
思路比较清晰,建图还是20分钟能搞得定的(正确性也OK)
然后…我就在模拟还是二分的边界上卡了整整..嗯..1个小时吧
模拟一遍,如果不是满流就跳出来,然而….卡了半天硬是没调出来
于是怒而转用二分每次重新建图0.0
其实模拟更容易用,调出来再放模拟代码(然而我估计等我AFO了都不会再调一遍)

二分代码如下:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
    int x,y,c,next,other;
}a[210000];int len,last[210000];
void ins(int x,int y,int c)
{
    int k1,k2;
    len++;k1=len;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;

    len++;k2=len;
    a[len].x=y;a[len].y=x;a[len].c=0;
    a[len].next=last[y];last[y]=len;

    a[k1].other=k2;a[k2].other=k1;
}
int h[210000],list[210000];
int st,ed,n,k;
bool bt_h()
{
    memset(h,0,sizeof(h));
    h[st]=1;list[1]=st;
    int head=1,tail=2;
    while(head!=tail)
    {
        int x=list[head];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(a[k].c>0 && h[y]==0)
            {
                h[y]=h[x]+1;
                list[tail++]=y;
            }
        }
        head++;
    }
    if(h[ed]>0)return true;
    return false;
}
int find_flow(int x,int f)
{
    if(x==ed)return f;
    int s=0,t;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(h[y]==h[x]+1 && a[k].c>0 && s<f)
        {
            s+=(t=find_flow(y,min(a[k].c,f-s)));
            a[k].c-=t;a[a[k].other].c+=t;
        }
    }
    if(s==0)h[x]=0;
    return s;
}
char map[60][60];
/*
 boy1 1~n
 boy2 n+1~n+n
 girl1 n+n+1~n+n+n
 girl2 n+n+n+1~n+n+n+n
*/
bool check(int w)
{
    len=0;memset(last,0,sizeof(last));
    st=4*n+1;ed=4*n+2;
    for(int i=1;i<=n;i++)
    {
        ins(st,i,w);ins(i,i+n,k);
        for(int j=1;j<=n;j++)
        {
            if(map[i][j]=='Y')ins(i,j+2*n,1);
            else ins(i+n,j+3*n,1);
        }
    }
    for(int i=1;i<=n;i++)ins(i+3*n,i+2*n,k),ins(i+2*n,ed,w);
    int q=0;
    while(bt_h())q+=find_flow(st,999999999);
    if(w*n==q)return true;
    return false;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%s",map[i]+1);
    int l=0,r=n,ans;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(check(mid)){ans=mid;l=mid+1;}
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

by_lmy

作者:HeroDeathes 发表于2017/11/18 19:05:13 原文链接
阅读:41 评论:0 查看评论

从零开始前端学习[53]:js中的获取元素的方式

$
0
0

js中的获取元素的方式

  • 通过getElementById的形式获取
  • 通过getElementsByClassName形式获取元素
  • 通过getElementsByTagName标签选择元素
  • 静态获取和动态获取过程
  • 通过选择器来获取元素
  • js相关的命名规范

提示
博主:章飞_906285288
博客地址:http://blog.csdn.net/qq_29924041


通过getElementById的形式获取

getElementById这个就不用多说了,最开始使用的就是这个,也就是需要给标签一个id,然后通过标签选择到对应的对象。因为id是唯一的,所以也获取的这个变量其实也是唯一的

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <meta charset="UTF-8"><!--申明当前网页的编码集UTF-8-->
  <meta name="Generator" content="EditPlus®">   <!--编辑器的名称-->
  <meta name="Author" content="作者是谁">       
  <meta name="Keywords" content="关键词">
  <meta name="Description" content="描述和简介">
  <style type="text/css">                                        
        body,dl,dd,dt,p,h1,h2,h3,h4,h5,h6{ margin: 0;}
        ul,ol{margin: 0; list-style: none; padding: 0;}
        a{ text-decoration: none; }
        *{ margin: 0; padding: 0; }
      .main{width: 1200px;margin: 10px auto;box-shadow: 0 0 10px 0 deeppink}
    p{width: 200px ;height: 200px;background: blue;}
  </style>
</head>
<body>
  <div class="main">
    <p id="id_p">p</p>
  </div>
  <script>
    var id_p = document.getElementById("id_p");
    id_p.onclick = function () {
        this.style.backgroundColor = "red";
    }
  </script>
</body>
</html>

这里写图片描述
最简单的效果


过getElementsByClassName形式获取元素

既然有getElementsById那么与之对应的肯定也有根据className来获取的变量名,那就是cgetElementsById,可能会有点奇怪,就是id是唯一的,但是很多时候,我们的className并不是唯一的啊。那么对应获取到的应该也不是唯一的。是的,通过getElementsByClassName获取到的是一个对象数组,是一个数组,并不是一个唯一的值

var abox = document.getElementsByClassName("box");
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <meta charset="UTF-8"><!--申明当前网页的编码集UTF-8-->
  <meta name="Generator" content="EditPlus®">   <!--编辑器的名称-->
  <meta name="Author" content="作者是谁">       
  <meta name="Keywords" content="关键词">
  <meta name="Description" content="描述和简介">
  <style type="text/css">                                        
        body,dl,dd,dt,p,h1,h2,h3,h4,h5,h6{ margin: 0;}
        ul,ol{margin: 0; list-style: none; padding: 0;}
        a{ text-decoration: none; }
        *{ margin: 0; padding: 0; }
    .main{width: 1200px;box-shadow: 0 0 10px 0 deeppink;margin: 10px auto}
    p{margin: 10px auto;width: 150px;height: 150px;background: greenyellow }
  </style>
</head>
<body>
  <div class="main">
    <p class="class_p">1</p>
    <p class="class_p">2</p>
    <p class="class_p">3</p>
  </div>
  <script>
   var classes_p = document.getElementsByClassName("class_p");
   console.log(classes_p.length);
   classes_p[0].onclick = function () {
       this.style.color ="red";
   }
   classes_p[1].onclick = function () {
       this.style.backgroundColor ="blue";
   }
   classes_p[2].onclick = function () {
       this.innerText = "换个内容试试";
   }

  </script>
</body>
</html>

这里写图片描述

注意:兼容:不兼容IE8以及以下


通过getElementsByTagName标签选择元素

与选择器一样,选择器可以使用标签选择器,那么在js中也是可以通过标签来选择到对应的标签的,它的使用跟getElementsByClassName一样,获取到的是一组数组。

var a_p = document.getElementsByTagName("p");
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <meta charset="UTF-8"><!--申明当前网页的编码集UTF-8-->
  <meta name="Generator" content="EditPlus®">   <!--编辑器的名称-->
  <meta name="Author" content="作者是谁">
  <meta name="Keywords" content="关键词">
  <meta name="Description" content="描述和简介">
  <style type="text/css">
    body,dl,dd,dt,p,h1,h2,h3,h4,h5,h6{ margin: 0;}
    ul,ol{margin: 0; list-style: none; padding: 0;}
    a{ text-decoration: none; }
    *{ margin: 0; padding: 0; }
    .main{width: 1200px;box-shadow: 0 0 10px 0 deeppink;margin: 10px auto}
    p{margin: 10px auto;width: 150px;height: 150px;background: greenyellow }
  </style>
</head>
<body>
<div class="main">
  <p >1</p>
  <p >2</p>
  <p >3</p>
</div>
<script>
  <!--直接通过getElementsByTag来获取标签名字-->
    var classes_p = document.getElementsByTagName("p");
    console.log(classes_p.length);
    classes_p[0].onclick = function () {
        this.style.color ="red";
    }
    classes_p[1].onclick = function () {
        this.style.backgroundColor ="blue";
    }
    classes_p[2].onclick = function () {
        this.innerText = "换个内容试试";
    }

</script>
</body>
</html>

显示效果如下所示:

这里写图片描述

注意:可以兼容所有浏览器


静态获取和动态获取过程

什么是静态获取过程和动态获取过程???
静态获取过程也就是当我们获取到一个节点之后,它的id改变以后不会影响到这个节点,就好比我们找到这个人,无论它改了什么名字,或者换了什么衣服,其实对我们所认识的这个人都没有任何影响
如:

<p id = "static">静态获取过程</p>
var oStatic = document.getElementById("static");
oStatic.style.color = "red";
oStatic.style.id = "s_static";
ostatic.style.color = "blue";

当id修改了之后,其对象的认知是不会进行改变的,注意为什么是id,因为id它具有唯一性

动态获取过程也就是如果我们每一次去修改其className的时候,这个时候都需要重新去获取一下这个数组,因为数组默认是会改变的。每当我们用到一次类数组的时候都会动态的获取一次

如:
<p class='dynamic'>p1</p>
<p class='dynamic'>p2</p>
<p class='dynamic'>p3</p>

var aDynamic= document.getElementsByClassName('xiao1');     //获取到dynamic类数组

console.log( aDynamic.length );     //先弹出长度 3
aDynamic[0].style.color = 'red';    //在给数组的第0个(p1)字体设置颜色
aDynamic[0].className = 'dynamic_2';    //然后将类数组的第一个的类名改一下,这个时候就只剩下2个dynamic   
console.log(aDynamic.length );  //弹出长度,这时候肯定长度为2了
aDynamic[0].style.color = '#cc00ff';     // 这个时候再给数组的第0个添加颜色,添加的就不再是p1了,而是p2

演示代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <meta charset="UTF-8"><!--申明当前网页的编码集UTF-8-->
  <meta name="Generator" content="EditPlus®">   <!--编辑器的名称-->
  <meta name="Author" content="作者是谁">       
  <meta name="Keywords" content="关键词">
  <meta name="Description" content="描述和简介">
  <style type="text/css">                                        
        body,dl,dd,dt,p,h1,h2,h3,h4,h5,h6{ margin: 0;}
        ul,ol{margin: 0; list-style: none; padding: 0;}
        a{ text-decoration: none; }
        *{ margin: 0; padding: 0; }
        .clearfix:after{
          content: "";
          display: block;
          clear: both;
        }
        .fl_l{float: left}
        .fl_r{float: right}
        .main{width: 1200px;margin: 10px auto;box-shadow: 0 0 10px 0 deeppink}
    p{width: 150px;height: 150px;background: greenyellow;margin: 10px}
  </style>
</head>
<body>
  <div class="main">
    <div class="static_content">
      <header>static_content</header>
      <p id="static_p">static</p>
    </div>
    <div class="dynamic_content clearfix">
      <header>dynamic_content</header>
      <p class="dynamic_p fl_l">dynamic_1</p>
      <p class="dynamic_p fl_l">dynamic_2</p>
      <p class="dynamic_p fl_l">dynamic_3</p>
    </div>
  </div>
  <script>
    //静态的获取方法,只要获取了,就不会再改变
    var oStatic = document.getElementById("static_p");
    oStatic.style.background = "red";
    oStatic.id = "static_p_2";
    oStatic.style.color = "blue";   //id改变了,但是其依旧能够改变样式
    //动态的获取方法,只要每使用一次,就需要动态的获取一次
    var aDynamicP = document.getElementsByClassName("dynamic_p");
    console.log(aDynamicP.length);
    aDynamicP[0].onclick = function () {
        aDynamicP[1].className = "dynamic_p_2 fl_l";
        console.log(aDynamicP.length);
        aDynamicP[1].style.backgroundColor = "blue";
    }
  </script>
</body>
</html>

显示效果如下所示:

这里写图片描述
静态的过程就直接改变了。动态的过程在点击第一个p元素的时候,console输出的为2,而不是原来的3,它会动态改变。这儿时候aDynamic中的第二个元素也就是对应的为dynamic3了。所以dynamic3的背景样式发生了改变

注意:getElementById是静态获取的过程,getElementsByClassName与getElementsByTagName都是动态获取的过程,但是一般很少去使用getElementsByTagName来修改


通过选择器来获取元素

通过querySelector()和querySelectorAll()来进行选择器选取元素。,但是这种是兼容IE8及以上版本

querySelector是获取单个节点,如果选择器是类名或者标签名等,只会获取到一个,(如果您在后面加上下标就会报错,找不到这个元素)

var oBox = document.querySelector("#main.box");
oBox.style.color = "red";

querySelectorAll是获取节点下面所有同一类的标签元素。

var aBox = document.querySelectorAll(".content p");
console.log(aBox.length);
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <meta charset="UTF-8"><!--申明当前网页的编码集UTF-8-->
  <meta name="Generator" content="EditPlus®">   <!--编辑器的名称-->
  <meta name="Author" content="作者是谁">       
  <meta name="Keywords" content="关键词">
  <meta name="Description" content="描述和简介">
  <style type="text/css">                                        
        body,dl,dd,dt,p,h1,h2,h3,h4,h5,h6{ margin: 0;}
        ul,ol{margin: 0; list-style: none; padding: 0;}
        a{ text-decoration: none; }
        *{ margin: 0; padding: 0; }
        .clearfix:after{
          content: "";
          display: block;
          clear: both;
        }
        .fl_l{float: left}
        .fl_r{float: right}
        .main{width: 1200px;margin: 10px auto;box-shadow: 0 0 10px 0 deeppink}
        p{width: 150px;height: 150px;background: greenyellow;margin: 10px}
  </style>
</head>
<body>
  <div class="main">
    <div class="qS">
      <header>querySelector</header>
      <p id="qS_p">querySelector</p>
    </div>
    <div class="content clearfix">
      <header>querySelectorAll</header>
      <p class="qSA_p fl_l">querySelectorAll</p>
      <p class="qSA_p fl_l">querySelectorAll</p>
      <p class="qSA_p fl_l">querySelectorAll</p>
    </div>
  </div>
  <script>
    var oP = document.querySelector(".qS #qS_p");
    oP.style.color = "red";
    var aP = document.querySelectorAll(".content .qSA_p");
    console.log(aP.length);
    aP[0].style.color = "blue"
    aP[1].style.color = "red"
    aP[2].style.color = "gold"
  </script>
</body>
</html>

显示如下所示:

这里写图片描述

相对于以上所有的获取方式,这个时候querySelector与querySelectorAll显得更加的灵活一点。


js相关的命名规范

1.s: 表示字符串String
2.b: 表示布尔Boolean
3.a: 表示数组Array
4.o: 表示对象Object
5.fn: 表示函数Function
6.re: 表示正则Regular Expression

欢迎持续访问博客:http://blog.csdn.net/qq_29924041

作者:qq_29924041 发表于2017/11/18 19:09:33 原文链接
阅读:43 评论:0 查看评论

[bzoj 1076--SCOI2008]奖励关

$
0
0

你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关。在这个奖励关里,系统将依次随机抛出k次宝物, 每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再吃)。
宝物一共有n种,系统每次抛出这n种宝物的概率都相同且相互独立。也就是说,即使前k-1次系统都抛出宝物1(这种情况是有可能出现的,尽管概率非常小),第k次抛出各个宝物的概率依然均为1/n。 获取第i种宝物将得到Pi 分,但并不是每种宝物都是可以随意获取的。第i种宝物有一个前提宝物集合Si。只有当Si中所有宝物都至少吃过一次,才能吃第i种宝物(如果系统抛出了一个目前不能吃的宝物,相当于白白的损失了一次机会)。注意,Pi可以是负数,但如果它是很多高分宝物的前提,损失短期利益而吃掉这个负分宝物将获得更大的长期利益。 假设你采取最优策略,平均情况你一共能在奖励关得到多少分值?

一道恶心的状压与期望dp。作为期望dp,大家都应该知道需要逆推,这样可以方便继承状态,顺推当然可以码,如果你足够神的话。定义一个f数组,f[i][j]中i表示n个物体是否被用过的二进制状态,注意是是否。j表示使用了j次机会。f[i][j]表示为期望值。
那么dp方程就很好推了,枚举一下二进制状态x,次数y,判断一下宝物i是否满足前提(1<=i<=n)。
如果不满足,f[x][y]+=1.0/n*1.0*f[x][y+1];
如果满足,则分两种情况。
一种为以前没出现过,f[x][y]+=1.0/n*1.0*max(f[x][y+1],f[x+bin[i]][y+1]+s[i]*1.0);
一种为以前出现过,f[x][y]+=1.0/n*1.0*max(f[x][y+1],f[x][y+1]+s[i]*1.0);
代码丑,请见谅。(本来可用位运算简化代码,但本蒟蒻不会)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
double f[32770][110];
bool v[20][20],vv[20];
int s[20],bin[20],ss[20];
int main()
{
    memset(v,false,sizeof(v));
    memset(ss,0,sizeof(ss));
    bin[1]=1;for(int i=2;i<=15;i++)bin[i]=bin[i-1]*2;
    int k,n;
    scanf("%d%d",&k,&n);
    double wy=1.0/n*1.0;
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&s[i]);
        while(scanf("%d",&x)!=EOF)
        {
            if(x==0)break;
            v[i][x]=true;ss[i]++;
        }
    }
    int maxx=0;
    for(int i=1;i<=n;i++)maxx+=bin[i];
    for(int x=maxx;x>=0;x--)
    {
        for(int y=k-1;y>=0;y--)
        {
            memset(vv,false,sizeof(vv));
            for(int i=1;i<=n;i++)
            {
                int he=0;
                for(int j=1;j<=n;j++)
                {
                    if((x&bin[j])!=0 && v[i][j]==true)he++;
                }
                if(he==ss[i])vv[i]=true;
            }
            for(int i=1;i<=n;i++)
            {
                if(vv[i]==false)f[x][y]+=wy*f[x][y+1];
                else 
                {
                    if((x&bin[i])==0)f[x][y]+=wy*max(f[x][y+1],f[x+bin[i]][y+1]+s[i]*1.0);
                    else f[x][y]+=wy*max(f[x][y+1],f[x][y+1]+s[i]*1.0);
                }
            }
        }
    }
    printf("%.6lf\n",f[0][0]);
    return 0;
}
作者:lixuanjing2016 发表于2017/11/18 21:24:32 原文链接
阅读:37 评论:0 查看评论

Nginx 搭建图片服务器

$
0
0

Nginx 搭建图片服务器

本章内容通过Nginx 和 FTP 搭建图片服务器。在学习本章内容前,请确保您的Linux 系统已经安装了Nginx和Vsftpd。

Nginx 安装:http://blog.csdn.net/qq_19558705/article/details/78559814
Vsftpd 安装:http://blog.csdn.net/qq_19558705/article/details/78570482

本章知识点

效果图:
效果图演示

需求:实现图片的上传和批量上传
技术:Nginx,Vsftpd,Spring,SpringMVC,KindEditor,CentOS
说明:本章节内容主要是实现图片的上传功能。使用 KindEditer 是为了更好的演示图片的上传,回显,批量效果。后台代码与KindEditer没有直接关系,放心阅读。另外源码中有Mybatis的jar,不用理会,本章内容用不到,是为后续内容做准备!
源码:见文章底部
场景:用户将图片上传到 tomcat 服务器上,再由 tomcat 服务器通过FTP上传到 Nginx 服务器上。
用户将图片上传到 tomcat 服务器上,再由 tomcat 服务器通过FTP上传到 Nginx 服务器
项目结构:
项目结构

单元测试

首先要攻破核心技术。通过单元测试实现图片上传的功能。

package com.itdragon.test;

import java.io.File;
import java.io.FileInputStream;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.junit.Test;

public class PictureFTPTest {

    // 测试 ftp 上传图片功能
    @Test
    public void testFtpClient() throws Exception {
        // 1. 创建一个FtpClient对象
        FTPClient ftpClient = new FTPClient();
        // 2. 创建 ftp 连接
        ftpClient.connect("192.168.0.11", 21);
        // 3. 登录 ftp 服务器
        ftpClient.login("ftpuser", "root");
        // 4. 读取本地文件
        FileInputStream inputStream = new FileInputStream(new File("F:\\hello.png"));
        // 5. 设置上传的路径
        ftpClient.changeWorkingDirectory("/usr/local/nginx/html/images");
        // 6. 修改上传文件的格式为二进制
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        // 7. 服务器存储文件,第一个参数是存储在服务器的文件名,第二个参数是文件流
        ftpClient.storeFile("hello.jpg", inputStream);
        // 8. 关闭连接
        ftpClient.logout();

    }

}

说明:这里的ip地址,端口,ftp用户名,密码,本地文件路径,以及Nginx服务器图片路径等,这些字符串参数都要根据自己实际设置的来填写的。如果你的Nginx和Vsftpd安装是按照我提供的链接来做的。那你只需要改ip地址即可。

Maven 的Web 项目

搭建Maven的Web 项目,之前有写过。这里就不过多描述。

项目核心配置文件

首先是 Maven 的核心文件 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itdragon.upload</groupId>
    <artifactId>pictrue-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <!-- 集中定义依赖版本号 -->
    <properties>
        <junit.version>4.12</junit.version>
        <spring.version>4.1.3.RELEASE</spring.version>
        <mybatis.version>3.2.8</mybatis.version>
        <mybatis.spring.version>1.2.2</mybatis.spring.version>
        <mybatis.paginator.version>1.2.15</mybatis.paginator.version>
        <mysql.version>5.1.6</mysql.version>
        <slf4j.version>1.6.4</slf4j.version>
        <jackson.version>2.4.2</jackson.version>
        <druid.version>1.0.9</druid.version>
        <httpclient.version>4.3.5</httpclient.version>
        <jstl.version>1.2</jstl.version>
        <servlet-api.version>2.5</servlet-api.version>
        <jsp-api.version>2.0</jsp-api.version>
        <joda-time.version>2.5</joda-time.version>
        <commons-lang3.version>3.3.2</commons-lang3.version>
        <commons-io.version>1.3.2</commons-io.version>
        <commons-net.version>3.3</commons-net.version>
        <pagehelper.version>3.4.2</pagehelper.version>
        <jsqlparser.version>0.9.1</jsqlparser.version>
        <commons-fileupload.version>1.3.1</commons-fileupload.version>
        <jedis.version>2.7.2</jedis.version>
        <solrj.version>4.10.3</solrj.version>
    </properties>
    <dependencies>
        <!-- 时间操作组件 -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>${joda-time.version}</version>
        </dependency>
        <!-- Apache工具组件 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>${commons-net.version}</version>
        </dependency>
        <!-- Jackson Json处理工具包 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!-- httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>${httpclient.version}</version>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- 日志处理 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis.spring.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.miemiedev</groupId>
            <artifactId>mybatis-paginator</artifactId>
            <version>${mybatis.paginator.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>${pagehelper.version}</version>
        </dependency>
        <!-- MySql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- 连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- JSP相关 -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>${jstl.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>${servlet-api.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>${jsp-api.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- 文件上传组件 -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>${commons-fileupload.version}</version>
        </dependency>
        <!-- Redis客户端 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>${jedis.version}</version>
        </dependency>
        <!-- solr客户端 -->
        <dependency>
            <groupId>org.apache.solr</groupId>
            <artifactId>solr-solrj</artifactId>
            <version>${solrj.version}</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <!-- 资源文件拷贝插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!-- java编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <!-- 配置Tomcat插件 -->
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

说明:和文件上传有直接关系的是:

<dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
        </dependency>

然后是 Web 项目的核心文件 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="taotao" version="2.5">
    <display-name>pictrue-service</display-name>
    <!-- 加载spring容器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/applicationContext-*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 解决post乱码 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- springmvc的前端控制器 -->
    <servlet>
        <servlet-name>pictrue-service</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>pictrue-service</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

再是 SpringMVC 配置文件 springmvc.xml,需要添加文件上传解析器

<!-- 定义文件上传解析器 -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设定默认编码 -->
        <property name="defaultEncoding" value="UTF-8"></property>
        <!-- 设定文件上传的最大值5MB,5*1024*1024 -->
        <property name="maxUploadSize" value="5242880"></property>
    </bean>

最后是 Ftp 配置文件 resource.properties

FTP_ADDRESS=192.168.0.11
FTP_PORT=21
FTP_USERNAME=ftpuser
FTP_PASSWORD=root
FTP_BASE_PATH=/usr/local/nginx/html/images
IMAGE_BASE_URL=http://192.168.0.11/images

Service 层

上传图片的接口 PictureService.java

package com.itdragon.service;
import java.util.Map;
import org.springframework.web.multipart.MultipartFile;
public interface PictureService {

    /**
     * 上传,批量上传接口
     * @param uploadFile
     * @return
     */
    Map uploadPicture(MultipartFile uploadFile);
}

上传图片接口实现类 PictureServiceImpl.java

package com.itdragon.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.itdragon.service.PictureService;

@Service
@SuppressWarnings({"rawtypes", "unchecked"})
public class PictureServiceImpl implements PictureService {

    // 通过 Spring4 的 Value注解,获取配置文件中的属性值
    @Value("${FTP_ADDRESS}")
    private String FTP_ADDRESS;     // ftp 服务器ip地址
    @Value("${FTP_PORT}")
    private Integer FTP_PORT;       // ftp 服务器port,默认是21
    @Value("${FTP_USERNAME}")
    private String FTP_USERNAME;    // ftp 服务器用户名
    @Value("${FTP_PASSWORD}")
    private String FTP_PASSWORD;    // ftp 服务器密码
    @Value("${FTP_BASE_PATH}")
    private String FTP_BASE_PATH;   // ftp 服务器存储图片的绝对路径
    @Value("${IMAGE_BASE_URL}")
    private String IMAGE_BASE_URL;  // ftp 服务器外网访问图片路径

    @Override
    public Map uploadPicture(MultipartFile uploadFile) {
        Map resultMap = new HashMap<>();
        try {
            // 1. 取原始文件名
            String oldName = uploadFile.getOriginalFilename();

            // 2. ftp 服务器的文件名
            String newName = oldName;
            //图片上传
            boolean result = uploadFile(FTP_ADDRESS, FTP_PORT, FTP_USERNAME, FTP_PASSWORD, 
                    uploadFile.getInputStream(), FTP_BASE_PATH, newName);
            //返回结果
            if(!result) {
                resultMap.put("error", 1);
                resultMap.put("message", "upload Fail");
                return resultMap;
            }
            resultMap.put("error", 0);
            resultMap.put("url", IMAGE_BASE_URL + "/" + newName);
            return resultMap;

        } catch (Exception e) {
            e.printStackTrace();
            resultMap.put("error", 1);
            resultMap.put("message", "upload Fail");
            return resultMap;
        }
    }

    /**
     * ftp 上传图片方法
     * @param ip            ftp 服务器ip地址
     * @param port          ftp 服务器port,默认是21
     * @param account       ftp 服务器用户名
     * @param passwd        ftp 服务器密码
     * @param inputStream   文件流
     * @param workingDir    ftp 服务器存储图片的绝对路径
     * @param fileName      上传到ftp 服务器文件名
     * @throws Exception
     * 
     */
    public boolean uploadFile(String ip, Integer port, String account, String passwd,
            InputStream inputStream, String workingDir, String fileName) throws Exception{
        boolean result = false;
        // 1. 创建一个FtpClient对象
        FTPClient ftpClient = new FTPClient();
        try {
            // 2. 创建 ftp 连接
            ftpClient.connect(ip, port);
            // 3. 登录 ftp 服务器
            ftpClient.login(account, passwd);
            int reply = ftpClient.getReplyCode(); // 获取连接ftp 状态返回值
            System.out.println("code : " + reply);
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect(); // 如果返回状态不再 200 ~ 300 则认为连接失败
                return result;
            }
            // 4. 读取本地文件
//          FileInputStream inputStream = new FileInputStream(new File("F:\\hello.png"));
            // 5. 设置上传的路径
            ftpClient.changeWorkingDirectory(workingDir);
            // 6. 修改上传文件的格式为二进制
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            // 7. 服务器存储文件,第一个参数是存储在服务器的文件名,第二个参数是文件流
            if (!ftpClient.storeFile(fileName, inputStream)) {
                return result;
            }
            // 8. 关闭连接
            inputStream.close();
            ftpClient.logout();
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // FIXME 听说,项目里面最好少用try catch 捕获异常,这样会导致Spring的事务回滚出问题???难道之前写的代码都是假代码!!!
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }

}

说明:
① @Value 注解是Spring4 中提供的,@Value(“${XXX}”)
② 返回值是一个Map,并且key有error,url,message。这是根据KindEditer的语法要求来的。详情见链接。http://kindeditor.net/docs/upload.html

Controller 层

负责页面跳转的 PageController.java

package com.itdragon.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class PageController {

    /**
     * 打开首页
     */
    @RequestMapping("/")
    public String showIndex() {
        return "index";
    }

    @RequestMapping("/{page}")
    public String showpage(@PathVariable String page) {
        System.out.println("page : " + page);
        return page;
    }
}

负责图片上传的 PictureController.java

package com.itdragon.controller;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itdragon.service.PictureService;

@RestController
public class PictureController {

    @Autowired
    private PictureService pictureService;

    @RequestMapping("pic/upload")
    public String pictureUpload(@RequestParam(value = "fileUpload") MultipartFile uploadFile) {
        String json = "";
        try {
            Map result = pictureService.uploadPicture(uploadFile);
            // 浏览器擅长处理json格式的字符串,为了减少因为浏览器内核不同导致的bug,建议用json
            json = new ObjectMapper().writeValueAsString(result);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return json;
    }
}

说明:
① @RestController 也是Spring4 提供的,是 @Controller + @ResponseBody 的组合注解。
② Controller层的返回值是一个json格式的字符串。是考虑到浏览器对json解析兼容性比较好。

Views视图层

负责上传图片的jsp页面 pic-upload.jsp

<%@ page language="java" contentType="text/html; UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ITDragon 图片上传</title>
</head>
    <link href="/js/kindeditor-4.1.10/themes/default/default.css" type="text/css" rel="stylesheet">
    <script type="text/javascript" src="js/jquery.min.js"></script> 
    <script type="text/javascript" charset="utf-8" src="/js/kindeditor-4.1.10/kindeditor-all-min.js"></script>
    <script type="text/javascript" charset="utf-8" src="/js/kindeditor-4.1.10/lang/zh_CN.js"></script>
</head>  
<body>  
    <h3>测试上传图片功能接口的form表单</h3>
    <form action="pic/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="fileUpload" />
        <input type="submit" value="上传文件" />
    </form>
    <hr />
    <h3>借用KindEditor富文本编辑器实现批量上传图片</h3>
    <textarea id="kindEditorDesc" style="width:800px;height:300px;visibility:hidden;"></textarea>
    <script type="text/javascript">
        $(function(){
            //初始化富文本编辑器
            KindEditor.create("#kindEditorDesc", {
                // name值,必须和Controller 的参数对应,不然会提示 400 的错误
                filePostName : "fileUpload",
                // action值,
                uploadJson : '/pic/upload',
                // 设置上传类型,分别为image、flash、media、file
                dir : "image"
            });
        });
    </script>   
</body>
</html>

说明:pic-upload.jsp 分为两个部分,第一个部分是为了测试上传图片功能的form表单。第二个部分是为了更好的体验上传,批量上传,回显功能的KindEditer 富文本编辑器。

总结

  • Nginx 搭建服务器的思维
  • Java实现 Ftp上传图片的功能
  • KindEditer 上传图片的功能

源码:https://github.com/ITDragonBlog/daydayup/tree/master/Nginx

Nginx 搭建图片服务器到这里就结束了,有什么不足的地方,请赐教。如果觉得不错,可以点个赞哦!

作者:qq_19558705 发表于2017/11/18 21:28:52 原文链接
阅读:32 评论:0 查看评论

接受·改变——写给想上985的211学生

$
0
0

【来信】
  我是武汉某211高校一名大三生,专业是电子信息科学与技术,偶然的机会在CSDN上看到了您创建的这个非常优秀的解疑专栏,而最近对自己的现状很失望,对于自己的前路又很迷茫,希望能得到您的一点建议和指导,感激不尽!
  我想去985读研,但是和老师、同学交流后,深刻地意识到我实现这个目标的希望有多渺茫,这让我对前路感到迷茫和恐慌,另外我追溯原因,仔细回顾自己的大学生活后,为自己的目光短浅、无所作为感到很惭愧甚至厌恶,这让我对自己的现状很失望。
  对前路迷茫和恐慌发生是在对读研方面了解更多之后。读研可以保研或者考研,对于我们学校,保研有A类和B类,A类靠成绩,我所在的专业每年有大概4个名额;B类靠创新或竞赛。说起来很惭愧,虽然说自己想读研,但却没有及时充分了解读研方面的信息,妄想着自己学好当前的课程到时再说,结果现在成绩不够好,也没有项目竞赛经历。至于考研,我们老师跟我们介绍说,现在很多优秀的大学招收研究生时,很大的比例都是保研的,考研的很少,而且学校会有保护本校生政策(为本校考研生降低标准),还说在考研方面,我们比较普通的211学生很多时候没有二本院校表现好,而我对自己的学习能力又一直不自信,目前的一点点成绩很多时候我都是拼时间得来的,做事很没效率,另外其实我很不想为备考而经历高考模式的长期疯狂刷题。
  概括起来是,保研是不可能的,感觉考研难度很大,高考模式的备考会很痛苦,所以我很怀疑自己最后能不能到一所985院校读研。我还想补充两点:一是我指的学习能力主要指自学能力,高中时的教育有中“填鸭”的感觉,这种模式下我表现还可以,但是进入大学后深刻认识到我自学能力有多差,这让我感觉考研对我很难;二是不愿考研很大程度上是很抵触高考复习那种模式,因为那种模式下我有很不好的体验,高三时压力很大,近一年我都处于失眠的状态,以至于高考后我有一种很强烈的想法:不管考什么样子,我都不要复习了,这不是调侃或者玩笑,而是出于避免糟糕体验而产生的强烈想法。
  诶,全文都散发着消极的看法吧,也许我看事情过于悲观了些,按我的思路对我来说好像读研变得不可能了,但是我真的比较担心,因为我真的不够相信自己。如果我消极的看法打扰到贺老师,真心说句抱歉。
  如果贺老师能针对我的情况给我一些建议或者纠正我的一些错误想法,我会非常感谢您的!
  
【回复】
  昨天上午看到这封信,没有及时回。当时在火车上,不方便回,也真不知道怎么说这件事,
  不堪回首的高考模式已经成为过去,如果受到过伤害,忘掉它吧。学习本不该是这个样子。但话又说回来,不要将其看都是一无是处,你现在能在211,有赖于此。进入大学,学习是要继续,改变学法,改变体验,这显然成了于你而言很重要的一件事。而你现在一提到备考沿心有余悸,可以是两种情况:你的学习方式依然是被动的,或者,你的学习方式已经改变而不知。复习,作为任何阶段的学习,包括我现在完全工作状态中的学习都是必要的。只是,要面临考试时,复习的强度会大,目标性更强。复习是正常学习中的一个环节,接受它。
  你不可能得到保研的机会几成定局的前提下,审视一下自己上985研究生的阶段性目标。你上研要得到的是什么?就上211是否能得到?毕业证书上写的学校的名头会帮助到个人,但作为个人发展,最重要的还是你自己。我自己的本科在985(当时叫全国重点),硕士在一般院校,博士在211,20余年扎根在一般院校工作,见过无数的同事和学生的历程,这一点很清楚。所以首先劝你,别太把学校的标签太放在心上。现在开始,更加关注自己,关注自己的学习能力,关注自己对学习的认识,985、211,对你的前途不是决定性的。作为一名没有985、211名头的学校的老师,在看信的过程中,心情实是有些小复杂,我每天都能看到,我的学生里,不乏有为获得你现在能轻易得到的机会而奋力去争取的。我相信,机会留给努力的人,留给勇于改变的人,留给能够面对当下,脚踏实地的人。
  若是985情结未消,自己上大学以来的改变也不大,那再拼一把是你需要接受的。再次的高投入复习,和当年的感觉可以不一样,现在需要你自主把握的成份很大,也就在这个过程中,锻炼自己的自主能力。你在进入大学两年多的时间内,显然应该要提高这方面的能力,然而你的描述让我看到,你似乎在这方面做得并不好。你备考的过程,学习强度会大不少,但也恰是你改变的过程。无论结果如何,这个过程本身就很珍贵。
  学习本来就是一件苦差事。这里,有的是辛苦,但可以不是受苦、受罪,在终身学习的时代,要在努力学习中感受到这一点。有一个需要很努力才能达到的目标,拿出面对的勇气,付出该有的辛苦,卸下不必有的负担,往前走吧。
  最后分享一位我的学生的故事“努力了就没有失败“。你的来信,让我想起了他。
  祝你能够改变!

作者:sxhelijian 发表于2017/11/18 21:34:13 原文链接
阅读:36 评论:0 查看评论

Spring cloud系列九 Hystrix的配置属性优先级和详解

$
0
0

1. 概述

本文对Hystrix的配置参数的覆盖优先级,可配置参数的种类、配置项进行详细的介绍。

Hystrix可以配置属性的有以下类型:

  • Execution:控制HystrixCommand.run() 的如何执行
  • Fallback: 控制HystrixCommand.getFallback() 如何执行
  • Circuit Breaker: 控制断路器的行为
  • Metrics: 捕获和HystrixCommand 和 HystrixObservableCommand 执行信息相关的配置属性
  • Request Context:设置请求上下文的属性
  • Collapser Properties:设置请求合并的属性
  • Thread Pool Properties:设置线程池的属性

2. Hystrix参数的覆盖优先级

每个Hystrix参数都有4个地方可以配置,优先级从低到高如下,如果每个地方都配置相同的属性,则优先级高的值会覆盖优先级低的值

  • 1 内置全局默认值:写死在代码里的值
  • 2 动态全局默认属性:通过属性文件配置全局的值
  • 3 内置实例默认值:写死在代码里的实例的值
  • 4 动态配置实例属性:通过属性文件配置特定实例的值

3 Hystrix配置属性详解

Hystrix可以配置属性的有以下类型:

  • Execution:控制HystrixCommand.run() 的如何执行
  • Fallback: 控制HystrixCommand.getFallback() 如何执行
  • Circuit Breaker: 控制断路器的行为
  • Metrics: 捕获和HystrixCommand 和 HystrixObservableCommand 执行信息相关的配置属性
  • Request Context:设置请求上下文的属性
  • Collapser Properties:设置请求合并的属性
  • Thread Pool Properties:设置线程池的属性

3.1. Execution

以下属性控制HystrixCommand.run() 的如何执行

1. execution.isolation.strategy
表示HystrixCommand.run()的执行时的隔离策略,有以下两种策略

  • 1 THREAD: 在单独的线程上执行,并发请求受线程池中的线程数限制
  • 2 SEMAPHORE: 在调用线程上执行,并发请求量受信号量计数限制

在默认情况下,推荐HystrixCommands 使用 thread 隔离策略,HystrixObservableCommand 使用 semaphore 隔离策略。
只有在高并发(单个实例每秒达到几百个调用)的调用时,才需要修改HystrixCommands 的隔离策略为semaphore 。semaphore 隔离策略通常只用于非网络调用

默认值:THREAD,

// 设置所有实例的默认值
hystrix.command.default.execution.isolation.strategy=..
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.execution.isolation.strategy=...

2. execution.isolation.thread.timeoutInMilliseconds
设置调用者执行的超时时间(单位毫秒)

默认值:1000

// 设置所有实例的默认值
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds=...

3. execution.timeout.enabled
表示是否开启超时设置。

默认值:true

// 设置所有实例的默认值
hystrix.command.default.execution.timeout.enabled=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.execution.timeout.enabled=...

4. execution.isolation.thread.interruptOnTimeout
表示设置是否在执行超时时,中断HystrixCommand.run() 的执行

默认值:true

// 设置所有实例的默认值
hystrix.command.default.execution.isolation.thread.interruptOnTimeout=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.execution.isolation.thread.interruptOnTimeout=...

5. execution.isolation.thread.interruptOnCancel
表示设置是否在取消任务执行时,中断HystrixCommand.run() 的执行

默认值:false

// 设置所有实例的默认值
hystrix.command.default.execution.isolation.thread.interruptOnCancel=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.execution.isolation.thread.interruptOnCancel

6. execution.isolation.semaphore.maxConcurrentRequests

当HystrixCommand.run()使用SEMAPHORE的隔离策略时,设置最大的并发量

默认值:10

// 设置所有实例的默认值
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=...

// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.execution.isolation.semaphore.maxConcurrentRequests=...

3.2. Fallback

以下属性控制HystrixCommand.getFallback() 如何执行。这些属性对隔离策略THREAD 和SEMAPHORE都起作用.
1. fallback.isolation.semaphore.maxConcurrentRequests
此属性设置从调用线程允许HystrixCommand.getFallback()方法允许的最大并发请求数
如果达到最大的并发量,则接下来的请求会被拒绝并且抛出异常.

默认值:10

// 设置所有实例的默认值
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.fallback.isolation.semaphore.maxConcurrentRequests=...

2. fallback.enabled
是否开启fallback功能

默认值:true

// 设置所有实例的默认值
hystrix.command.default.fallback.enabled=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.fallback.enabled=...

3.3. Circuit Breaker

控制断路器的行为

1. circuitBreaker.enabled
是否开启断路器功能

默认值:true

// 设置所有实例的默认值
hystrix.command.default.circuitBreaker.enabled=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.circuitBreaker.enabled=...

2. circuitBreaker.requestVolumeThreshold

该属性设置滚动窗口中将使断路器跳闸的最小请求数量

如果此属性值为20,则在窗口时间内(如10s内),如果只收到19个请求且都失败了,则断路器也不会开启。

默认值:20

// 设置所有实例的默认值
hystrix.command.default.circuitBreaker.requestVolumeThreshold=...

// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.circuitBreaker.requestVolumeThreshold=...

3. circuitBreaker.sleepWindowInMilliseconds
断路器跳闸后,在此值的时间的内,hystrix会拒绝新的请求,只有过了这个时间断路器才会打开闸门

默认值:5000

// 设置所有实例的默认值
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.circuitBreaker.sleepWindowInMilliseconds=...

4. circuitBreaker.errorThresholdPercentage

设置失败百分比的阈值。如果失败比率超过这个值,则断路器跳闸并且进入fallback逻辑

默认值:50

// 设置所有实例的默认值
hystrix.command.default.circuitBreaker=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.circuitBreaker.errorThresholdPercentage=...

5. circuitBreaker.forceOpen
如果设置true,则强制使断路器跳闸,则会拒绝所有的请求.此值会覆盖circuitBreaker.forceClosed的值

默认值:false

// 设置所有实例的默认值
hystrix.command.default.circuitBreaker.forceOpen=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.circuitBreaker.forceOpen=...

6. circuitBreaker.forceClosed
如果设置true,则强制使断路器进行关闭状态,此时会允许执行所有请求,无论是否失败的次数达到circuitBreaker.errorThresholdPercentage值

默认值:false

// 设置所有实例的默认值
hystrix.command.default.circuitBreaker.forceClosed=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.circuitBreaker.forceClosed=...

3.4. Metrics

捕获和HystrixCommand 和 HystrixObservableCommand 执行信息相关的配置属性

1. metrics.rollingStats.timeInMilliseconds
设置统计滚动窗口的时间长度

如果此值为10s,将窗口分成10个桶,每个桶表示1s时间,则统计信息如下图:
这里写图片描述

默认值: 10000

// 设置所有实例的默认值
hystrix.command.default.metrics.rollingStats.timeInMilliseconds=....

// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.metrics.rollingStats.timeInMilliseconds=...

2. metrics.rollingStats.numBuckets
设置统计滚动窗口的桶数量,

注意:以下配置必须成立,否则会抛出异常。

metrics.rollingStats.timeInMilliseconds % metrics.rollingStats.numBuckets == 0

如:10000/10、10000/20是正确的配置,但是10000/7错误的

在高并发的环境里,每个桶的时间长度建议大于100ms

默认值:10

// 设置所有实例的默认值
hystrix.command.default.metrics.rollingStats.numBuckets=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.metrics.rollingStats.numBuckets=...

3. metrics.rollingPercentile.enabled

设置执行延迟是否被跟踪,并且被计算在失败百分比中。如果设置为false,则所有的统计数据返回-1

默认值: true

// 设置所有实例的默认值
hystrix.command.default.metrics.rollingPercentile.enabled=...

// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.metrics.rollingPercentile.enabled=...

4. metrics.rollingPercentile.timeInMilliseconds

此属性设置统计滚动百分比窗口的持续时间

默认值:60000

// 设置所有实例的默认值
hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.metrics.rollingPercentile.timeInMilliseconds=...

5. metrics.rollingPercentile.numBuckets
设置统计滚动百分比窗口的桶数量

注意:以下配置必须成立,否则会抛出异常。

metrics.rollingPercentile.timeInMilliseconds % metrics.rollingPercentile.numBuckets == 0

如: 60000/6、60000/60是正确的配置,但是10000/7错误的

在高并发的环境里,每个桶的时间长度建议大于1000ms

默认值:6

// 设置所有实例的默认值
hystrix.command.default.metrics.rollingPercentile.numBuckets=...

// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.metrics.rollingPercentile.numBuckets=...

6. metrics.rollingPercentile.bucketSize
此属性设置每个桶保存的执行时间的最大值。如果桶数量是100,统计窗口为10s,如果这10s里有500次执行,只有最后100次执行会被统计到bucket里去

默认值:100

// 设置所有实例的默认值
hystrix.command.default.metrics.rollingPercentile.bucketSize=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.metrics.rollingPercentile.bucketSize=...

7. metrics.healthSnapshot.intervalInMilliseconds

采样时间间隔

默认值:500

// 设置所有实例的默认值
hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.metrics.healthSnapshot.intervalInMilliseconds=...

3.5. Request Context

此属性控制HystrixCommand使用到的Hystrix的上下文

1. requestCache.enabled
是否开启请求缓存功能

默认值:true

// 设置所有实例的默认值
hystrix.command.default.requestCache.enabled=...

// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.requestCache.enabled=...

2. requestLog.enabled
表示是否开启日志,打印执行HystrixCommand的情况和事件

默认值:true

// 设置所有实例的默认值
hystrix.command.default.requestLog.enabled=...
// 设置实例HystrixCommandKey的此属性值
hystrix.command.HystrixCommandKey.requestLog.enabled=...

3.6. Collapser Properties

设置请求合并的属性

1. maxRequestsInBatch
设置同时批量执行的请求的最大数量

默认值:Integer.MAX_VALUE

// 设置所有实例的默认值
hystrix.collapser.default.maxRequestsInBatch=...
// 设置实例HystrixCommandKey的此属性值
hystrix.collapser.HystrixCollapserKey.maxRequestsInBatch=...

2. timerDelayInMilliseconds
批量执行创建多久之后,再触发真正的请求

默认值:10

// 设置所有实例的默认值
hystrix.collapser.default.timerDelayInMilliseconds=...
// 设置实例HystrixCommandKey的此属性值
hystrix.collapser.HystrixCollapserKey.timerDelayInMilliseconds=...

3. requestCache.enabled
是否对HystrixCollapser.execute() 和 HystrixCollapser.queue()开启请求缓存

默认值:true

// 设置所有实例的默认值
hystrix.collapser.default.requestCache.enabled=...
// 设置实例HystrixCommandKey的此属性值
hystrix.collapser.HystrixCollapserKey.requestCache.enabled=...

3.7. Thread Pool Properties

设置Hystrix Commands的线程池行为,大部分情况线程数量是10。

线程池数量的计算公式如下:

最高峰时每秒的请求数量 × 99%命令执行时间 + 喘息空间

设置线程池数量的主要原则是保持线程池越小越好,因为它是减轻负载并防止资源在延迟发生时被阻塞的主要工具

1. coreSize
设置线程池的core的大小

默认值:10

// 设置所有实例的默认值
hystrix.threadpool.default.coreSize=...
// 设置实例HystrixCommandKey的此属性值
hystrix.threadpool.HystrixThreadPoolKey.coreSize=...

2. maximumSize
设置最大的线程池的大小,只有设置allowMaximumSizeToDivergeFromCoreSize时,此值才起作用

默认值:10

// 设置所有实例的默认值
hystrix.threadpool.default.maximumSize=...
// 设置实例HystrixCommandKey的此属性值
hystrix.threadpool.HystrixThreadPoolKey.maximumSize=...

3. maxQueueSize
设置最大的BlockingQueue队列的值。如果设置-1,则使用SynchronousQueue队列,如果设置正数,则使用LinkedBlockingQueue队列

默认值:-1

// 设置所有实例的默认值
hystrix.threadpool.default.maxQueueSize=...
// 设置实例HystrixCommandKey的此属性值
hystrix.threadpool.HystrixThreadPoolKey.maxQueueSize=...

4. queueSizeRejectionThreshold
因为maxQueueSize值不能被动态修改,所有通过设置此值可以实现动态修改等待队列长度。即等待的队列的数量大于queueSizeRejectionThreshold时(但是没有达到maxQueueSize值),则开始拒绝后续的请求进入队列。

如果设置-1,则属性不启作用

默认值:5

// 设置所有实例的默认值
hystrix.threadpool.default.queueSizeRejectionThreshold=...
// 设置实例HystrixCommandKey的此属性值
hystrix.threadpool.HystrixThreadPoolKey.queueSizeRejectionThreshold=...

5. keepAliveTimeMinutes
设置线程多久没有服务后,需要释放(maximumSize-coreSize )个线程

默认值:1

// 设置所有实例的默认值
hystrix.threadpool.default.keepAliveTimeMinutes=...
// 设置实例HystrixCommandKey的此属性值
hystrix.threadpool.HystrixThreadPoolKey.keepAliveTimeMinutes=...

6. allowMaximumSizeToDivergeFromCoreSize
设置allowMaximumSizeToDivergeFromCoreSize值为true时,maximumSize才有作用
默认值:false

// 设置所有实例的默认值
hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize=....
// 设置实例HystrixCommandKey的此属性值
hystrix.threadpool.HystrixThreadPoolKey.allowMaximumSizeToDivergeFromCoreSize=...

7. metrics.rollingStats.timeInMilliseconds
设置滚动窗口的时间

默认值:10000

// 设置所有实例的默认值
hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds=true
// 设置实例HystrixCommandKey的此属性值
hystrix.threadpool.HystrixThreadPoolKey.metrics.rollingStats.timeInMilliseconds=true

8. metrics.rollingStats.numBuckets
设置滚动静态窗口分成的桶的数量

配置的值必须满足如下条件:

metrics.rollingStats.timeInMilliseconds % metrics.rollingStats.numBuckets == 0

默认值:10
建议每个桶的时间长度大于100ms

// 设置所有实例的默认值
hystrix.threadpool.default.metrics.rollingStats.numBuckets=...
// 设置实例HystrixCommandKey的此属性值
hystrix.threadpool.HystrixThreadPoolProperties.metrics.rollingStats.numBuckets=...
作者:hry2015 发表于2017/11/18 21:59:37 原文链接
阅读:32 评论:0 查看评论

Unity Shader 学习笔记(13) 混合光源、光的衰减

$
0
0

Unity Shader 学习笔记(13) 混合光源、光的衰减

参考书籍:《Unity Shader 入门精要》
3D数学 学习笔记(8) 光照


混合光源的前向渲染

一个BasePass处理平行光、四个点光源调用四次Additional Pass,四个点光源的顺序是依靠重要度排序的(光源强度、颜色、距离远近)。注意:只处理了逐像素光照,即光源渲染模式如果为Not Imoportant,则不会对物体产生影响。

使用Phong光照模型。定义了Base Pass 和 Additional Pass来处理多个光源。

Base Pass 代码如下。Unity会把最亮的平行光给BasePass处理,其他平行光交给AdditionalPass处理。

Pass {
    Tags { "LightMode"="ForwardBase" }

    CGPROGRAM

    #pragma multi_compile_fwdbase       // 保证使用光照衰减等光照变量可以正确被赋值

    ...

    fixed4 frag(v2f i) : SV_Target {
        ...

        // 环境光,只在BasePass处理一次够了。
        fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;  

        // 漫反射,_LightColor0是平行光颜色和强度相乘后的结果。
        fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));

        ...
        // 镜面高光。
        fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);

        // 衰减值,平行光为1.0。
        fixed atten = 1.0;

        return fixed4(ambient + (diffuse + specular) * atten, 1.0);
    }
    ...
}

Additional Pass代码如下。处理其他光源。

Pass {
    Tags { "LightMode"="ForwardAdd" }

    // 开启光照混合,与在帧缓存中的光照叠加
    Blend One One                   

    CGPROGRAM

    // 获取正确光照变量
    #pragma multi_compile_fwdadd    

    ...

    fixed4 frag(v2f i) : SV_Target {
        fixed3 worldNormal = normalize(i.worldNormal);
        #ifdef USING_DIRECTIONAL_LIGHT
            // 如果是平行光,直接获取光源方向
            fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
        #else
            // 点光或聚光,光源方向要依赖视角方向
            fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);    
        #endif

        ...
        // 漫反射和高光反射

        // 计算衰减值。平行光为1。其他光照较复杂。
        #ifdef USING_DIRECTIONAL_LIGHT
            fixed atten = 1.0;
        #else
            #if defined (POINT)
                float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
                fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
            #elif defined (SPOT)
                float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));
                fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
            #else
                fixed atten = 1.0;
            #endif
        #endif

        return fixed4((diffuse + specular) * atten, 1.0);
    }

    ENDCG
}

光照衰减

UNITY_ATTEN_CHANNEL:可以得到衰减纹理中衰减值所在分量。

光照衰减纹理

  需要预处理得到采样纹理,纹理的大小会影响衰减精度。类似渐变纹理,(0, 0)表示与光源重合时的衰减值,(1, 1)为离光源空间最大距离的衰减值。
  Unity内部使用_LightTexture0的纹理来计算光源衰减。利用_LightMatrix0变换矩阵来计算点在光源空间的位置。

// 计算衰减纹理坐标值
float3 lightCoord = mul(_LightMatrix0, float4(i.worldPosition, 1)).xyz;

// 根据坐标对纹理采样,用dot点乘就是直接做距离的平方,`.rr`的意思就是取得到rgb值的r作为一个新的二维坐标即(r, r)。
fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;

数学公式计算衰减

使用的是线性衰减:

flaot distance = length(_WorldSpaceLightPos0.xyz) - i.worldPosition.xyz);
atten = 1.0 / distance;

作者:l773575310 发表于2017/11/18 23:15:27 原文链接
阅读:44 评论:0 查看评论

剑指offer 链表

$
0
0

链表是一种较为简单的数据结构,但是其相关的问题也是相对较为复杂的。

链表的结构很简单,它是由指针把若干个结点连接成的链状结构。由于其是一种动态的数据结构,所以一般是对指针进行操作。

在遇到链表的问题时,有几点需要注意的地方:

  • 我们需要对链表结构有正确的认识
  • 我们需要对传入的指针做正确的输入判断
  • 我们需要对头指针的特殊性进行判断(删除结点、插入结点)
  • 临时结点的应用可以使得传入参数无需改变,const函数由此产生
  • 删除结点情况下,需要对其指针进行置NULL操作
#include <iostream>  
#include <string>  
#include <vector>  
using namespace std;  

typedef int datatype;

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

//根据value查找结点
//当给一个链表加入第一个结点时,我们用一个指针指向该结点,但是由于可能会新插入结点到头部,我们就用一个指针来指向头指针,以改动头指针
bool Find_Node(Node **first,datatype value_tobefound)
{
	if ((first == NULL) || ((*first) == NULL))
	{
		return false;
	}

	Node *Node_temp = *first;
	while (Node_temp != NULL)
	{
		if (Node_temp->value == value_tobefound)
		{
			return true;
		}
		else
		{
			Node_temp = Node_temp->Next_Node;
		}
	}
	return false;
}

//根据value删除结点
void Delete_Node(Node **first,datatype value_tobedeleted)
{
	if ((first == NULL) || (*first == NULL))
	{
		return;
	}

	//**先将待删除结点的指针设置为空
	Node *Tobedeleted = nullptr;

	//**如果第一个结点就是待删除结点,需要将第二个结点设置为首节点
	if ((*first)->value == value_tobedeleted)
	{
		Tobedeleted = *first;
		*first = (*first)->Next_Node;
	}
	else
	{
		//**设置一个临时Node存放结点(方便表示下一个节点)
		Node * Node_temp = *first;
		while (Node_temp != NULL)
		{
			if (Node_temp->Next_Node->value == value_tobedeleted)
			{
				//由于需要删除改结点,所以需要将待删除结点的下一个结点设置为当前结点的下一个结点
				//使用临时结点,可以保证传入的first指针指向不变
				Tobedeleted = Node_temp->Next_Node;
				Node_temp->Next_Node = Node_temp->Next_Node->Next_Node;

			}
			else
			{
				Node_temp = Node_temp->Next_Node;
			}
		}
	}

	if (Tobedeleted != NULL)
	{
		//delete只是删除其指向的内容,仍然需要使指针指向NULL
		delete Tobedeleted;
		Tobedeleted = NULL;
	}
}

//由数值在结尾插入结点
bool Insert_Node(Node **first,datatype value_Insert)
{
	//产生一个新结点
	Node *New_Node = new Node;
	New_Node->value = value_Insert;
	New_Node->Next_Node = NULL;

	//输入合法判断
	if (first == NULL)
	{
		return false;
	}

	if (*first == NULL)
	{
		*first = New_Node;
	}
	else
	{
		//使用临时结点,可以保证传入的first指针指向不变
		Node *Node_temp = *first;
		while (Node_temp->Next_Node != NULL)
		{
			Node_temp = Node_temp->Next_Node;
		}
		Node_temp->Next_Node = New_Node;
	}
}

void main()  
{     

	system("pause");
}  


作者:misayaaaaa 发表于2017/11/19 9:04:06 原文链接
阅读:33 评论:0 查看评论

Aerospike partition tree的内存管理

$
0
0

as_namespaces_init:

1、uint32_t stage_capacity = as_mem_check()
     for (capacity = MAX_STAGE_CAPACITY; capacity >= MIN_STAGE_CAPACITY; capacity /= 2) {
         if (check_capacity(capacity)) {
             break;
         }
     }
    申请的内存大小以16M开始,如果内存大小不够用,则申请16/2M依次类推,最小大小是2M

2、as_namespaces_setup(cold_start_cmd, instance, stage_capacity);
     ->setup_namespace(g_config.namespaces[i], stage_capacity);
     ->ns->arena = (cf_arenax*)cf_malloc(cf_arenax_sizeof());
       cf_arenax_err arena_result = cf_arenax_create(ns->arena, 0, 
	       as_index_size_get(ns), stage_capacity, 0, CF_ARENAX_BIGLOCK);
     ->uint64_t stage_size = (uint64_t)stage_capacity * sizeof(as_index);
       memset(this->stages, 0, sizeof(this->stages));
       uint8_t* p_stage = (uint8_t*)cf_malloc(this->stage_size);
       this->stages[this->stage_count++] = p_stage;
       memset(cf_arenax_resolve(this, 0), 0, sizeof(as_index));
    ns->arena->stages[256]共有256个内存stage。
     最开始,只申请对第一个stages申请16M*sizeof(as_index)的内存空间。

3、as_partition_init(ns, pid);
     ->p->vp = as_index_tree_create(&ns->tree_shared, ns->arena);
     ->tree->arena = arena;
    对partition进行初始化,树的内存都是共用一个arena,即ns->arena

run_index_tree_gc:线程回收tree的内存

1、从g_gc_queue队列中pop出回收的tree,然后调用as_index_tree_destroy函数回收

while (cf_queue_pop(&g_gc_queue, &tree, CF_QUEUE_FOREVER) == CF_QUEUE_OK) {
        as_index_tree_destroy(tree);
     }

2、递归调用as_index_sprig_traverse_purge进行回收
     即将tree的每个element的handle回收到arena的free_h链表中

作者:yanzongshuai 发表于2017/11/19 10:34:54 原文链接
阅读:18 评论:0 查看评论

HEVC代码学习32:getInterMergeCandidates函数

$
0
0

今天来看xCheckRDCostMerge2Nx2N函数中提到的重要函数getInterMergeCandidates,其功能是创建merge候选列表,这里重点来看空域候选列表的建立。

首先来回忆一下merge的空域候选列表。merge候选列表长度为5,空域最多提供4个候选,按顺序依次遍历A1-B1-B0-A0-B2,选出4个候选填入候选列表。注意,空域最终可能提供的候选数量可能少于4个。
这里写图片描述

下面来看getInterMergeCandidates工作流程:
1.初始化准备工作。
2.建立空域候选列表,按顺序依次遍历A1-B1-B0-A0-B2位置PU,对每个位置进行以下操作,选出最多4个候选。
(1)检测是否有效
(2)若有效则写入候选列表记录其MV
(3)检测列表是否已满
3.建立时域候选列表。
4.为B Slice建立组合列表。
5.候选列表未满时,用0填充。

代码分析:

//! Construct a list of merging candidates  构造merge候选列表
Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx )
{
  /******************************************初始化准备工作**************************************/
  UInt uiAbsPartAddr = m_absZIdxInCtu + uiAbsPartIdx;       //当前CU的ZScan地址
  Bool abCandIsInter[ MRG_MAX_NUM_CANDS ];      //MRG_MAX_NUM_CANDS最大候选数为5
  for( UInt ui = 0; ui < getSlice()->getMaxNumMergeCand(); ++ui )
  {
    abCandIsInter[ui] = false;
    pcMvFieldNeighbours[ ( ui << 1 )     ].setRefIdx(NOT_VALID);
    pcMvFieldNeighbours[ ( ui << 1 ) + 1 ].setRefIdx(NOT_VALID);
  }
  numValidMergeCand = getSlice()->getMaxNumMergeCand(); //最大有效候选数为5
  // compute the location of the current PU 计算当前PU的位置
  Int xP, yP, nPSW, nPSH;
  this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH);       //获取当前PU的索引、起始坐标、高和宽

  Int iCount = 0;

  UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
  PartSize cCurPS = getPartitionSize( uiAbsPartIdx );       //获取当前CU的分割模式
  deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT );      //左上右上块索引
  deriveLeftBottomIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLB );     //左下块索引

    /******************************************建立空域候选列表**************************************/
  //left 左侧
  UInt uiLeftPartIdx = 0;
  TComDataCU* pcCULeft = 0;
  pcCULeft = getPULeft( uiLeftPartIdx, uiPartIdxLB );       //获取左侧PU

  //判断A1有效性
  Bool isAvailableA1 = pcCULeft &&      //左侧PU是否有效
                       pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) &&     //左侧PU与当前PU是否在同一运动估计区域
                       !( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) &&        //分割模式判断
                       pcCULeft->isInter( uiLeftPartIdx ) ;     //帧间预测是否有效

  if ( isAvailableA1 )      //A1有效
  {
    abCandIsInter[iCount] = true;
    // get Inter Dir
    puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx );     //获取帧间预测方向
    // get Mv from Left
    pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );        //获取左侧PU list0的MV
    if ( getSlice()->isInterB() )       //双向预测时,获取list1MV
    {
      pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    }
    if ( mrgCandIdx == iCount )
    {
      return;
    }
    iCount ++;
  }

  // early termination 达到最大候选数则退出
  if (iCount == getSlice()->getMaxNumMergeCand())   
  {
    return;
  }
  // above 上方
  UInt uiAbovePartIdx = 0;
  TComDataCU* pcCUAbove = 0;
  pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT );

  //判断B1有效性
  Bool isAvailableB1 = pcCUAbove &&
                       pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP) &&
                       !( uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD) ) &&
                       pcCUAbove->isInter( uiAbovePartIdx );

  if ( isAvailableB1 && (!isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) )
  {
    abCandIsInter[iCount] = true;
    // get Inter Dir
    puhInterDirNeighbours[iCount] = pcCUAbove->getInterDir( uiAbovePartIdx );
    // get Mv from Left
    pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
    if ( getSlice()->isInterB() )
    {
      pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    }
    if ( mrgCandIdx == iCount )
    {
      return;
    }
    iCount ++;
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand())
  {
    return;
  }

  // above right 右上
  UInt uiAboveRightPartIdx = 0;
  TComDataCU* pcCUAboveRight = 0;
  pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT );

    //判断B0有效性
  Bool isAvailableB0 = pcCUAboveRight &&
                       pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP) &&
                       pcCUAboveRight->isInter( uiAboveRightPartIdx );

  if ( isAvailableB0 && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) )
  {
    abCandIsInter[iCount] = true;
    // get Inter Dir
    puhInterDirNeighbours[iCount] = pcCUAboveRight->getInterDir( uiAboveRightPartIdx );
    // get Mv from Left
    pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
    if ( getSlice()->isInterB() )
    {
      pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    }
    if ( mrgCandIdx == iCount )
    {
      return;
    }
    iCount ++;
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand())
  {
    return;
  }

  //left bottom 左下
  UInt uiLeftBottomPartIdx = 0;
  TComDataCU* pcCULeftBottom = 0;
  pcCULeftBottom = this->getPUBelowLeft( uiLeftBottomPartIdx, uiPartIdxLB );

  //判断A0有效性
  Bool isAvailableA0 = pcCULeftBottom &&
                       pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP) &&
                       pcCULeftBottom->isInter( uiLeftBottomPartIdx ) ;

  if ( isAvailableA0 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) )
  {
    abCandIsInter[iCount] = true;
    // get Inter Dir
    puhInterDirNeighbours[iCount] = pcCULeftBottom->getInterDir( uiLeftBottomPartIdx );
    // get Mv from Left
    pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
    if ( getSlice()->isInterB() )
    {
      pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    }
    if ( mrgCandIdx == iCount )
    {
      return;
    }
    iCount ++;
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand())
  {
    return;
  }

  // above left 左上
  if( iCount < 4 )      //空域最多提供4个候选
  {
    UInt uiAboveLeftPartIdx = 0;
    TComDataCU* pcCUAboveLeft = 0;
    pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr );

    //判断B2有效性
    Bool isAvailableB2 = pcCUAboveLeft &&
                         pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP) &&
                         pcCUAboveLeft->isInter( uiAboveLeftPartIdx );

    if ( isAvailableB2 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) )
        && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) )
    {
      abCandIsInter[iCount] = true;
      // get Inter Dir
      puhInterDirNeighbours[iCount] = pcCUAboveLeft->getInterDir( uiAboveLeftPartIdx );
      // get Mv from Left
      pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
      if ( getSlice()->isInterB() )
      {
        pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
      }
      if ( mrgCandIdx == iCount )
      {
        return;
      }
      iCount ++;
    }
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand())
  {
    return;
  }

  /******************************************建立时域候选列表**************************************/
  //由时域列表最多提供1个候选
  if ( getSlice()->getEnableTMVPFlag() )
  {
    //>> MTK colocated-RightBottom
    UInt uiPartIdxRB;

    deriveRightBottomIdx( uiPUIdx, uiPartIdxRB );

    UInt uiAbsPartIdxTmp = g_auiZscanToRaster[uiPartIdxRB];
    const UInt numPartInCtuWidth  = m_pcPic->getNumPartInCtuWidth();
    const UInt numPartInCtuHeight = m_pcPic->getNumPartInCtuHeight();

    TComMv cColMv;
    Int iRefIdx;
    Int ctuRsAddr = -1;

    if (   ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxTmp] + m_pcPic->getMinCUWidth () ) < m_pcSlice->getSPS()->getPicWidthInLumaSamples () )  // image boundary check
        && ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxTmp] + m_pcPic->getMinCUHeight() ) < m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
    {
      if ( ( uiAbsPartIdxTmp % numPartInCtuWidth < numPartInCtuWidth - 1 ) &&           // is not at the last column of CTU
        ( uiAbsPartIdxTmp / numPartInCtuWidth < numPartInCtuHeight - 1 ) )              // is not at the last row    of CTU
      {
        uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + numPartInCtuWidth + 1 ];
        ctuRsAddr = getCtuRsAddr();
      }
      else if ( uiAbsPartIdxTmp % numPartInCtuWidth < numPartInCtuWidth - 1 )           // is not at the last column of CTU But is last row of CTU
      {
        uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdxTmp + numPartInCtuWidth + 1) % m_pcPic->getNumPartitionsInCtu() ];
      }
      else if ( uiAbsPartIdxTmp / numPartInCtuWidth < numPartInCtuHeight - 1 )          // is not at the last row of CTU But is last column of CTU
      {
        uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + 1 ];
        ctuRsAddr = getCtuRsAddr() + 1;
      }
      else //is the right bottom corner of CTU
      {
        uiAbsPartAddr = 0;
      }
    }

    iRefIdx = 0;

    Bool bExistMV = false;
    UInt uiPartIdxCenter;
    Int dir = 0;
    UInt uiArrayAddr = iCount;
    xDeriveCenterIdx( uiPUIdx, uiPartIdxCenter );
    bExistMV = ctuRsAddr >= 0 && xGetColMVP( REF_PIC_LIST_0, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx );
    if( bExistMV == false )
    {
      bExistMV = xGetColMVP( REF_PIC_LIST_0, getCtuRsAddr(), uiPartIdxCenter,  cColMv, iRefIdx );
    }
    if( bExistMV )
    {
      dir |= 1;
      pcMvFieldNeighbours[ 2 * uiArrayAddr ].setMvField( cColMv, iRefIdx );
    }

    if ( getSlice()->isInterB() )
    {
      bExistMV = ctuRsAddr >= 0 && xGetColMVP( REF_PIC_LIST_1, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx);
      if( bExistMV == false )
      {
        bExistMV = xGetColMVP( REF_PIC_LIST_1, getCtuRsAddr(), uiPartIdxCenter, cColMv, iRefIdx );
      }
      if( bExistMV )
      {
        dir |= 2;
        pcMvFieldNeighbours[ 2 * uiArrayAddr + 1 ].setMvField( cColMv, iRefIdx );
      }
    }

    if (dir != 0)
    {
      puhInterDirNeighbours[uiArrayAddr] = dir;
      abCandIsInter[uiArrayAddr] = true;

      if ( mrgCandIdx == iCount )
      {
        return;
      }
      iCount++;
    }
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand())
  {
    return;
  }

  UInt uiArrayAddr = iCount;
  UInt uiCutoff = uiArrayAddr;

  /******************************************为B Slice建立组合列表**************************************/
  //给B Slice建立组合列表
  if ( getSlice()->isInterB() )
  {
    static const UInt NUM_PRIORITY_LIST=12;
    static const UInt uiPriorityList0[NUM_PRIORITY_LIST] = {0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3};
    static const UInt uiPriorityList1[NUM_PRIORITY_LIST] = {1 , 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2};

    for (Int idx=0; idx<uiCutoff*(uiCutoff-1) && uiArrayAddr!= getSlice()->getMaxNumMergeCand(); idx++)
    {
      assert(idx<NUM_PRIORITY_LIST);
      Int i = uiPriorityList0[idx];
      Int j = uiPriorityList1[idx];
      if (abCandIsInter[i] && abCandIsInter[j]&& (puhInterDirNeighbours[i]&0x1)&&(puhInterDirNeighbours[j]&0x2))
      {
        abCandIsInter[uiArrayAddr] = true;
        puhInterDirNeighbours[uiArrayAddr] = 3;

        // get Mv from cand[i] and cand[j]
        pcMvFieldNeighbours[uiArrayAddr << 1].setMvField(pcMvFieldNeighbours[i<<1].getMv(), pcMvFieldNeighbours[i<<1].getRefIdx());
        pcMvFieldNeighbours[( uiArrayAddr << 1 ) + 1].setMvField(pcMvFieldNeighbours[(j<<1)+1].getMv(), pcMvFieldNeighbours[(j<<1)+1].getRefIdx());

        Int iRefPOCL0 = m_pcSlice->getRefPOC( REF_PIC_LIST_0, pcMvFieldNeighbours[(uiArrayAddr<<1)].getRefIdx() );
        Int iRefPOCL1 = m_pcSlice->getRefPOC( REF_PIC_LIST_1, pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getRefIdx() );
        if (iRefPOCL0 == iRefPOCL1 && pcMvFieldNeighbours[(uiArrayAddr<<1)].getMv() == pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getMv())
        {
          abCandIsInter[uiArrayAddr] = false;
        }
        else
        {
          uiArrayAddr++;
        }
      }
    }
  }
  // early termination
  if (uiArrayAddr == getSlice()->getMaxNumMergeCand())
  {
    return;
  }

  Int iNumRefIdx = (getSlice()->isInterB()) ? min(m_pcSlice->getNumRefIdx(REF_PIC_LIST_0), m_pcSlice->getNumRefIdx(REF_PIC_LIST_1)) : m_pcSlice->getNumRefIdx(REF_PIC_LIST_0);

    /******************************************列表未满,用0填充**************************************/
  Int r = 0;
  Int refcnt = 0;
  while (uiArrayAddr < getSlice()->getMaxNumMergeCand())
  {
    abCandIsInter[uiArrayAddr] = true;
    puhInterDirNeighbours[uiArrayAddr] = 1;
    pcMvFieldNeighbours[uiArrayAddr << 1].setMvField( TComMv(0, 0), r);

    if ( getSlice()->isInterB() )
    {
      puhInterDirNeighbours[uiArrayAddr] = 3;
      pcMvFieldNeighbours[(uiArrayAddr << 1) + 1].setMvField(TComMv(0, 0), r);
    }
    uiArrayAddr++;

    if ( refcnt == iNumRefIdx - 1 )
    {
      r = 0;
    }
    else
    {
      ++r;
      ++refcnt;
    }
  }
  numValidMergeCand = uiArrayAddr;
}
作者:lin453701006 发表于2017/11/19 11:24:30 原文链接
阅读:0 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


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