learning notes

2017/02/24

1、 Server所在进程启动后,需要将其中的Servic注册到ServiceManager,这样Client就可以通过ServiceManager找到对应的Binder引用,而ServiceManager自身的Binder引用时通过BinterInternal.getContextObject()函数获得。

2、 我们在写程序时,通过getSystemService获得XXXManager,在XXXManager中保存了一个IXXX变量,这个变量可能是Proxy类型,也可能是Stub类型,这个过程被asInterface函数屏蔽了。

3、Context是一个抽象类,ContextWrapper是对Context的封装,它包含一个Context类型的变量,ContextWrapper的功能函数内部其实都是调用里面的Context类型变量完成的。Application,Service,Activity等都是直接或者间接继承自ContextWrapper,但是并没有真正的实现其中的功能,Application,Service,Activity中关于Context的功能都是通过其内部的Context类型变量完成的,而这个变量的真实对象必定是ContextImpl,所以每创建一个Application,Activity,Servcice便会创建一个ContextImpl,并且这些ContextImpl中的mPackages和mResources变量都是一样的,所以不管使用Acitivty还是Service调用getResources得到相同的结果。

4、在一个apk中,Context的数量等于Activity个数+Service个数+1。

5、wait()、notify()和notifyAll()是 Object类 中的方法

​ await()、signal()、signalAll()是Condition类中的方法

​ 因此调用wait()、notify()方法必须在同步块或者同步方法中进行(synchronized块或者

synchronized方法)。

6、JVM垃圾回收方式:新生代基本采用复制算法,老年代采用标记整理算法,CMS采用标记清理。

7、需要使用抽象类的情况:

当一个类的一个或多个方法是抽象方法时;

当类是一个抽象类的子类,并且不能为任何抽象方法提供任何实现细节或方法体时;

当一个类实现一个接口,并且不能为任何抽象方法提供实现细节或方法体时。

2017/02/23

C语言实现单链表的初始化、创建、遍历等操作:

#include

#include

typedef struct LNode

{

int data;

struct LNode *next;

}LNode,*LinkList;

LinkList Init_LNode() //链表初始化

{

LNode *L;

L = (LinkList)malloc(sizeof(LNode));

if(L == NULL)

{

    printf("初始化失败!\n");

    exit(-1);

}

L->next = NULL;

    return L;

}

void Creat_List1(LNode *L) //头插法

{

int i,n,num;

LNode *pnew;



printf("请输入要输入的元素个数:n = ");

scanf("%d",&n);

for(i=0;i<n;i++)

{

    printf("请输入第%d个数:",i+1);

    scanf("%d",&num);

    pnew = (LinkList)malloc(sizeof(LNode));

    pnew->data = num;

    pnew->next = L->next;

    L->next = pnew;

}

}

img

void Creat_List(LNode *L) //创建 尾插法

{

int i,n,num;

LNode *p,*pnew;

p = L;

printf("请输入要输入的元素个数:n = ");

scanf("%d",&n);

for(i=0;i<n;i++)

{

    printf("请输入第%d个数:",i+1);

    scanf("%d",&num);

    pnew = (LinkList)malloc(sizeof(LNode));

    if(pnew == NULL)

    {

        printf("初始化失败!\n");

        exit(-1);

    }

    pnew->data = num;

    p->next = pnew;

    p = pnew;

}

p->next =NULL;

}

img

void Show_Linst(LNode *L) //遍历

{

LNode *p;

p =L->next;

while(p!=NULL)

{

    printf("%d ",p->data);

    p = p->next;



}

printf("\n");

}

void Insert_List(LNode *L) //插入

{

int i , n , val;

LNode *p,*s;

p = L;

i=1;

printf("请输入你要插入的位置:n=");

scanf("%d",&n);

printf("请输入你要插入的元素:val=");

scanf("%d",&val);

while(p&&i<n)

{

    p = p->next;

    ++i;

}

if(!p || i>n)

    printf("无法插入!\n");

s = (LinkList)malloc(sizeof(LNode));

s->data = val;

s->next = p->next;

p->next = s;

}

void Delete_List(LNode *L) //删除

{

int i , n ;

LNode *p,*s;

p = L;

i=1;

printf("请输入你要删除的位置:n=");

scanf("%d",&n);

while(p&&i<n)

{

    p = p->next;

    ++i;

}

if(!(p->next) || i>n)

    printf("删除的位置不合法!\n");

// p->next =p->next->next;

s = p->next;

p->next = s->next;

free(s);

}

void Query_List(LNode *L) //查询

{

int i , n ,val;

LNode *p;

p = L->next;

i=1;

printf("请输入你要查询的位置:n=");

scanf("%d",&n);

while(p&&i<n)

{

    p = p->next;

    ++i;

}

if(!(p->next) || i>n)

    printf("查询的元素不存在!\n");

val = p->data;

printf("你查询的元素值为:%d\n",val);

}

void Destroy_List(LNode *L) //销毁

{

LinkList p,q;

p = L->next;    //p指向第一个结点

while(p)

{

    q = p->next;

    free(p);

    p = q;

}

L->next = NULL;

}

int Show_Menu() //主菜单

{

int num;

printf("********************************************\n");

printf("\n  【1】创建            【2】插入\n");

printf("\n  【3】删除            【4】查询\n");

printf("\n  【5】遍历            【6】退出\n");

printf("\n********************************************\n");

printf("请输入你的操作序号:");

if(scanf("%d",&num)==0)

{

    printf("请重新输入!\n");

}

return num;

}

int main(int argc,char *argv[])

{

LinkList S;

int val;

S = Init_LNode();

if(S == NULL)

{

    printf("初始化失败!\n");

}

while(val!=6)

{

val = Show_Menu();

switch(val)

{

case 1:

        Creat_List(S);        //尾插法

        //Creat_List1(S);    //头插法

        break;

case 2:

        Insert_List(S);        //插入

        break;

case 3:

        Delete_List(S);        //删除

        break;

case 4:

        Query_List(S);        //查询

        break;

case 5:

        Show_Linst(S);        //显示

        break;

case 6:

        Destroy_List(S);    //销毁

        exit(0);

        break;

}

}

}

2017/02/22

1、非空二叉树,叶子数 + 1 = 结点数

2、二叉树 先序遍历:中左右,中序遍历:左中右

3、CPU中,寄存器访问速度最快

4、画图能使抽象问题形象化,举例能使抽象问题具体化,分解能使复杂问题简单化

5、想要优化代码效率,需要熟悉数据结构

6、Java中:

栈Stack(先进后出),入栈(push、add),出栈(pop)

队列Queue(先进先出),入队(offer、add),出队(poll)

获取 队头/栈顶 元素,使用peek

7、使用LinkedList类实现栈和队列更为方便:

对于栈:常用等效方法有 addFirst(e)、removeFirst()、peekFirst()、isEmpty()

对于队列:常用的等效方法有 offerLast(e)、pollFirst()、peekFirst()、isEmpty()

2016/11/26

1、codeblocks(C99标准)不支持在for循环里面定义变量

2、codeblocks(C99标准)不支持在循环中设置判断条件while(true),可改为while(1)

3、PCB(process control block)进程控制块

4、操作系统进程调度算法:

完成时间=开始时间+需要运行时间

周转时间=完成时间-到达时间

等待时间=上一个进程完成时间-本进程到达时间

①短作业(进程)优先:当上一进程运行结束之后,下面的进程根据所需服务时间进行排序,所需服务时间越短,越先执行。短作业优先算法,如果某一进程占用了处理机,则除非因某事件发生被阻塞而放弃处理机再重新调度,否则一直执行到完成;

②时间片轮转调度:采用先来先执行的原则,但是不采用进程一旦占用处理机就执行至完成的算法,而是为进程设置时间片,用队列的方式对进程进行动态调用执行,直到每个进程都执行完成(状态为finish);

③响应比优先:优先权=(等待时间+需要运行时间)/需要运行时间。

2016/11/24

1、用例图 (用例、参与者、关系、系统边界)

2、上下文图 (数据流图最高层,系统功能的最高抽象)

3、数据流图 (数据源(人、物、其他系统)、数据流、数据加工处理、数据存储)

4、实体-联系图(E-R图) (实体、属性、实体之间的联系)

2016/11/22

1、关于sql 删除指定课程名称的外键约束问题,采用级联删除解除约束

alter table SC add constraint fk_test foreign key (Cno) references Course(Cno) on delete cascade;(解除非多重级联删除的)

alter table Course drop constraint FKCourseCpno__09DE7BCC(解除多重级联删除的, 约束键值为报错信息中所给的值)

2、

这个语句没问题

select Student.Sno,Sname,Cno,Grade

from Student,SC

where Student.Sno = ‘201215121’ and Student.Sno = SC.Sno;

这个语句有问题

select Student.Sno,Sname,Cno,Grade

from Student,SC

where Sno = ‘201215121’ and Student.Sno = SC.Sno;

2016/11/12

Java输入输出:

1、绝对路径如:“C:/java/demo” 相对路径:“demo”

2、/ 是转义字符,表示路径的方法可以是: ①\ ②//

3、Windows平台的换行符是:\r\n

4、Java.io主要包括输入、输出两种IO流,每种又可分为字节流(8位)和字符流(16位)两大类

5、File类不能访问文件内容本身,需要使用输入/输出流

6、File类提供了很多方法来操作文件和目录,详情看书本

7、文件过滤器:File类的list()方法可以接受一个filenamefilter参数(此接口包含一个accept(File dir ,String name)方法,用此方法加上lambda表达式,即可实现过滤器)

8、

img

9、处理流的用法:通常需要在创建处理流时传入一个节点流作为构造器参数即可

​ 例子:

​ FileOutputStream fos = new FileOutputStream(“test.txt”);

​ PrintStream ps = new PrintStream(fos);

10、计算机的文件分为文本文件(能用记事本打开并查看内容)和二进制文件两大类

11、StringReader对象和StringWriter对象相较于FileReader和FileWriter不同的是,创建对象时传入的是字符串节点,而不是文件节点

2016/11/11

1、一般的类声明有如下几个部分:

【modifiers】class ClassName【extends SuperClassName】【implement InterfaceNames】

2、abstract(抽象)类不能直接实例化为对象,子类会用不同的方式实现本类的方法

​ final类具有唯一性,不能再有子类(即不能再被继承)

3、类变量(static),系统在第一次遇上时即为它分配内存,类的所有实例对象共享这个类变量,通常用于定义常数,因为常数对所有对象来说都不变

4、类变量可以用类名来访问,实例变量不能

5、成员变量以及方法的访问限制,其声明的形式和定义完全一样,有四类:private、public、protected、friendly(虽友好但不给子类访问权限),访问权限请看书本

6、语法细节:参数名可以与成员变量同名,但不能与局部变量同名

​ this在方法体中指当前对象的成员,包括成员变量和方法

​ super用于指定当前对象所隐藏或重写的超类的成员

分簇+触摸屏精确定位Algo

问题分析

现代生活,触摸屏手机已是非常普及,可以说人手一只。我们只要用手指轻轻在屏幕上触碰,手机就能感应到我们的操作,并且执行相应的功能。那么,手机是怎样定位到触摸点的呢?这个就是我们今天要讨论算法所重点要模拟解决的问题。

解决的思路是:把我们手机屏幕看成一个二维坐标系,横竖分别分为X轴和Y轴,这样我们就可以通过坐标值来定位某个点。知道如何表示触摸点还不足够,我们怎样确定定位点呢?这就涉及到硬件了,每个屏幕TP上面都会有电容感应器,当你用手触摸某个地方时,那里对应的电容值便会升高。多点触摸,就会有多个地方电容值升高。

但问题又来了,我们触摸的地方往往是一个区域,因为我们手指有一定的宽度。所以,我们需要按电容值的高低对屏幕坐标先进行分簇,即局部最大值聚类。对np_values搜索局部极大值。如果只找到一个局部最大值,则有一个单点触摸。如果找到多个局部极大值,则有多个接触。

分簇完成,接下来就好办了,可以通过计算电容加权平均值得出每个分簇的精确定位。

分簇实现

下面是一个屏幕电容值的模拟数据表:

img

可以看到,表中所给电容值横轴方向、纵轴方向都有所变化,当触摸屏某个位置有触摸动作发生时,该处电容值会升高,由此可判断出,上图中有两处按压。

可得到两个序列:

x轴序列是{0,6,137,84,9,4},Y轴序列是{1,4,45,25,2,2,13,52,58,15,4}。

分簇要找的就是所给序列的突峰区间,如果用索引(坐标索引从0开始计)来表示的话,上述x轴序列有一个分簇区间[0,5],y轴序列有两个分簇区间[0,4]和[5,10]。图示如下:

imgimg

img img

最后,我们需要输出分簇结果:x轴分簇[0,5],y轴分簇[0,4]、[5,10]。

分簇算法实现的难点在哪儿呢?我觉得应该是如何判断一个分簇的开始与结束。为了实现判断,我在遍历索引的时候,加上了标志变量(如果当前电容值比它的前者大的话,标志变量置1,否则置2)。然后在输出分簇的时候,我们就可以通过判断标志变量,准确输出区间。主要实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
printf("x方向上的增减标志位如下:\n");
for (i = 0; i < x-1; i++)
{
if(xx[i] <= xx[i+1])
{
xTag[i] = 1;
}
if(xx[i] >= xx[i+1])
{
xTag[i] = 2;
bianjieX++;
}
printf("%d", xTag[i]);
}
printf("y方向上的增减标志位如下:\n");
for (j = 0; j < y-1; j++)
{
if(yy[j] <= yy[j+1])
{
yTag[j] = 1;
}
//根据区间来看,前后相等的情况应该赋值为2,所以上面小于情况的=号可下可不下
if(yy[j] >= yy[j+1])
{
yTag[j] = 2;
bianjieY++;
}
printf("%d", yTag[j]);
}
//定义二维数组用于存储区间的索引
for (i = 0; i < x-1; i++) {
if(xTag[i] == 2 && xTag[i+1] == 1) {
xsection[count++][1] = i;
xsection[count][0] = i+1;
}
}
if(xsection[count][1] == 0) {
xsection[count][1] = x-1;
}
while(i < x-1) {
printf("\nX方向上的分簇[%d, %d]", xsection[i][0], xsection[i][1]);
}

精确定位实现

有了分簇结果,我们就可以借用分簇结果来计算每个分簇对应的精确坐标值了。计算的过程:首先需要找到分簇区间中每个索引对应的电容值,把电容值累加到变量CapacitanceALL,然后将每个索引值*对应电容值累加到变量AddAll,最后就可通过AddAll / CapacitanceALL来计算出每个分簇的精确值location。

主要实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
while(i < x-1) {
printf("\nX方向上的分簇[%d, %d]", xsection[i][0], xsection[i][1]);
AddAll = 0.0,CapacitanceALL = 0.0;
location = 0.0;
//输出此段分簇区间的精确定位
for(m = xsection[i][0];m <= xsection[i][1];m++)
{
AddAll = AddAll + xx[m] * m;
CapacitanceALL = CapacitanceALL + xx[m];
}
location = AddAll / CapacitanceALL;
printf(" 此段分簇区间的加权精确x值是:%.3f",location);
i++;
if(xsection[i][0] == 0) {
break;
}
}

算法测试

测试数据用的是上面提供电容模拟表中的数值,分别输入X、Y方向上的电容值,测试结果如下:

img

后言

关于这个算法就介绍这么多了,有什么不对的地方还望多多指教,也欢迎大家关注我(简书/GitHub

谢谢观看此文。

源代码地址​http://pan.baidu.com/s/1slAOoTf

|