节省叶子结点空指针浪费的空间,来记录该结点按遍历顺序的前驱后继
只有中序遍历满足每隔一个结点会出现一个浪费空间的结点
结点由五个属性组成;{
lchild:取决于ltag
ltag:为0时,lchild指向该结点左孩子,为1时lchild指向该结点的前驱
data:该结点数据
rchild:取决于rtag
rtag:为0时,rchild指向该结点右孩子,为1时rchild指向该结点的后继
}
learn and share
节省叶子结点空指针浪费的空间,来记录该结点按遍历顺序的前驱后继
只有中序遍历满足每隔一个结点会出现一个浪费空间的结点
结点由五个属性组成;{
lchild:取决于ltag
ltag:为0时,lchild指向该结点左孩子,为1时lchild指向该结点的前驱
data:该结点数据
rchild:取决于rtag
rtag:为0时,rchild指向该结点右孩子,为1时rchild指向该结点的后继
}
插件所需js文件链接
用法:
1.在将要使用的控制器里配置好插件文件
2.在HTML里用data-clipboard-text绑定要复制的值,并用class或者id绑定复制动作所在的标签1
<a class="font-green-meadow clicopy" data-clipboard-text="{{x.scan_url}}" ><i class="fa fa-copy"></i> 复制扫描链接</a>
3.在控制器里面初始化复制插件对象,并写回调函数1
2
3
4
5
6
7
8
9
10
11
12
13//复制链接
$scope.copy = function(){
var clipboard = new Clipboard('.clicopy');
clipboard.on('success', function(e) {
toastr.success('复制成功!','成功');
e.clearSelection();
});
clipboard.on('error', function(e) {
toastr.error('复制失败!','失败');
});
}
$scope.copy();
所需文件
用法:
var hash = hex_md5($scope.password);
其实加密文件就是一个算法文件,加密算法也分好多种,所以不同算法加密加载不同的算法文件即可
nodejs的Crypto模块是一个加密模块,也可用于加密处理
相关链接
定义:是n(n>=0)个结点的有限集合,该集合或者为空集(空二叉树),或者由一个
根节点和两颗不互相交的、分别称为根的左子树和右子树的二叉树
特点:
-每个结点最多有两颗子树,不存在度大于2的结点
-左右子树有顺序,次序不能颠倒,即使只有一颗子树也要区分它是左子树还是右子树
空二叉树
只有一个根节点
根结点只有左子树
根结点只有右子树
根结点既有左子树又有右子树
1.斜树:只有左子树或只有右子树
2.满二叉树:该二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上
–特点:
1.叶子只能出现在最下一层
2.非叶子结点的度一定是2
3.在同样深度的二叉树中,满二叉树的节点个数一定最多,同时叶子也最多
3.完全二叉树:对一颗具有N个结点的二叉树按层序编号,如果编号为i(i<=i<=n)的结点与同样深度的满二叉树中编号为i的
结点位置完全相同,则这棵树称为完全二叉树
–特点:
1.叶子结点只能出现在最下两层
2.最下层的叶子一定集中在左部连续位置
3、倒数第二层,若有叶子结点,一定都在右部连续位置
4.如果结点度为1,则该结点只有左孩子
5.同样结点数的二叉树,完全二叉树的深度最小
满二叉树一定是完全二叉树,但完全二叉树不一定是满二叉树
用数组存储,按层序遍历对比满二叉树顺序,没有结点的位置数组在该位置填空
每个结点包含一个数据域和两个指针域,两个指针分别指向该结点左右孩子结点1
2
3
4
5typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode,8BiTree;
从根结点出发,按照某种次序访问二叉树中所有结点,使每个结点被访问一次且仅被访问一次
1.前序遍历:根左右
若二叉树为空,则空操作返回;否则先访问根结点,然后前序遍历左子树,再前序遍历右子树
a.先访问根结点,然后访问根结点的左孩子
b.将根结点的左孩子视作子树根结点,继续访问其左孩子,再以这个左孩子结点为根再访问其左孩子直到叶结点
c.访问完该叶结点后,再访问该叶结点双亲的右孩子,
d.如果没有右孩子,则该子树访问完毕,继续访问该结点双亲的双亲的右孩子,再以该右孩子为根继续从步骤a开始访问
核心:从整棵树的根结点开始,每次将左孩子看成子树根结点,从上到下,从左到右
ABDHIEJCFKG
2.中序遍历 :左根右
若二叉树为空,则空操作返回;否则从根节点根结点开始(并不是先访问根结点),然后中序遍历左子树,然后访问根结点,再中序遍历右子树
核心:无论什么级别的子树树都从最左端叶结点开始,按左孩子,双亲,右孩子顺序遍历,从下到上,从左到右
HDIBEJAFKCG
3.后序遍历 :左右根
若二叉树为空,则空操作返回;否则从左到右先叶子结点的方式遍历左右子树,最后访问根结点
核心:从最左端叶结点开始,按左孩子,右孩子,双亲顺序遍历,从左到右,从下到上
HIDJEBKFGCA
4.层序遍历
若二叉树为空,则空操作返回;否则从根节点开始,按层依次往下,每层从左到右依次遍历
性质一:在二叉树的第i层上至多有2^(i-1)个结点(i>=1)
性质二:深度为K的二叉树至多有2^K-1个结点(K>=1)
性质三:对于任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1
性质四:具有n个结点的完全二叉树的深度为log2n取下限加1
性质五:如果对一颗有n个结点的完全二叉树(其深度为log2n取下限加1)的结点按层序编号对任一结点i(1<=i<=n)有以下性质
如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点i/2取下限
如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i
如果2i+1>n,则结点i无右孩子(结点i为叶子结点);否则其右孩子是结点2i+1
计算:
输出指定结点在该树中所在的层数
[未完成]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
35var str="AB DEC #";//约定前序遍历输入
var btree = {
data:'',
lchild:{},
rchild:{}
};
console.log(btree);
function creatbtree(num,item){
console.log(str[num])
if(str[num]=="#");
{
return
}
if(str[num] == " "){
item = null;
}else{
item.data = str[num];
num+=1;
item.lchild ={
data:'',
lchild:{},
rchild:{}
}
creatbtree(num,item.lchild);
num+=1;
item.rchild ={
data:'',
lchild:{},
rchild:{}
}
creatbtree(num,item.rchild);
}
}
creatbtree(0,btree);
console.log(btree.rchild)
定义:n(n>=0)个结点的有限集。当n=0时称为空树,在任意一颗非空树中:
——有且仅有一个特定的结点称为根
——当n>1时,其余结点可分为m(m>0)个互不相交]的有限集T1、T2…Tm,其中每一个集合本身又是一颗树,并且称为根的子树
结点:图中每一个圆圈称为树的一个结点
结点的度:结点拥有的子树数称为该结点的度
树的度:树内各结点度的最大值
叶结点/终端结点:度为0的结点
分支结点/非终端结点:度不为0的结点
内部结点:分支结点中除根节点以外的结点
结点的孩子:D是B的孩子
孩子的双亲:B是D的双亲
兄弟:D和E互称为兄弟
结点的祖先:从根到该结点所经过分支上的所有结点
结点的层次:从根开始定在一起,根为第一层,根的孩子为第二层
树的深度/高度:树中结点的最大层次,图中树的深度为3
有序树:如果将树中结点的各子树看成从左至右是有次序的不能互换的,则称该树为有序树,否则称为无序树
森林:m(m>=0)棵互不相交的树的集合。对树中每个结点而言,其子树的集合即为森林
以下遍历采用层序遍历
每个结点由该结点数据和该结点双亲的下标组成,根结点双亲下标赋值为-1
下标 | data | parent |
---|---|---|
0 | A | -1 |
1 | B | 0 |
2 | C | 0 |
3 | D | 0 |
4 | E | 1 |
5 | F | 3 |
6 | G | 3 |
7 | K | 6 |
8 | H | 4 |
9 | I | 4 |
10 | J | 4 |
每个结点由该结点数据和该结点双亲的下标、该结点孩子的下标组成,根结点双亲下标赋值为-1
无孩子则孩子属性赋值-1
下标 | data | parent | children |
---|---|---|---|
0 | A | -1 | 1,2,3 |
1 | B | 0 | 4 |
2 | C | 0 | -1 |
3 | D | 0 | 5,6 |
4 | E | 1 | 8,9,10 |
5 | F | 3 | -1 |
6 | G | 3 | -1 |
7 | K | 6 | -1 |
8 | H | 4 | -1 |
9 | I | 4 | -1 |
10 | J | 4 | -1 |
每个结点由该结点数据和该结点双亲的下标、该结点兄弟的下标组成,根结点双亲下标赋值为-1
无兄弟则兄弟属性赋值-1
下标 | data | parent | rightsib |
---|---|---|---|
0 | A | -1 | -1 |
1 | B | 0 | 2 |
2 | C | 0 | 3 |
3 | D | 0 | -1 |
4 | E | 1 | 5 |
5 | F | 3 | 6 |
6 | G | 3 | -1 |
7 | K | 6 | -1 |
8 | H | 4 | 9 |
9 | I | 4 | 10 |
10 | J | 4 | -1 |
所有结点组成一个数组,每个结点包含该结点数据属性,该结点双亲属性(由双亲结点下标表示)以及第一个孩子结点的下标
每一个孩子结点包含下一个孩子结点的下标,用js数组实现相当于兄弟表示法
下标 | data | parent | nextchildren |
---|---|---|---|
0 | A | -1 | -1 |
1 | B | 0 | 2 |
2 | C | 0 | 3 |
3 | D | 0 | -1 |
4 | E | 1 | 5 |
5 | F | 3 | 6 |
6 | G | 3 | -1 |
7 | K | 6 | -1 |
8 | H | 4 | 9 |
9 | I | 4 | 10 |
10 | J | 4 | -1 |
1 | # define MAX_TREE_SIZE 100 |
js实现: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
32var tree=[];
for(var i =0;i<11;i++){
var prior = -1;
var next = [];
if(i==0){
prior =-1;
}else if(i>0&&i<4){
prior = 0;
}else if(i==4){
prior = 1;
}else if(i==5 || i==6){
prior = 3;
}else if(i>6 && i<10){
prior = 4;
}else{
prior = 6;
}
tree.push({
data:i,
parent:prior,
});
}
for(var i =0;i<11;i++){
var children=[];
for(var j =0;j<11;j++){
if(tree[j].parent == i){
children.push(j);
}
}
tree[i].children = children.slice();
}
console.log(tree);
定义:串是由0个或多个字符组成的有限序列,又名字符串
1.空串:没有字符,直接由””表示
2.主串与子串:”hello”是”helloworld”的子串,”helloworld”是”hello”主串
3.字符串比较:比较字符串里每个字符的ASCII码大小,没有意义,一般看是否相等
4.存储结构
顺序存储:用一组地址连续的存储单元来存储串中的字符序列,
按照预定义大小,为每个定义的字符串变量分配一个固定长度的存储区,一般用定长数组来定义
链式存储:不常用
5.BF算法:
有两个字符串S和T,长度为N和M,首先S[1]和T[1]比较,若相等,则再比较S[2]和T[2],一直到T[M-1]为止;
若S[1]和T[1]不等,则T向右移动一个字符的位置,再依次进行比较
6.字符串模式匹配:依据BF算法,S是主串,T是子串这种定位操作即字符串模式匹配
1 | var string1="hellohannahworld"; |
1.选择仓库存放位置,新建文件夹,用作本地仓库
2.打开Git bash,cd 切换路径到该文件夹
3.执行以下命令1
2
3
4
5echo "该项目简短说明" >> README.md ##输入“该项目简短说明”内容到README.md文件
git init
git add README.md ##将提交的文件(README.md)的信息添加到索引库
git commit -m "第一次提交" ##依据索引库中的内容来进行文件的提交
##同时提交更改描述“第一次提交”
以上步骤完成本地仓库建立和将文件提交到本地仓库的工作
1.登录github账号,点击右上角“+”,选择“New repository”
2.填写仓库名称,简单描述
3.为避免与本地仓库READMD.md冲突,初始化时不勾选“Initialize this repository with a README”
4.点击“Create repository”,生成远程仓库
1.点击“Clone or download”, 复制远程仓库地址
2.执行以下代码1
2git remote add origin 远程仓库地址 ##将本地仓库推送到远成仓库
git push -u origin master ##将本地仓库推送到远程分支
以上步骤即完成本地仓库同步到远程仓库
执行git remote时,
若出现提示出错信息:fatal: remote origin already exists.
则先输入1
git remote rm origin ##删除远程仓库
再执行推送语句 “git remote add origin 远程仓库地址”
若对本地仓库进行了修改
git add <文件名> 只是添加一个文件
git add . 可添加全部仓库文件
若执行“git add .”时,总出现警告:warning: LF will be replaced by CRLF in XXXXXXXXXXXXXX.
可执行语句 “git config core.autocrlf false”
添加完文件后执行提交操作
git commit -m “”
最后推送到远程仓库
git push -u origin master
循环队列的容量是固定的,并且它的对头和队尾指针都可以随着元素出入队列而发生改变,
这样循环队列逻辑上就好像是一个环形存储空间,但在实际内存中,是不可能有真正的环形存储区的,
我们只是用顺序表模拟逻辑上的循环
因此,为防止发生假溢出,当我们采用循环队列时,front和rear不断加1,即使超出了地址范围,
也会自动从头开始,判断溢出,可采用取模处理
(rear+1)%QueueSize
(front+1)%QueueSize
取模即取余数,取得的值永远不会大于除数
1
2
3
4
5
6# define MAXSIZE 100
typedef struct{
ElemType *base; ##存放内存分配基地址,也可以用数组存放
int front;
int rear;
}
1 | initQueue(cyclQueue *q){ |
1 | insertQueue(cyclQueue *q,ElemType e){ |
1 | DeleteQueue(cyclQueue *q,ElemType e){ |
1.把有一个直接调用自己或通过一系列的调用语句间接的调用用自己的函数,称作递归函数
2.每个递归函数必须有一个终止调用的条件语句,否则陷入永不结束的无穷递归
迭代实现1
2
3
4
5
6
7
8
9var a=[];
a[0] = 1;
a[1] = 1;
for(var i =2;i<40;i++){
a[i]=a[i-1]+a[i-2];
}
for(var j=0;j<40;j++){
console.log(j,a[j]);
}
递归实现1
2
3
4
5
6
7
8
9function fib(n){
if(n<2){
return 1;
}
if(n>1 && n<40){
return fib(n-1)+fib(n-2);
}
}
console.log(fib(4));
1 | function fib(n){ |
1 | function hanoita(n,x,y,z){ |
1 | var string = "hello#"; |
1.迭代使用循环结构,递归使用选择结构
2.递归能使程序结构更清晰、简洁、容易让人理解,从而减少读懂代码的时间
3.大量的递归会建立函数的副本,会消耗大量时间和内存,而迭代不需要
4.递归函数分为调用和回退阶段,递归的回退顺序是它调用顺序的逆序
经推导发现,进行模式匹配时,子串的移位规律与主串内容无关,与子串的内容有关,
因此根据子串的内容,生成基于子串的next数组,用来存放在对应位置如果发生失配,
应该将子串的哪个位置移动到失配位置
1.失配位置的前缀:永远是子串第一位
2.失配位置的后缀:失配位置的前一位
3.失配位置的前后缀相同位数:
从第一位开始的n位和从后缀开始倒数的n位相同,但前缀连续长度最长不能包含后缀那一位,
后缀也不能包含前缀,重叠也没关系,就说失配位置的前缀和后缀有n位相同
例:
ababc
若在倒数第二位的b位置(位置4)失配,则位置4的前缀是位置1的a,后缀是位置3的a,
从位置1和位置3开始,二者只有一位相同,则前后缀有1为相同,
若在最后一位位置5失配,前缀a虽然和后缀b不相同,但前缀连续两位ab和后缀连续两位ab相同
则c的前后缀有两位相同
ssssb
若在b位置失配,前缀连续sss,后缀连续sss,虽然重叠位置2和位置3的s,但前后缀相同位数为3
4.next数组值
失配位置的next数组值 = 失配位置的前后缀相同位数 + 1
特殊情况:子串位置1的next数组值为0,位置2的next数组值为1
例:
T: | a | b | a | b | a | a | a | b | a |
---|---|---|---|---|---|---|---|---|---|
下标: | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
next: | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 | 3 |
next数组获取代码实现
i后缀 | 1 | 2 | 。 | 3 | 4 | 5 | 6 | 7 | 。 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|---|
j前缀 | 0 | 1 | 0 | 1 | 2 | 3 | 4 | 2 | 1 | 2 | 3 |
1 | var string = "9ababaaaba"; //第一位存放字符串长度 |
1.先进先出的线性表,有顺序表和链表
2.只允许在一段插入,另一端删除
和栈相反,队列常用链表实现1
2
3
4
5
6
7
8typedef sruct QNode{
ElemType data;
struct QNode *next;
}QNode,*QueuePrt;
typedef struct {
QueuePrt front; ##队头指针指向链队列的头结点(头结点不是必要的)
QueuePrt rear; ##队尾指针指向终端结点,空队列时,front,rear都指向头结点
}LinkQueue;
1
2
3
4
5
6
7
8
9
10
11InsertQueue(LinkQueue *q,ElemType e){
QueuePrt p;
p = (QueuePtr)malloc(sizeof(QNode));
if(p==NULL){
exit(0);
}
p->data = e;
p->next = NULL;
q->rear->next = p;
q->rear = p;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14DeleteQueue(LinkQueue *q,ElemType e){
QueuePrt p;
if(q->front ==q->rear)
{
retrun;
}
p=q->front->next;
*e=p->data;
q->front->next = p->next;
if(q->rear ==p){
q->rear = q->front;
}
free(p);
}
由于链队列建立在内存的动态区,因此当一个队列
不在有用时,应当及时销毁掉,以免过多占用内存空间1
2
3
4
5
6
7DestroyQueue(LinkQueue *q){
while(q->front){
q->rear = q->front->next;
free(q->front):
q->front = q->rear;
}
}
简单实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var list = [];
for(var i=0;i<5;i++){
list.push({
next:i+1
})
}
list[4].next = null;
console.log(list);
//入队列
var length = list.length;
list.push({
next:null
})
list[length-1].next=length;
console.log(list);
//出队列
list.splice(0,1);
console.log(list);
//清空
list=[];