Fork me on GitHub
drqblog


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 日程表

  • 站点地图

  • 公益404

  • 有料

Oracle数据库之触发器

发表于 2018-12-12 | 分类于 数据库
字数统计: 273 | 阅读时长 ≈ 1

一、触发器

有点类似AOP里的拦截器,触发器不能传递参数,也不能输出参数,也不能显式调用,只有当满足触发器条件的时候Oracle会自动调用。

触发器:

  1、语句级别的触发器:CRUD操作

  2、行级别的触发器

  3、系统级别的触发器:数据库的关闭,启动

  4、用户事件的触发器:进行drop,alter,create时候触发

二、触发器的创建

1
2
3
4
5
6
7
8
9
--创建行级别的触发器CREATE OR REPLACE trigger trigger_update_product_table
AFTER UPDATEON product_tableFOR EACH ROW --每更新一行,就触发一次BEGIN
--Oracle里面对触发器提供了特殊的对象:NEW :OLD来访问更新前后的数据
DBMS_OUTPUT.put_line('更新后'||:NEW.name);--orcle使用||符号链接字符串而已,相当于java中的+连接字符串
DBMS_OUTPUT.put_line('更新前'||:OLD.name);
IF UPDATING THEN

END IF;
IF INSETINGEND;
1
2
3
4
5
--创建表级别的触发器CREATE OR REPLACE trigger trigger_update_product_table
AFTER UPDATEON product_tableBEGIN
--表级别触发器里面,不允许使用:NEW :OLD变量
--DBMS.OUTPUT.put_line('更新后:'||:NEW.name);
--DBMS.OUTPUT.put_line('更新前:'||:OLD.name);END;

Oracle数据库

发表于 2018-12-12 | 分类于 数据库
字数统计: 769 | 阅读时长 ≈ 2

1、Oracle中使用rownum来进行分页,这个是效率最好的分页方法

1
2
select * from ( select rownum rn,a from tabName where rownum<=20) 
where rn>10

2、Oracle的索引使用

创建索引:

1
create index index_name on table_name(collum_name)

索引使用规则:

  1、经常和其他表进行连接的表,在连接字段上应该建立索引。

  2、经常出现在where子句中的字段而且过滤性很强的,特别是大表的字段,应该建立索引

索引的优点:

  1、建立唯一性索引,可以保证数据库表中的每一行数据的唯一性

  2、大大加快数据的检索速度,加速了表和表之间的连接,特别是实现数据的参照完整性。

  3、在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间

索引的缺点:

  1、索引创建在表上,不能创建在索引上

  2、创建索引和维护索引耗费时间,时间随着数据量的增加而增加

  3、索引需要占用物理空间,除了数据表占用数据空间之外,每一个索引还要占用一定的物理空间,如果要建立聚集索引,那么消耗的空间更大,一个表只能有一个聚集索引。

  4、当对表中的数据进行增加,删除,修改的时候,索引也需要动态的维护,降低了数据的维护速度。

3、视图的使用

创建视图:

1
create view view_name as select column_name from table_name

视图的优点:

  1、可以简单的将视图理解为SQL查询语句,视图最大的好处就是不占用系统空间

  2、一些安全性很高的系统,不会公布系统的表结构,可能会使用视图将一些敏感信息过滤或者重命名后公布结构

  3、简化查询,可以控制权限,在使用的时候需要将视图的使用权限grant给用户。

4、合并查询

有时候,为了合并多个select语句的结果,可以使用集合操作符号UNION,UNION ALL,INTERSECT,MINUS多用于数据量比较大的数据库,运行速度快。

  1、union:取得两个结果集的并集,使用它时,会自动去掉结果集中重复行

  2、union all:也是取得两个结果集的并集,但是不会取消重复行,也不会排序。

  3、intersect:取得两个结果集的交集

  4、minus:取得两个结果集的差集。

5、维护数据的完整性

数据的完整性用于确保数据库数据遵从一定的商业规则和逻辑规则。

Oracle中,数据完整性可以使用约束,触发器,应用程序(存储过程,函数)来实现。这三个因为约束更容易维护,并且具有最好的性能,所以作为维护数据完整性的首选。

不过约束还可以用:not null,unique,primary key,foreign key,check

数组与链表

发表于 2018-12-12 | 分类于 计算机
字数统计: 789 | 阅读时长 ≈ 2

内存的工作原理

1.个人理解:

  比如你要去逛超市,需要将东西寄存,寄存处有一个柜子,柜子有很多抽屉。每个抽屉可以放一样东西,你有两样东西,所以要了两个抽屉。这大概就是计算机内存的工作原理。计算机就像很多抽屉的集合体,每个抽屉都有地址。

  当你需要将数据存储到内存时,你请求计算机提供存储空间,计算机会给你一个存储地址。但是当你要存储多项数据时,有两种基本方式:1.使用数组 2.使用链表,但是他们并不是都适用于所有的情形,要进行适当的选择。

2.数组和链表

数组:在内存中都是相连的(紧靠在一起的)

链表:链表中的严肃可存储在内存的任何地方。链表的每个元素都存储了下一个元素的地址,从而使得一系列随机的内存地址串在了一起。

  • 访问元素(查询):数组更好选择

  但是链表存在问题,比如当你需要读取链表的最后一个元素时,你不能直接读取,因为你根本不知道它所处的地址,所以必须先访问第一个元素,然后获取第二个元素的地址,在访问第三个,以此类推,直到访问到最后一个元素。当你需要同时读取所有元素时,链表的效率很高。但是当你需要跳跃读取某个元素,链表的效率很低。数组不一样,因为你是知道每个元素的地址的,根据数组的下标可以算出来。比如一个数组里有五个元素,起始地址为000,那么第五个元素的地址肯定是004.所以当你需要随机访问元素时,数组效率很高,可以迅速的找到数组的任何元素。在链表中,元素并非靠在一起,你无法迅速计算出第五个元素的内存地址,必须县访问第一个元素以获取第二个,依次下去。

  • 插入操作(中间插入):链表更好选择

  加入你要在中间插入一个元素,使用链表时,插入元素很简单,只需要修改前面那个元素的指针指向。但是使用数组时,则必须先将后面的元素都向后移动,如果没有足够的空间,可能还要将整个数组复制到其他地方。

  • 删除操作:链表更好选择

  因为你只需要修改前一个元素指向的地址就行。使用数组,删除元素后,比如将后面的元素都向前移动。不同于插入,删除元素总能成功。如果内存中没有足够的空间,插入操作可能失败,但是任何情况下都能将元素删除

比较 数组 链表
读取 O(1) O(N)
插入 O(N) O(1)
删除 O(N) O(1)

折半查找

发表于 2018-12-12 | 分类于 计算机
字数统计: 423 | 阅读时长 ≈ 1

查找

  • 线性结构:顺序查找,折半查找,分块查找

  • 树形结构:二叉搜索树(二叉排序树),AVL平衡二叉树,B树,B+树

  • 散列结构:散列表Hash,性能分析,冲突处理,效率指标–平均查找长度,查找成功,查找失败

线性表顺序查找:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct List{
ElemType *elem;
int table_len;//表长
}SSTable;

int Search_Seq(SSTable st,ElemType key)
{

//顺序表st种顺序查找关键字key的元素,并返回元素的表中位置
st.elem[0]=key;
for(int i=st.table_len;st.elem[i]!=key;--i)//从后往找
{ return i;
}
}
  • 折半查找:二分查找,只用在有序的顺序表

  • 算法思想:首先将给定值key和表中中间位置元素的关键字比较,如果相等,成功,返回元素位置

1
2
3
4
5
6
7
8
9
10
11
12
13
int Binary_Search(SeqList L,ElemType key)
{
int low=0,mid;
int high=L.Table_len-1;
while(low<=high)
{
mid=(low+high)/2;//取中间位置
if(L.elem[mid==key])return mid;
else if(L.elem[mid]>key)high=mid-1;//关键字比中间值小,从前半部分查找
else low=mid+1;//关键字比中间值大,从后半部分查找
}
return -1;
}//时间复杂度为O(logN)
  • 分块查找:索引顺序查找,吸取顺序查找和折半查找的优点,有动态结构,适用于快速查找

  • B树:多路平衡查找树

  • Hash表:一个把查找表中的关键字映射成该关键字对应地址的函数,叫做Hash(key)=Addr。

  • 散列表:根据关键字而直接进行访问的数据结构,也就是,散列表建立了关键字和存储地址之间的一种直接映射关系。

二叉树

发表于 2018-12-12 | 分类于 计算机
字数统计: 959 | 阅读时长 ≈ 4

二叉树的遍历:

  • 前序遍历:根左右

  • 中序遍历:左根右

  • 后序遍历:左右根

  • 层次遍历:一层一层的遍历,类似广度优先

二叉树的存储结构

  • 二叉树以二叉链表结构存储,也就是1个数据域,两个指针域(分别指向左右孩子)
1
2
3
4
5
6
7
//二叉树的二叉链表结构定义
typedef char ElemType;
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree
  • 二叉树的建立,先按照前序遍历的方式建立二叉树,当然也可以按照中序遍历或者后序遍历的方式建立二叉树
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
//以前序遍历的方式建立二叉树
void CreateBiTree(BiTree *T)
{
ElemType ch;
cin>>ch;
if(ch=='#')
{
*T=NULL;
}
else
{

*T=(BiTNode)malloc(sizeof(BiTNode));
if(!*T)
{
exit(OVERFLOW);//分配内存失败退出

}
else
{
(*T)->data=ch;//生成结点
CreateBiTree(&(*T)->lchild);//构造左子树
CreateBiTree(&(*T)->rchild);//构造右子树

}
}

}

递归前序遍历二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//递归方式前序遍历二叉树

void PreOrderTraverse(BiTree T,int level)
{
if(T==NULL)
{
return;
}
else
{
Display(T->data);
Floor(T->data,level);//输出了层数
PreOrderTraverse(T->lchild,level+1);
PreOrderTraverse(T->rchild,level+1);
}
}

递归中序遍历二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//递归中序遍历
void InOrderTraverse(BiTree T,int level)
{ if(T==NULL)
{
return;
}
else
{
InOrderTraverse(T->lchild,level+1);
Display(T->data);
Floor(T->data,level);
InOrderTraverse(T->rchild,level+1);
}
}

递归后序遍历二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//递归后序遍历
void PostOrderTraverse(BiTree T,int level)
{ if(T==NULL)
{
return;
}
else
{
PostOrderTraverse(T->lchild,level+1);
PostOrderTraverse(T->rchild,level+1);
Display(T->data);
Floor(T->data,level);
}
}

中序遍历非递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void InOrder(BiTree T)
{
InitStack(S);
BiTree p=T;//p是遍历指针
while(p||!isEmpty(S))
{
if(p)//根指针进站,遍历左子树
{
Push(S,p);
p=p->lchild;
}
else{
Pop(S,p);
visit(p);
p=p->rchild;
}
}
}

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef char ElemType;//二叉树的二叉链表结构,也就是二叉树的存储结构,1个数据域,2个指针域(分别指向左右子结点)
typedef struct BiTNode {
ElemType data;
struct BiTNode lchild,rchild;
}BiTNode,*BiTree;

//以前序遍历的方式建立二叉树
void CreateBiTree(BiTree *T) {
ElemType ch;
cin>>ch;
if(ch=='#')
{
*T=NULL;
}
else
{
` T=(BiTNode)malloc(sizeof(BiTNode));
if(!T)
{
exit(OVERFLOW);//分配内存失败退出
}
else
{
(T)->data=ch;//生成结点
CreateBiTree(&(T)->lchild);//构造左子树
CreateBiTree(&(*T)->rchild);//构造右子树
}
}
}

//将二叉树前序遍历输出
void Display(ElemType ch) {
cout<<ch<<" ";
}

//在输出的基础上,输出层数
void Floor(ElemType ch,int level) {
cout<<ch<<"在第"<<level<<"层"<<end;
}

//递归方式前序遍历二叉树
void PreOrderTraverse(BiTree T,int level) {
if(T==NULL)
{
return;
}
else
{
Display(T->data);
Floor(T->data,level);//输出了层数
PreOrderTraverse(T->lchild,level+1);
PreOrderTraverse(T->rchild,level+1);
}
}

//递归中序遍历
void InOrderTraverse(BiTree T,int level) {
if(T==NULL)
{
return;
}
else
{
InOrderTraverse(T->lchild,level+1);
Display(T->data);
Floor(T->data,level);
InOrderTraverse(T->rchild,level+1);
}
}

//递归后序遍历
void PostOrderTraverse(BiTree T,int level) {
if(T==NULL)
{
return;
}
else
{
PostOrderTraverse(T->lchild,level+1);
PostOrderTraverse(T->rchild,level+1);
Display(T->data);
Floor(T->data,level);
}
}

int main() {
int level=1;//表示层数
BiTree T=NULL;
cout<<"请以前序遍历的方式输入二叉树:";//类似输入AB#D##C##
CreateBiTree(&T);//建立二叉树,没有树,无法遍历
cout<<"递归前序遍历输出:"<<endl;
PostOrderTraverse(T,level);
cout<<end;
cout<<"递归中序遍历输出为:"<<end;
InOrderTraverse(T,level);
cout<<endl;
cout<<"递归后序遍历输出为:"<<endl;
PostOrderTraverse(T,level);
cout<<endl;
return 0;
}

Python3入门

发表于 2018-12-12 | 分类于 计算机
字数统计: 1.5k | 阅读时长 ≈ 6

Python3的入门

  • Win+R键,输入cmd,输入python,查看版本

    Python3

  • 使用交互式IPython运行Python

    IPython是一个Python的交互式shell,比默认的Python shell好用多,支持变量自动补全,自动缩进,支持bash shell命令,内置了许多很有用的功能和函数

    安装:pip install ipython

Python3基础语法

  • 编码

    默认情况下,Python3源码文件以UTF-8编码,所有字符串都是UNICODE字符串

    1
    #  -*-coding:cp-1252 -*-
  • 注释

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #这是第一个注释
    print("hello,Python3!")
    多行注释,用'''或者"""
    '''
    注释块
    '''
    """
    注释块
    """
  • 行与缩进

    python最具有特色就是使用缩进来表示代码块,不需要使用大括号{}

    1
    2
    3
    4
    if True:
    print("True")
    else:
    print("False")
  • 数字类型Number

    python中数字有四种类型:整数,布尔,浮点,复数

    • int:整数,表示长整型
    • bool:布尔,True,False
    • float:浮点数,1.23,3E-2
    • complex:复数,1+2j,1.1+2.2j
  • 字符串String

    python中单引号和双引号使用完全相同

    三个引号,用来表示多行的字符串

    1
    2
    3
    4
    5
    word='字符串'
    sentence="这是一个句子"
    paragraph="""这是一个段落
    ,可以多行组成
    """"
  • import与from…import

    • 使用import或者from…import导入相应的模块

    • 将整个模块导入:import module

    • 从某个模块中导入某个函数:from module import function

    • 从某个模块中导入多个函数:from module import function1,function2

    • 将某个模块中的全部函数导入:from module import *

      1
      2
      3
      4
      5
      6
      7
      #导入sys模块
      import sys
      print("======================Python import module===========")
      print('命令行参数为:')
      for i in sys.argv:
      print(i)
      print('\n python 路径为',sys.path)
  • Python3基本数据类型

    • python中的变量不需要生命,每个变量在使用之前都必须复制,变量赋值以后该变量才会被创建。

    • 在Python中,变量就是变量,没有类型,我们所说的类型是变量所指的内存中对象的类型

      1
      2
      3
      4
      5
      6
      couter=100#整型变量
      miles=100.0#浮点型变量
      name='python3'#字符串
      print(counter)
      print(miles)
      print(name)
  • Python3的标准数据类型

    • Number数字

      • Python3中支持,int,float,bool,complex

      • 内置函数type()

        1
        2
        3
        a,b,c,d=20,1.1,True,1+2j
        print(type(a),type(b),type(c),type(d))
        #<class 'int'> <class 'float'> <class 'bool'> <class 'complex'>
      • 内置函数isinstance(),类似java中instanceof

        1
        2
        3
        a=111
        isinstance(a,int)
        #True
    • String字符串

      • Python使用反斜杠\转义特殊字符,如果不想让反斜杠发生转义,可以再字符串前面添加一个r,表示原始字符串:

        1
        2
        3
        4
        print('Py\thon3')
        #Py thon3
        print(r'Py\thon3')
        #Py\thon3
    • List列表

      List列表是Python中使用最频繁的数据类型

      列表可以完成大多数集合类的数据结构实现。

      变量[头下标:尾下标]

      1
      2
      3
      4
      5
      6
      list=['abcd',123,2.1,2+1j,True]
      print(list)
      print(list[0])
      print(list[1:3])#输出第1
      print(list[2:])#下标从2开始输出所有,list元素下标从0开始
      print(list*2)#输出两次列表
    • Tuple元组

      • 元组Tuple是不可以修改元素,写在()里,和list类似,只不过list写在[]里
      1
      2
      3
      4
      5
      6
      tuple=('abcd',784,1.11,1+2j,True)
      print(tuple)
      print(tuple[0])
      print(tuple[1:3])
      print(tuple*2)
      tuple[1]=123#修改元素元素的操作是非法的
    • Set集合

      • 是由一个或者多个形态各异的大小整体组成

      • 可以使用{}大括号,或者set()函数创建集合

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        student={'tom',123,True,1+2j,'tom'}
        print(student)#输出集合,重复的元素被自动去掉
        #成员测试
        if 'tom' in student:
        print('tom在集合中')
        else 'Tom' in student:
        print('Tom不在集合中')

        #set可以进行集合运算
        a=set('Hello')
        b=set('Python3')
        print(a)
        print(a-b)#a和b的差集
        print(a|b)#a和b的并集
        print(a&b)#a和b的交集
        print(a^b)#a和b不同是存在的元素
    • Dictionary字典

      • 列表List是有序的对象集合,字典是无需的对象集合。

      • 字典中的元素是通过key来存取的,列表list中是通过下标来的

      • 字典是一种映射类型,字典用{},一个无序的key-value集合

        1
        2
        3
        4
        5
        6
        7
        8
        9
        dict={}
        dict['one']='Hello'
        dict[2]='Python3'
        dictionary={'name':'Hello',1:"Python3",True:1,1+2j:1+2j,1.2:1.2}
        print(dict['one'])#输出键为'one'的值
        print(dict[2])#输出键为2的值
        print(dictionary)#输出完整的字典
        print(dictionary.keys())#输出所有的key
        print(dictionary.values())#输出所有的值
    • 不可变数据:Number数字,String字符串,Tuple元组

    • 可变数据:List列表,Dictionary字典,Set集合

Python3编程第一步

1
2
3
4
5
#Fibonacci series:
a,b=0,1
while b<10:
print(b)
a,b=b,a+b
end关键字

关键字end可以用来将结果输出到同一行,或者在输出的末尾添加不同的字符

1
2
3
4
5
6
#Fibonacci series:
a,b=0,1
while b<10:
print(b)
a,b=b,a+b
#1,1,2,3,5,8

Python3条件控制

1
2
3
4
5
6
7
8
9
condition=100
if condition:
print('表达式条件为true')
print(condition)
condition1=0
if condition1:
print('表达式条件为true')
print(condition1)
print('Hello,Python3')
1
2
3
4
5
6
7
8
9
10
11
12
13
age=int(input('请输入年龄:'))
print('')
if age<0:
print('你在逗我吧!')
elif age==1:
print('相当于14岁的人')
elif age==2:
print('相当于22岁的人')
elif age>2:
human=22+(age-2)*5
print('对应人的年龄:',human)
#退出提示
input('点击enter键退出')
1
2
3
4
5
6
7
8
9
10
11
num=int(input('输入一个数字:'))
if num%2==0:
if num%3==0:
print('输入的数字可以整除2和3')
else:
print('输入的数字可以整除2,但不能整除3')
else:
if num%3==0:
print('输入的数字可以整除3,但不能整除2')
else:
print('输入的数字不能整除2和3')

Python3循环语句

  • while循环

    1
    2
    3
    4
    5
    6
    7
    counter=1
    n=100
    sum=0
    while couter<=n:
    sum=sum+counter
    counter+=1
    print('1到%d之和为:%d'%(n,sum))
  • for循环

    使用range()函数,生成数列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for i in range(5):
    print(i)
    #0,1,2,3,4
    for i in range(5,9):
    print(i)
    #5,6,7,8
    for i in range(0,10,3):
    print(i)
    #0,3,6,9
  • pass语句

    pass是空语句,为了保持程序结构的完整性,不做任何事情,只是用作占位语句

    1
    2
    3
    4
    5
    6
    for letter in 'Python3':
    if letter=='o':
    pass
    print('执行pass块')
    print('当前字母:',letter)
    print('Hello,Python3')

Node.JS入门

发表于 2018-12-12 | 分类于 计算机
字数统计: 885 | 阅读时长 ≈ 3

NPM使用介绍

NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题。

  • 允许用户从NPM服务器下载别人编写的第三方包到本地使用
  • 允许用户从NPM服务器下载并安装别人编写好的命令程序到本地使用
  • 允许用户将自己编写的包或者命令行程序上传到NPM服务器供别人使用

npm升级命令

1
2
3
npm install npm -g
##使用淘宝镜像的命令
cnpm install npm -g

npm命令安装模块

1
2
3
4
5
6
npm install <Module Name>
#安装常用的web框架模块express:
npm install express
#安装好后,express包放在工程目录下的node_modules目录中,因为在
#代码中需要通过require('express')方式调用就好。无需指定包路径
var express=require('express');

使用package.json

package.json位于模块目录下,用于定义包的属性。

package.json属性说明

  • name:包名
  • versin:包的版本号
  • description:包的描述
  • homepage:包的官网url
  • author:包的作者姓名
  • contributors:包的其他贡献者姓名
  • dependencies:依赖包列表。如果依赖包没有安装,npm会自动将依赖包安装在node_module目录下
  • repository:包代码存放的地方的类型,可以是git,svn,git可在GitHub上
  • main:main字段制定了程序的主入口文件,require(‘module_name’)就会加载这个文件,这个字段的默认值是模块根目录下面的index.js
  • keywords:关键字

卸载模块

1
2
3
4
#卸载Node.js的web框架模块
npm uninstall express
#卸载后查看目录下的包是否存在
npm ls

更新模块

1
2
#使用命令更新模块
npm update express

搜索模块

1
2
#搜索模块
npm search express

使用淘宝NPM镜像

1
2
3
4
5
#国内直接使用npm的官方镜像非常慢,推荐使用淘宝NPM镜像
#淘宝NPM镜像是一个完整的npmjs.org镜像。
npm install -g cnpm --registry=https://registry.npm.taobao.org
#使用cnpm命令安装模块
cnpm install <module_name>

Node.js REPL交互式解释器

Node.js REPL(Read Eval Print Loop:交互式解释器):表示一个电脑的环境,类似Window系统的终端或者Linux shell,我们可以在终端中输入命令,并接受系统的响应

Node自带的交互式解释器可执行的任务:

  • 读取:读取用于输入,解析输入了JS数据结构并存储在内存中
  • 执行:执行输入的数据结构
  • 打印:输出结果
  • 循环:循环操作以上步骤直到用户两次按下ctrl-c退出

输入node命令启动Node终端

1
node
  • 表达式运算

    1
    node

    1544580173914

使用Ctrl+c两次,退出REPL终端

Node.js回调函数

Node.js异步编程的体现就是回调

异步编程依赖于回调实现。但是不能说使用了回调后程序就异步化

回调函数在完成任务后就会被调用,Node使用了大量的回调函数,Node所有的API都支持回调函数。

比如:我们可以一边读取文件,一边执行其他命令,文件读取完成后,将文件内容作为回调函数的参数返回,这样在执行代码就没有阻塞或者等待文件I/O操作。提高了Node.js性能,处理大量的并发请求。

  • 阻塞代码:

    1
    2
    3
    4
    var fs=require('fs');
    var data=fs.readFileSync('input.txt');
    console.log(data.toString());
    console.log("程序结束");
  • 非阻塞代码

    1
    2
    3
    4
    5
    6
    7
    var fs=require("fs");
    fs.readFile('input.txt',function(err,data){
    if(err)
    return console.error(err);
    console.log(data.toString());
    });
    console.log('程序结束');

about

发表于 2018-12-12 | 分类于 关于
字数统计: 78 | 阅读时长 ≈ 1

关于

欢迎来到我的博客,这是一个热衷于技术分享,涉及软件开发, 计算机基础,高等数学,数据库,人工智能等热门前沿技术的分享论坛。

email:1397743321@qq.com

微信公众号:Victor的分享论坛

博客园:https://www.cnblogs.com/drq1/

数据结构

发表于 2018-12-12 | 分类于 计算机
字数统计: 4k | 阅读时长 ≈ 17

线性表

线性表:顺序存储——顺序表

链式存储—-单链表,双链表,循环链表—指针实现

静态链表(借助数组实现)

线性表的基本操作:

  • InitList(&L)
  • Length(L)
  • LocateElem(L,e)
  • ListInsert(&L,i,e)
  • ListDelete(&L,i,&e)
  • PrintList(L)
  • DestroyList(&L)

注:&是C++中的引用,传入的变量是指针型的变量

函数体内要对传入的指针进行改变,将用到执行变量的引用

C中采用*,指针的效果也可以

顺序表的定义

地址连续的存储单元,依次存储线性表中的数据元素,逻辑上相邻的两个元素在物理位置上也相邻。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define MaxSize 50//定义线性表的最大长度
typedef struct Node{
ElemType data[MaxSize];//顺序表的元素
int length;// 顺序表当前长度
}SqList;//顺序表的类型定义
一位数组静态分配,动态分配。
静态分配:数组大小和空间已经固定,当空间占满,再加入元素,将产生溢出,导致程序崩溃
动态分配:存储数组的空间在程序执行过程中通过动态分配语句分配的。
一旦数据空间站满,可以另外开辟一块更大的存储空间,替换原来的存储空间。
从而达到扩充存储数组空间的目的
#define InitSize 100
typedef struct Node{
ElemType *data;
int MaxSize,length;
}SeqList;
C的动态分配:
L.dada=(ElemType*)malloc(sizeof(ElemType)*InitSize)
C++的动态分配:
L.data=new ElemType[InitSize];

注:顺序表的主要特点:随机访问,通过首地址和元素序号可以再O(1)的时间内

找到指定的元素。

顺序表的存储密度高,每个节点只存储数据元素

顺序比哦啊逻辑上相邻的元素物理上也是相邻。插入和删除需要移动大量元素

顺序表的基本操作 实现

  • 插入操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    bool ListInsert(SqList &L,int i,ElemType e){//本算法实现将元素e插入到顺序表L中第i个位置,注:第i个位置的元素,数组下标是i-1
    if(i<1||i>L.length+1)
    return false;
    if(L.length>=MaxSize)
    return false;
    for(int j=L.lenght;j>=i;j--)//将第i个元素以及后面的元素后移
    L.data[j]=L.data[j-1];
    L.data[i-1]=e;//在位置i处放入e
    L.length++;//线性表长度+1
    return true
    }
    //时间复杂度:O(n)
  • 删除操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    bool ListDelete(SqList &L,int i,ElemType &e){//将顺序表L中第i个位置的元素删除
    if(i<1||i>L.length)
    return false;
    e=L.data[i-1];//将被删除的元素赋值给e
    for(int j=i;j<L.length;j++)//将第i个位置之后的元素向前移动
    L.data[j-1]=L.data[j];
    L.length--;//线性表长度-1
    return true;
    }
    //时间复杂度:O(n)
  • 按值查找(顺序查找)

    1
    2
    3
    4
    5
    6
    7
    8
    int LocateElem(SqList L,ElemType e){
    //查找顺序表L中值为e的元素,返回元素的位置号,下标为i的元素,是第i+1个位置
    for(int i=0;i<L.length;i++)
    if(L.data[i]==e)
    return i+1;
    return 0;
    }
    //时间复杂度:O(1)

链表

顺序表的插入,删除需要移动大量元素,引入线性表的链式存储。不需要使用地址连续的存储单元

不要求逻辑上相邻的两个元素在物理位置上相邻。

单链表
1
2
3
4
typedef struct Node{//单链表的节点
ElemType data;//数据域
struct Node *next;//指针域
}LNode,*LinkList;

注:用头指针标识一个单链表,如果单链表L,L->next=NULL,表示为一个空表

头结点,头指针区别:

不管带不带头结点,头指针始终只想链表的第一个节点,头结点是一个带头结点链表的第一个节点

通常节点不存储信息。

  • 头插法建立单链表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    LinkList CreateList(LinkList &L){
    Node *s;
    int x;
    L=(LinkList)malloc(sizeof(Node));//创建头结点
    L->next=NULL;//头指针为空,初始化为空表
    scanf("%d",&x);//输入节点的值
    while(x!=9999){
    s=(Node*)malloc(sizeof(Node));
    s->data=x;
    s->next=L->next;//s放在L->next是下一个元素之前
    L->next=s;//头指针L->next指向s
    scanf("%d",&x)
    }
    return L;
    }
    //插入时间复杂度:O(1)
  • 尾插法建立单链表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    LinkList CreateList(LinkList &L){
    int x;
    L=(LinkList)malloc(sizeof(Node);
    Node *s,*r=L;
    scanf("%d",&x);
    while(x!=9999){
    s=(Node*)malloc(sizeof(Node));
    s->data=x;
    r->next=s;//尾指针r等于L,让r->next指向新插入的节点s
    r=s;//调整尾指针r指向s
    scanf("%d",&x);
    }
    r->next=NULL;
    return L;
    }
    //时间复杂度:O(n)
  • 按序号查找节点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Node *GetElem(LinkList L,int i){
    //取出单链表L中第i个位置的节点指针
    int flag=1;
    LNode *p=L->next;
    if(i==0)
    return L;
    if(i<1)
    return NULL;
    while(p&&i>flag){//从第i个节点开始找,查找第i个节点
    p=p->next;//import step循环。
    flag++;
    }
    return p;//返回第i个节点的指针,如果i大于表长,p=NULL
    }
    //时间复杂度:O(n)
  • 按照值来查找节点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Node *LocateElem(LinkList L,ElemType e){
    //查找单链表L,数据域值为e的节点指针,否则返回NULL
    Node *P=L->next;
    while(p!=NULL&&p->data!=e){
    p=p->next;//从第1个节点开始查找data域为e的节点
    }
    return p;
    }
    //时间复杂度:O(n)
  • 插入节点操作

    1
    2
    3
    p=GetElem(L,i-1);
    s->next=p->next;
    p->next=s;
  • 删除节点操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    p=GetElem(L,i-1);
    q=p->next;
    p->next=q->next;
    free(q);

    //method 2:
    p->data=p->next->data;
    p->next=p->next->next;
    free(p->next)

双链表

单链表的节点中只有一个指向后继的指针,单链表只能从头结点依次顺序的向后遍历

想访问某个节点的前驱节点,比如插入,删除,只能从头遍历。

双链表的节点:
1
2
3
4
typedef struct DNode{
ElemType data;//数据域
struct DNode *prior,*next;//前驱,后继指针
}DNode,*DLinkList;

关键在于保证在修改的过程不断链。双链表可以方便的找到前驱节点。插入、删除节点的时间复杂度仅为O(1)

  • 双链表的插入操作

    1
    2
    3
    4
    s->next=p->next;
    p->next->prior=s;
    s->prior=p;
    p->next=s;
  • 双链表的删除操作

    1
    2
    3
    p->next=q->next;
    q->next->prior=p;
    free(q);

循环链表

循环链表与单链表的区别:表中最后一个节点的指针不为NULL,改为指向头结点。

单链表中只能从表头节点开始往后顺序遍历整个链表,而循环单链表可以从表中的任一节点开始遍历整个链表。有时对单链表常做的操作是在表头和表尾进行的,此时可对循环单链表不设头指针而设尾指针。

静态链表

是借助数组来描述线性表的链式存储结构,节点也有数据域data和指针域next。

指针是数组的下标,也叫游标。

静态链表结构的定义:
1
2
3
4
5
#define MaxSize 50
typedf struct{
ElemType data;
int next;
}SLinkList[MaxSize];

栈Stack

栈的基本操作:

  • InitStack(&S):初始化一个空栈S

  • StackEmpty(S):判断一个栈是否为空,S为空返回true,否则false

  • Push(&S,x):进栈,如果栈S未满,将x加入让它成为新的栈顶

  • Pop(&S,&x):出栈,如果栈S非空,弹出栈顶元素,并用x返回

  • GetTop(S,&x):读取栈顶元素 ,如果栈S非空,用x返回栈顶元素

  • ClearStack(&S):销毁栈,并释放栈S占用的存储空间

    注:&是C++的特有,用来引用,采用C的写法是*,用来传达地址的目的

顺序栈:

  • 顺序栈的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #define MaxSize 50
    typedef struct{
    ElemType data[MaxSize];
    int top;
    }SqStack;
    栈顶指针:初始化为S.top=-1
    栈顶元素:S.data[S.top]
    进栈操作:S is not full,top++
    出栈操作:S is not empty,get top ,top--
    栈空条件:S.top==-1
    栈满条件:S.top==MaxSize-1
    栈长:S.top+1
  • 顺序栈的基本运算

    • 初始化

      1
      2
      3
      void InitStack(SqStack &S){
      S.top=-1;
      }
    • 判断栈空

      1
      2
      3
      4
      5
      6
      bool StackEmpty(SqStack S){
      if(S.top==-1)
      return true;
      else
      return false;
      }
    • 进栈

      1
      2
      3
      4
      5
      6
      bool Push(SqStack &S,ElemType x){
      if(S.top==MaxSize-1)
      return false;
      S.data[++S.top]=x;
      return true;
      }
    • 出栈

      1
      2
      3
      4
      5
      6
      boop Pop(SqStack &S,ElemType &x){
      if(S.top==-1)
      return false;
      x=S.data[S.top--];
      return true;
      }
    • 读取栈顶元素

      1
      2
      3
      4
      5
      6
      bool GetTop(SqStack S,ElemType &x){
      if(S.top==-1)
      return false;
      x=S.data[S.top--];
      return true;
      }

链式栈

  • 链栈的节点定义

    1
    2
    3
    4
    typedef struct LinkNode{
    ElemType data;
    struct LinkNode *next;
    }*ListStack;

队列Queue

队列的常见基本操作

  • InitQueue(&Q):初始化队列,构建一个空队列Q
  • QueueEmpty(Q):判断队列为空,Q为空返回true,否则false
  • EnQueue(&Q,x):入队,若队列Q未满,将x加入,成为新的队尾
  • DeQueue(&Q,&x):出队,若队列Q非空,将队头元素赋值给x
  • GetHead(Q,&x):读取队头元素,若队列Q非空,将队头元素赋值给x
顺序队列
  • 节点定义:

    1
    2
    3
    4
    5
    6
    7
    8
    #define MaxSize 50
    typedef struct{
    ElemType data[MaxSize];
    int front,rear;
    }SqQueue;
    队空条件:Q.front==Q.rear==0
    进队操作:Queue is not full,enqueue data,rear+1
    出队操作:Queue is not empty,dequeue data,front+1
  • 循环队列

    1
    2
    3
    4
    5
    6
    7
    初始化:Q.front==Q.rear=0
    队首指针rear:Q.rear=(Q.front+1)%MaxSize
    队尾指针front:Q.rear=(Q.rear+1)%MaxSize
    队列长度:(Q.rear+MaxSize-Q.front)%MaxSize
    队满条件:(Q.rear+1)%MaxSize==Q.front
    队空条件:Q.front==Q.rear
    队中元素个数:(Q.rear-Q.front+MaxSize)%MaxSize
  • 循环队列的操作

    • 初始化

      1
      2
      3
      void InitQueue(SqQueue &Q){
      Q.rear=Q.front=0;
      }
    • 判断队空

      1
      2
      3
      4
      5
      6
      bool isEmpty(SqQueue Q){
      if(Q.rear==Q.front)
      return true;
      else
      return false;
      }
    • 入队

      1
      2
      3
      4
      5
      6
      7
      bool EnQueue(SqQueue &Q,ElemType x){
      if((Q.rear+1)%MaxSize==Q.front)
      return false;
      Q.data[Q.rear]=x;
      Q.rear=(Q.rear+1)%MaxSize;
      return true;
      }
    • 出队

      1
      2
      3
      4
      5
      6
      7
      bool DeQueue(SqQueue &Q,ElemType &x){
      if(Q.rear==Q.front)
      return false;
      x=Q.data[Q.front];
      Q.front=(Q.front+1)%MaxSize;
      return true;
      }

链队

  • 链队节点定义:

    1
    2
    3
    4
    5
    6
    7
    typedef struct{
    ElemType data;
    struct LinkNode
    }LinkNode;
    typedef struct{
    LinkNode *front,*rear;
    }LinkQueue;
  • 链式队列的基本操作

    • 初始化

      1
      2
      3
      4
      void InitQueue(LinkQueue &Q){
      Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode));
      Q.front->next=NULL;
      }
    • 判断队空

      1
      2
      3
      4
      5
      6
      bool IsEmpty(LinkQueue Q){
      if(Q.front==Q.rear)
      return true;
      else
      return false;
      }
    • 入队

      1
      2
      3
      4
      5
      6
      7
      void EnQueue(LinkQueue &Q,ElemType x){
      s=(LinkNode*)malloc(sizeof(LinkNode));
      s->data=x;
      s->next=NULL;
      Q.rear->next=s;
      Q.rear=s;
      }
    • 出队

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      bool DeQueue(LinkQueue &Q,ElemType &x){
      if(Q.front==Q.rear)
      return false;
      p=Q.front->next;
      x=p->data;
      Q.front->next=p->next;
      if(Q.rear==p)
      Q.rear=Q.front;//原来队列中如果只有一个节点,删除后变为空
      free(p);
      return true;
      }

队列在计算机系统中的应用

队列在计算机系统中应用非常广泛:

  • 解决主机CPU与外部设备IO之间的速度不匹配问题

  • 解决由多用户引起的资源竞争问题

    主机与打印机之间速度不匹配的问题:主机输出数据给打印机打印,输出数据的速度比打印数据的速度要快很多。由于速度不匹配,如果直接把输出的数据送给打印机打印显然是不行的

    解决方法:设置一个打印数据的缓冲区,主机把要打印输出的数据依次写入到这个缓冲区。写满后就暂停输出,转去做其他事情。打印机就从缓冲区中按照先进先出的原则依次取出数据并打印。打印完后再向主机发出请求。

    CPU资源的竞争是一个典型的队列应用问题。在一个带有终端的计算机系统上,有多个用户需要CPU格子运行自己的程序,它们分别通过各自的终端向系统提出占用CPU的请求。操作系统通常按照每个用户请求在时间上的先后顺序,把它们排成一个队列。每次把CPU分配给队首的用户使用。当相应的程序运行结束后,或者用户用完规定的时间片后,让它出队,再把CPU分配给新的队首请求的用户使用。

括号匹配问题

算法思想:扫描每个字符,遇到花,中,圆左括号进栈,遇到花,中,圆有括号出栈

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
bool BracketsCheck(char *str){
InitStack(SqStack S);
int i=0;
while(str[i]!='\0'){
switch(str[i]){
//左括号入栈
case '(':Push(S,'(');break;
case '[':Push(S,'[');break;
case '{':Push(S,'{');break;
//遇到右括号,检测栈顶
case ')':Pop(S,e);
if(e!='(')return false;
break;
case ']':Pop(S,e);
if(e!='[')return false;
break;
case '}':Pop(S,e);
if(e!='{')return false;
break;
default:break;
}
i++;
}
if(!IsEmpty(S)){
printf("括号不匹配\n");
return false;
}
else{
printf("括号匹配\n");
return true;
}
}

树与二叉树

  • 二叉树链式存储节点:

    1
    2
    3
    4
    typedef struct BiTNode{
    ElemType data;
    struct BiTNode *lchild,*rchild;
    }BiTNode,*BiTree;
  • 二叉树的遍历

    • 先序遍历PreOrder

      1
      2
      3
      4
      5
      6
      7
      void PreOrder(BiTree T){
      if(T!=NULL){
      visit(T);
      PreOrder(T->lchild);
      PreOrder(T->rchild);
      }
      }
    • 中序遍历InOrder

      1
      2
      3
      4
      5
      6
      void InOrder(BiTree T){
      if(T!=NULL){}
      InOrder(T->lchild);
      visit(T);
      InOrder(T->rchild);
      }
    • 后序遍历PostOrder

      1
      2
      3
      4
      5
      6
      7
      void PostOrder(BiTree T){
      if(T!=NULL){
      PostOrder(T->lchild);
      PostOrder(T->rchild);
      visit(T);
      }
      }

      三种遍历方式的时间复杂度,空间复杂度都为O(n)

    • 层次遍历LevelOrder

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      void LevelOrder(BiTree T){
      //需要借助到队列Queue
      InitQueue(Q);
      BiTree p;
      EnQueue(Q,T);//根节点入队
      while(!IsEmpty(Q)){
      DeQueue(Q,p);//队列不空,队头元素出队
      visit(p);
      if(p->lchild!=NULL)
      EnQueue(Q,p->lchild);//左子树不空,左子树入队
      if(p->rchild!=NULL)
      EnQueue(Q,p->rchild);//右子树不空,右子树入队
      }
      }
    • 中序遍历非递归

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      void InOrder(BiTree T){//需要借助一个栈
      InitStack(S);//初始化栈S,
      BiTree p=T;//p是遍历指针
      while(p||!IsEmpty(S)){//栈不为空,p不空循环
      if(p){
      Push(S,p);//根指针进栈
      p=p->lchild;//遍历左子树
      }
      else{
      Pop(S,p);//根指针出栈
      visit(p);//访问根节点
      p=p->rchild//遍历右子树
      }
      }
      }
    • 后序遍历非递归

      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
      void PostOrder(BiTree T){
      InitStack(S);
      BiTree p=T;//p是遍历指针
      BiTree r=NULL;
      while(p||!IsEmpty(S)){
      if(p){//走到最左边
      push(S,p);
      p=p->lchild;
      }
      else{//向右
      GetTop(S,p);//获取栈顶节点
      if(p->rchild&&p->rchild!=r){//如果右子树存在,且未被访问
      p=p->rchild;//转向右子树
      push(S,p);//将右子树节点进栈
      p=p->lchild;//然后转向最左边
      }
      else{//没有右子树,弹出节点并访问
      pop(S,p);//将节点弹出
      visit(p->data);//访问节点
      r=p;//记录最近访问的节点
      p=NULL;//节点访问完后,重置p指针
      }
      }
      }
      }

二叉排序树BST

也叫二叉查找树,左<根<右

  • 二叉排序树的查找

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    BSTNode *BST_search(BiTree T,ElemType key,BSTNode *&p){
    p=NULL;
    while(T!=NULL&&key!=T->data){
    p=T;
    if(key<T->data)
    T=T->lchild;
    else
    T=T->rchild;
    }
    return T;
    }
  • 二叉排序树的插入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int BST_Insert(BiTree &T,int k){
    if(T==NULL){
    T=(BiTree)malloc(sizeof(BSTNode));
    T->key=k;
    T->lchild=T->rchild=NULL;
    return 1;//返回1,表示成功
    }
    else if(k==T->key)//树中存在相同的关键字节点,返回0
    return 0;
    else if(k<T->key)//递归,插入到T的左子树中
    return BST_Insert(T->lchild,k);
    else//递归,插入到T的右子树中
    return BST_Insert(T->rchild,k);
    }
  • 二叉排序树的构造

    1
    2
    3
    4
    5
    6
    7
    8
    void Create_BST(BiTree &T,char str[],int n){
    T=NULL;//初始化的时候T为空树
    int i=0;
    while(i<n){//依次将每个元素插入
    BST_Insert(T,str[i]);
    i++
    }
    }

平衡二叉树VAL

平衡二叉树的各个节点的平衡因子只能为-1,0,1

Hello ,Hexo

发表于 2018-12-12 | 分类于 关于
字数统计: 73 | 阅读时长 ≈ 1

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

1…67
Victor Drq

Victor Drq

70 日志
8 分类
1 标签
RSS
GitHub E-Mail 博客园
© 2018 Victor Drq | Site words total count: 62k
本站访客数:
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4