数据结构知识点总结
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法 insert:对 search 函数进行适当改变(设置 parent 节点保存搜素的节点的父节点)
算法 remove
void remove(node* root ,int key) { //如果待删除节点的左右孩子都在,用它的前驱节点替 代他;否则直接删掉它就行
if (root != NULL) { if (key < root->data) remove(x, root->lchild); else if (key > root->data) remove(x, root->rchild); else if (root->lchild&&root->rchild) { node* temp = root->lchild; if (!temp->rchild) { root->data = temp->data; delete temp; } else { while (temp->rchild->rchild) temp =
(2*n-j-1)*j/2+i (i>j)
第三章 字符串 模式匹配 bf 算法:O(m*n) kmp 算法:O(m+n)
void GetNext(char* p,int m,int next[]) {
int pLen = m; next[0] = -1; int k = -1; int j = 0; while (j < pLen - 1) {
//p[k]表示前缀,p[j]表示后缀 if (k == -1 || (p[j] == p[k]&&p[j+1]!=p[k+1])) { ++k; ++j; next[j] = k; } else k = next[k];
} }
int KMP(char * p, int m, char * t, int n ) {
尾递归:直接转化为循环(eg:n!)、 线性递归(非重点)
proc(int n) { Stms1(n); if (Eval(n)) { proc(n-1); //递归调用 Stms2(n); } else Stms3(n);
}
proc(int n) { int k=n+1; do { k--; Stms1(k); } while Eval(k); Stms3(k); while (k<n){ stms2(k); k++: }
//从下到上构造堆
堆的 insert(利用 shift_up):把元素加到数组最后,然后对这个元素进行 shift_up; 堆的 remove(利用 shift_down):把第一个元素和最后一个元素互换位置,然 后进行 shift_down;
二叉树的计数(前序、中序可唯一地确定一棵二叉树 \根节点左、右两边各有 多少节点,递归计算):1/(1+n)*C (n||2n);
堆的向下调整
void shift_down(node a[],int n,int i) { //堆的向下调整 n:a 的大小;i:需要调整的(子)
堆
int j;
while ((j = 2 * i + 1) < n) {
node k = a[i];
if (j < n - 1 && a[j]<a[j+1] ) j++; //两个子元素里较大的一个
双亲表示法(数组):存储双亲
树的遍历
深度优先
先根:对应二叉树(左孩、右兄表示法) 的前序 后根:对应二叉树(左孩、右兄表示法) 的中序(遍 历完我的孩子(左节点),遍历我的兄弟(右节点))
广度优先(层次序、queue)
二叉树
概念: 满二叉树、完全二叉树(注意区分)
性质:
n 个节点、n-1 条边; 第 i 层最多有 2^i 个节点; 深度为 k(k+1 层)的二叉树最少有 k+1 个节点,最多有 2^(k+1)-1 个节
}
堆的 construct(利用 shift_down)
void heap_construct(node a[],int n) { int pos = (n - 1) / 2; while (pos >= 0) { shift_down(a, n, pos); pos--; }
}
//构造堆 //确保能找到最后一个分支节点
第五章 递归->非递归
递归-->非递归:
栈 :hanoi 塔:
void towers(int n, int A, int B, int C) {
stack s; int done=FALSE; while (!done) {
while (n>1) { s _ tack(n, A, B, C, &s); setvar1(&n, &A, &B, &C); } printf(“\n %d -> %d\n”, A, C); if (!empty(&s)) { restore(&n, &A, &B, &C, &s); printf(“\n %d -> %d\n”, A, C); setvar2(&n, &A, &B, &C); } else done=TRUE; } }
construct:设置 pre 指针(初始化为 NULL)指向之前访问的那个节点,然 后: 线索化左子树(更新 pre)-->改变当前节点左、右指针-->线索化右子树;
insert:分为左插入、右插入(判断节点是否有左、右子女,然后插入)
remove:
堆 定义(最大堆):完全二叉树+ a[i]≥a[2i+1]+ a[i]≥a[2i+2] ps:如果要求手工构造的话,直接排序就行了
遍历: 深度优先遍历: 前、中、后的递归遍历 前、中、后的非递归遍历 中序的非递归:
void LDR(node* root){ stack<node*>s; node* x=root; while(x){ s.push(x); x=x->lchild; } while(!s.empty()){ x=s.top(); s.pop(); cout<<x->data; if(x->rchile) x=x->rchild; while(x){ s.push(x); x=x->lchild; } }
}
广义表:表头:第一个元素;表尾:其余的所有元素
广义表的递归算法:它的后继、子表都是广义表 求深度:数括号数
第六章 树
概念: 树的次数(度):节点的子树的最大个数 m 次完全树:节点的度数不是 m 就是 0 层次:根节点层次为 0 深度\高度
存储结构:
子女链表表示:
等量子女节点数(eg:二叉树、三叉树) 左孩子、右兄弟:firstchild、nextsibling
while(x){ s.push(x); x=x->lchild;
} } else{
cout<<x->data; s.pop(); } } return; }
广度优先遍历(层次序遍历):queue
(中序)线索化二叉树:(中序的第一个节点和最后一个节点的子树为 NULL, 其他都有值) prior、next 函数;
霍夫曼树 概念:外部路径长度 EPL、内部路径长度 IPL、最优二叉树; 霍夫曼编码(无前缀编码):左 0 右 1;
第七章 查找
顺序搜索(无序表、链表):设置监视哨
等概率情况下:ASLsuccess=(n+1)/2;ASLunsuccess=n+1
有序表:折半搜索法
折半搜索判定树的高度:向上 log2(n+1)取整-1; ps:注意搜索长度的计算与点所在的高度有关 ASLsuccess=log2(n+1)-1
二叉查找树(二叉排序树:中序遍历)
ps:左边的都比我小、右边的都比我大; 左右子树也都是二叉查找树
不同形态的总数:1/(n+1)*C(2n|| n);
算法 search:迭代\递归进行
while(nod!=NULL && nod->!=key){ }
if(nod==NULL) return NULL; else return nod;
题型:计算某一棵(手工构造的)给定的二叉搜索树中某一个节点的搜索长度\ 所有节点的平均搜索长度;
AVL 树
定义:左树和右树的高度差不超过 1 ps:高度为:O(log2n),平均搜索长度为 log2n; 平衡因子:“右高”-“左高”(-1、0、1) 平衡化旋转: 每插入一个节点,从这个节点回溯,如果遇到节点不平衡,往回看三个节点
}
后序的非递归
void LRD(node* root){ stack<node*>s; node* x=root; while(x){ s.push(x); x=x->lchild; } while(!s.empty()){ x=s.top(); if(x->sign){ //sign 标记是否遍历过 x 的 lchild 了 x->sign=0; x=x->rchild;
if (k < a[j]) {
a[i] = a[j];
ቤተ መጻሕፍቲ ባይዱ
a[j] = k;
//给 root 的元素找一个合适的位置
i = j;
}
else break;
} }
堆的向上调整
void shift_yup(node a[], int n, int i) { int k = (i - 1) / 2; while (k >= 0) { if (a[i] > a[k]) { int temp = a[i]; a[i] = a[k]; a[k] = temp; i = k; k = (i - 1) / 2; } else break; } return;
int i, j, Next[SIZE]; //预处理
Getnext ( p, m, Next); //查找 for (i=j = 0; j<n;){
for(;i>-1 && p[i]!= t[j]; ) i=Next[i]; i++; j++; if (i>= m ) return j-i;
} return -1; }
temp->rchild;
root->data = temp->data; delete temp->rchild; } } else { temp = root; if (root->lchild==NULL) root = ptr->rchild; else root = root->lchild; delete temp; } }
(三)对角矩阵: 性质:3n-2 个元素 a[i][j]=&a[0][0]+( 2*i+j)*s=&a[0][0]+(3*i+(j-i))*s
对称矩阵(只存上(下)三角): 下三角: ( i+1)* i/2+j(i>=j)
j *(j+1)/2+i (i<j) 上三角: (2*n-i-1)*i/2+j (i<=j)
第一章 复杂度分析 时间复杂度 :
大 o 表示法:c<log2 n<n<n*log2 n<n^2<n^3<n!<n^n 加法原理:Omax(f(n),g(n),h(n)……)\乘法原理: Omax(f(n )*g(n)) 空间复杂度:
第二章 数组存储 数组:( s:一个元素的大小、t:某个维度的长度) 1 维: &a[i]=a[0]+i*s 2 维: a[i][j]= & a[0][0]+( i * t2 +j)* s\ & a[0][0]+(j * t 1 + i)* s(列优先) 3 维: a[x][y][z]=&a[0][0][0]+(x*t2*t3+y*t3+z)*s n 维:&a[0][0]···[0]+Σij*cj (cj:j 后的维的长度的累乘) ps: 在首地址不是(00……)时,用减法求元素之间的空隙,“减后”+1 求维 的长度
点; 如果叶节点数有 n0,则度为 2 的节点数为 n2,则有 n0=n2+1 个; 有 n 个节点的完全二叉树,高度:向上 log2(n+1)取整-1;
i>0,i 的双亲:向下(i-1)取整/2;若 2*i+1<n,i 的左子女:2*i+1;若 2*i+2<n,i 的右子女:2*i+1;i 为偶数,i 的左兄弟:i-1;i 为奇数,i 的 右兄弟:i+1;i 所在的层次为:向下 log2(i+1)取整+1
第四章 堆 栈 队列 //火车进站问题 循环队列: 队头指针出 1:front=(front+1)%maxSize 队尾指针进 1:rear=(rear+1)%maxSize 队列初始化:front=rear=0 队空条件:front==rear 队满条件:(rear+1)%maxSize==front
算法 remove
void remove(node* root ,int key) { //如果待删除节点的左右孩子都在,用它的前驱节点替 代他;否则直接删掉它就行
if (root != NULL) { if (key < root->data) remove(x, root->lchild); else if (key > root->data) remove(x, root->rchild); else if (root->lchild&&root->rchild) { node* temp = root->lchild; if (!temp->rchild) { root->data = temp->data; delete temp; } else { while (temp->rchild->rchild) temp =
(2*n-j-1)*j/2+i (i>j)
第三章 字符串 模式匹配 bf 算法:O(m*n) kmp 算法:O(m+n)
void GetNext(char* p,int m,int next[]) {
int pLen = m; next[0] = -1; int k = -1; int j = 0; while (j < pLen - 1) {
//p[k]表示前缀,p[j]表示后缀 if (k == -1 || (p[j] == p[k]&&p[j+1]!=p[k+1])) { ++k; ++j; next[j] = k; } else k = next[k];
} }
int KMP(char * p, int m, char * t, int n ) {
尾递归:直接转化为循环(eg:n!)、 线性递归(非重点)
proc(int n) { Stms1(n); if (Eval(n)) { proc(n-1); //递归调用 Stms2(n); } else Stms3(n);
}
proc(int n) { int k=n+1; do { k--; Stms1(k); } while Eval(k); Stms3(k); while (k<n){ stms2(k); k++: }
//从下到上构造堆
堆的 insert(利用 shift_up):把元素加到数组最后,然后对这个元素进行 shift_up; 堆的 remove(利用 shift_down):把第一个元素和最后一个元素互换位置,然 后进行 shift_down;
二叉树的计数(前序、中序可唯一地确定一棵二叉树 \根节点左、右两边各有 多少节点,递归计算):1/(1+n)*C (n||2n);
堆的向下调整
void shift_down(node a[],int n,int i) { //堆的向下调整 n:a 的大小;i:需要调整的(子)
堆
int j;
while ((j = 2 * i + 1) < n) {
node k = a[i];
if (j < n - 1 && a[j]<a[j+1] ) j++; //两个子元素里较大的一个
双亲表示法(数组):存储双亲
树的遍历
深度优先
先根:对应二叉树(左孩、右兄表示法) 的前序 后根:对应二叉树(左孩、右兄表示法) 的中序(遍 历完我的孩子(左节点),遍历我的兄弟(右节点))
广度优先(层次序、queue)
二叉树
概念: 满二叉树、完全二叉树(注意区分)
性质:
n 个节点、n-1 条边; 第 i 层最多有 2^i 个节点; 深度为 k(k+1 层)的二叉树最少有 k+1 个节点,最多有 2^(k+1)-1 个节
}
堆的 construct(利用 shift_down)
void heap_construct(node a[],int n) { int pos = (n - 1) / 2; while (pos >= 0) { shift_down(a, n, pos); pos--; }
}
//构造堆 //确保能找到最后一个分支节点
第五章 递归->非递归
递归-->非递归:
栈 :hanoi 塔:
void towers(int n, int A, int B, int C) {
stack s; int done=FALSE; while (!done) {
while (n>1) { s _ tack(n, A, B, C, &s); setvar1(&n, &A, &B, &C); } printf(“\n %d -> %d\n”, A, C); if (!empty(&s)) { restore(&n, &A, &B, &C, &s); printf(“\n %d -> %d\n”, A, C); setvar2(&n, &A, &B, &C); } else done=TRUE; } }
construct:设置 pre 指针(初始化为 NULL)指向之前访问的那个节点,然 后: 线索化左子树(更新 pre)-->改变当前节点左、右指针-->线索化右子树;
insert:分为左插入、右插入(判断节点是否有左、右子女,然后插入)
remove:
堆 定义(最大堆):完全二叉树+ a[i]≥a[2i+1]+ a[i]≥a[2i+2] ps:如果要求手工构造的话,直接排序就行了
遍历: 深度优先遍历: 前、中、后的递归遍历 前、中、后的非递归遍历 中序的非递归:
void LDR(node* root){ stack<node*>s; node* x=root; while(x){ s.push(x); x=x->lchild; } while(!s.empty()){ x=s.top(); s.pop(); cout<<x->data; if(x->rchile) x=x->rchild; while(x){ s.push(x); x=x->lchild; } }
}
广义表:表头:第一个元素;表尾:其余的所有元素
广义表的递归算法:它的后继、子表都是广义表 求深度:数括号数
第六章 树
概念: 树的次数(度):节点的子树的最大个数 m 次完全树:节点的度数不是 m 就是 0 层次:根节点层次为 0 深度\高度
存储结构:
子女链表表示:
等量子女节点数(eg:二叉树、三叉树) 左孩子、右兄弟:firstchild、nextsibling
while(x){ s.push(x); x=x->lchild;
} } else{
cout<<x->data; s.pop(); } } return; }
广度优先遍历(层次序遍历):queue
(中序)线索化二叉树:(中序的第一个节点和最后一个节点的子树为 NULL, 其他都有值) prior、next 函数;
霍夫曼树 概念:外部路径长度 EPL、内部路径长度 IPL、最优二叉树; 霍夫曼编码(无前缀编码):左 0 右 1;
第七章 查找
顺序搜索(无序表、链表):设置监视哨
等概率情况下:ASLsuccess=(n+1)/2;ASLunsuccess=n+1
有序表:折半搜索法
折半搜索判定树的高度:向上 log2(n+1)取整-1; ps:注意搜索长度的计算与点所在的高度有关 ASLsuccess=log2(n+1)-1
二叉查找树(二叉排序树:中序遍历)
ps:左边的都比我小、右边的都比我大; 左右子树也都是二叉查找树
不同形态的总数:1/(n+1)*C(2n|| n);
算法 search:迭代\递归进行
while(nod!=NULL && nod->!=key){ }
if(nod==NULL) return NULL; else return nod;
题型:计算某一棵(手工构造的)给定的二叉搜索树中某一个节点的搜索长度\ 所有节点的平均搜索长度;
AVL 树
定义:左树和右树的高度差不超过 1 ps:高度为:O(log2n),平均搜索长度为 log2n; 平衡因子:“右高”-“左高”(-1、0、1) 平衡化旋转: 每插入一个节点,从这个节点回溯,如果遇到节点不平衡,往回看三个节点
}
后序的非递归
void LRD(node* root){ stack<node*>s; node* x=root; while(x){ s.push(x); x=x->lchild; } while(!s.empty()){ x=s.top(); if(x->sign){ //sign 标记是否遍历过 x 的 lchild 了 x->sign=0; x=x->rchild;
if (k < a[j]) {
a[i] = a[j];
ቤተ መጻሕፍቲ ባይዱ
a[j] = k;
//给 root 的元素找一个合适的位置
i = j;
}
else break;
} }
堆的向上调整
void shift_yup(node a[], int n, int i) { int k = (i - 1) / 2; while (k >= 0) { if (a[i] > a[k]) { int temp = a[i]; a[i] = a[k]; a[k] = temp; i = k; k = (i - 1) / 2; } else break; } return;
int i, j, Next[SIZE]; //预处理
Getnext ( p, m, Next); //查找 for (i=j = 0; j<n;){
for(;i>-1 && p[i]!= t[j]; ) i=Next[i]; i++; j++; if (i>= m ) return j-i;
} return -1; }
temp->rchild;
root->data = temp->data; delete temp->rchild; } } else { temp = root; if (root->lchild==NULL) root = ptr->rchild; else root = root->lchild; delete temp; } }
(三)对角矩阵: 性质:3n-2 个元素 a[i][j]=&a[0][0]+( 2*i+j)*s=&a[0][0]+(3*i+(j-i))*s
对称矩阵(只存上(下)三角): 下三角: ( i+1)* i/2+j(i>=j)
j *(j+1)/2+i (i<j) 上三角: (2*n-i-1)*i/2+j (i<=j)
第一章 复杂度分析 时间复杂度 :
大 o 表示法:c<log2 n<n<n*log2 n<n^2<n^3<n!<n^n 加法原理:Omax(f(n),g(n),h(n)……)\乘法原理: Omax(f(n )*g(n)) 空间复杂度:
第二章 数组存储 数组:( s:一个元素的大小、t:某个维度的长度) 1 维: &a[i]=a[0]+i*s 2 维: a[i][j]= & a[0][0]+( i * t2 +j)* s\ & a[0][0]+(j * t 1 + i)* s(列优先) 3 维: a[x][y][z]=&a[0][0][0]+(x*t2*t3+y*t3+z)*s n 维:&a[0][0]···[0]+Σij*cj (cj:j 后的维的长度的累乘) ps: 在首地址不是(00……)时,用减法求元素之间的空隙,“减后”+1 求维 的长度
点; 如果叶节点数有 n0,则度为 2 的节点数为 n2,则有 n0=n2+1 个; 有 n 个节点的完全二叉树,高度:向上 log2(n+1)取整-1;
i>0,i 的双亲:向下(i-1)取整/2;若 2*i+1<n,i 的左子女:2*i+1;若 2*i+2<n,i 的右子女:2*i+1;i 为偶数,i 的左兄弟:i-1;i 为奇数,i 的 右兄弟:i+1;i 所在的层次为:向下 log2(i+1)取整+1
第四章 堆 栈 队列 //火车进站问题 循环队列: 队头指针出 1:front=(front+1)%maxSize 队尾指针进 1:rear=(rear+1)%maxSize 队列初始化:front=rear=0 队空条件:front==rear 队满条件:(rear+1)%maxSize==front