赞
踩
数据结构(大头6)+算法(小头3)
题目分布于57-65
对于 在循环和递归以外的代码,都看成常数阶O(1)
时间复杂度T(n)和问题规模n有关(循环次数和递归的次数)
非递归形式
问题规模和执行次数的关系
- O(1)代码里面没有循环、递归
- O(log2n)
循环的判断是比循环多一次
总计算步骤为:
转换为大O表示法为:- O(n)
循环的判断是比循环多一次
总运算次数为:
大O表示法为:
4. O(nlog2n)
分析思路是拆分来分析
看成线性阶套对数阶
对于最内层的循环次数:嵌套用乘法
总循环次数是:
加法看高阶,所以答案是线性对数阶O(nlog2n)
总结:嵌套循环只需关注最内层的循环的循环体时间复杂度(就代表了整个算法的时间复杂度)
5. O(n^2)
再次说明:嵌套循环只需关注最内层的循环的循环体时间复杂度(就代表了整个算法的时间复杂度)
O(n^3)
总结:计算时间复杂度只需要看最内层的循环的循环体时间复杂度
例子
非递归方式
问题规模和存储空间的关系
例子如下
A
A
代码实现如下
package dataStructure.one; //2011年下半年64 public class a { public static void main(String[] args) { int [] A = {-1,0,1,-1,0,1}; int n = A.length; int n1 = 0;//统计-1的数目 int n2 = 0;//统计0的数目 int n3 = 0;//统计1的数目 //开始统计-1,0,1的数目 for(int i=0;i<n;i++){ if(A[i]==-1){ n1++; } if(A[i]==0){ n2++; } if(A[i]==1){ n3++; } } //将数组按照统计的-1,0,1数目来赋值(下标从0开始所以全部按照逻辑图的值减1) for(int i=0;i<n1;i++){ A[i]=-1; } for(int j=n1;j<n1+n2;j++){ A[j]=0; } for(int k=n1+n2;k<n;k++){ A[k]=1; } //输出看看 for (int a:A){ System.out.println(a); } } }
时间复杂度是O(n)
空间复杂度是O(1)
开辟的存储空间n1,n2,n3和问题规模之间没有关系
(上面俩个是题目条件,我们看空间复杂度看的是n1,n2,n3)
C
代码实现如下(我写代码的时候,交换A[i]和A[j]没有在条件if(i<j)下,所以错了)
package dataStructure.one; public class b { public static void main(String[] args) { int [] A = {-1,-3,3,1,-2,2}; int n = A.length; int i = 0; int j = n-1; //i向右移动,j向左移动,直到俩个重合,就完成了。 while (i<j){ while (A[i]<0){ i = i+1; } while (A[j]>0){ j = j-1; } //到这一步的时候,i指向的是正数,j指向的是负数,就交换他们的位置 if(i<j){ int temp; temp = A[i]; A[i] = A[j]; A[j] = temp; } //然后就开始下一轮的交换。。。 } for (int a:A){ System.out.println(a); } } }
时间复杂度就是遍历了长度为n的数组O(n)
空间复杂度就是定了了俩个变量O(1)
D
渐进分析就是时间复杂度分析
例子
解题方法:
- 将10n2+4n+2估算,化为:n2
- 对于(1),O(n2)>=n2,成立; 对于(2),O(n3)>=n2,成立;对于(3),O(n)>=n2,不成立
- 对于(4),Ω(n2)<=n2,成立;对于(5),Ω(n3)<=n2,不成立; 对于(6),Ω(n)<=n2,成立
对于(7)成立
对于(8),(9)不能同时满足俩个,所以不成立。
C
递归:自己调用自己。。
例如,求n的阶乘。
package dataStructure.one; //求n的阶乘 public class c { public static int func(int n){ if(n==1){ return 1; } return n*func(n-1); } public static void main(String[] args) { int result = func(5); System.out.println(result); } }
递归的时间复杂度:递归调用的次数x每次递归的时间复杂度
递归调用的空间复杂度:递归调用的次数x每次递归的空间复杂度
例如:
例子
时间复杂度:O(log2n)
空间复杂度:O(log2n)
先求递归调用的出口,也就是一共递归调用多少次
也就是:
求出x,就是递归调用的总次数
由于本来在一次递归中,时间复杂度和空间复杂度都是O(1),所以总的时间或空间复杂度都是O(log2n)
例子
分析时间复杂度:
递归调用n次,但每次递归执行的循环次数不一样
总循环次数有等差数列求和公式得到:
只保留最高阶的项,时间复杂度为O(n2)
时间复杂度为:O(n2)
分析空间复杂度
空间复杂度为O(n),因为每次递归,开辟的存储空间的空间复杂度相同,所以可以用之前的公式:
O(n)xO(1) = O(n)
例子
分析空间复杂度:
每次递归的空间复杂度都不一样。。
把所有的空间复杂度加起来:
所有,空间复杂度为:O(n2)
题目多考察定理1和定理2
例子
考察(1)和(2)
就是先算出logba的值,看套公式(1)还是(2)。
如果得到
就套用(1)求时间复杂度
如果得到(渐进紧致界括号内的阶要和f括号内的阶完全一样才行)这是之前渐进符号的定义
就套用(2)求时间复杂度
B
自己调用自己:递归式
递归调用n次
并且每次递归的执行次数还不一样
直接求出所有的执行次数(n+1)n/2,时间复杂度为o(n2)
A
A
A
C,C
对于第二问:直接n=16,则T(n)=O(n2)就是256
D.C
线性表
就是用数组实现顺序存储的物理结构(线性表是逻辑结构)
等概率下插入元素,需要移动元素个数的数学期望:
表长n是数组中当前元素个数是n
等概率下删除元素,需要移动元素个数的数学期望:
package dataStructure.SequenceList; public class SequenceList { final int N = 10; //最大容量 int[] a; int n; //当前表长 void init(){ a = new int[N]; for (int i = 0;i<N/2;i++){ a[i] = i+1; } n = N/2; for (int i =0;i<n;i++){ System.out.print(a[i]+" "); } System.out.println(); } public static void main(String[] args) { SequenceList list = new SequenceList(); list.init(); } }
package dataStructure.SequenceList; public class SequenceList { final int N = 10; //最大容量 int[] a; int n; //当前表长 void init(){ a = new int[N]; for (int i = 0;i<N/2;i++){ a[i] = i+1; } n = N/2; for (int i =0;i<n;i++){ System.out.print(a[i]+" "); } System.out.println(); } /* * k是实际的位置 从1开始到n (n+1是最后的一个插入位置) * */ void insert(int k,int x){ if(k<1||k>n+1) return; for(int i =n;i>=k;i--){ a[i] = a[i-1]; } a[k-1] = x; n++; } void show(){ for (int i=0;i<n;i++){ System.out.print(a[i]+" "); } System.out.println(); } public static void main(String[] args) { SequenceList list = new SequenceList(); list.init(); list.insert(3,100); list.insert(0,11); list.show(); } }
分析时间复杂度
package dataStructure.SequenceList; public class SequenceList { final int N = 10; //最大容量 int[] a; int n; //当前表长 void init(){ a = new int[N]; for (int i = 0;i<N/2;i++){ a[i] = i+1; } n = N/2; for (int i =0;i<n;i++){ System.out.print(a[i]+" "); } System.out.println(); } /* * k是实际的位置 从1开始到n (n+1是最后的一个插入位置) * */ void insert(int k,int x){ if(k<1||k>n+1) return; for(int i =n;i>=k;i--){ a[i] = a[i-1]; } a[k-1] = x; n++; } /* * n也是实际的位置 * */ void delete(int k){ if(k<1||k>n) return; //后面的元素向前移动 for(int i = k;i<n;i++){ a[i-1] = a[i]; } n--; } void show(){ for (int i=0;i<n;i++){ System.out.print(a[i]+" "); } System.out.println(); } public static void main(String[] args) { SequenceList list = new SequenceList(); list.init(); list.insert(3,100); list.insert(0,11); list.show(); list.delete(1); list.show(); list.delete(6); list.show(); } }
分析时间复杂度
package dataStructure.SequenceList; public class SequenceList { final int N = 10; //最大容量 int[] a; int n; //当前表长 void init(){ a = new int[N]; for (int i = 0;i<N/2;i++){ a[i] = i+1; } n = N/2; for (int i =0;i<n;i++){ System.out.print(a[i]+" "); } System.out.println(); } /* * k是实际的位置 从1开始到n (n+1是最后的一个插入位置) * */ void insert(int k,int x){ if(k<1||k>n+1) return; for(int i =n;i>=k;i--){ a[i] = a[i-1]; } a[k-1] = x; n++; } /* * n也是实际的位置 * */ void delete(int k){ if(k<1||k>n) return; //后面的元素向前移动 for(int i = k;i<n;i++){ a[i-1] = a[i]; } n--; } int getElements(int k){ if(k<1||k>n){ return -1; } return a[k-1]; } void show(){ for (int i=0;i<n;i++){ System.out.print(a[i]+" "); } System.out.println(); } public static void main(String[] args) { SequenceList list = new SequenceList(); list.init(); list.insert(3,100); list.insert(0,11); list.show(); list.delete(1); list.show(); list.delete(6); list.show(); System.out.println(list.getElements(1)); } }
package dataStructure.LinkList; class Node{ int data; Node next; Node(int data){ this.data = data; } } public class LinkList { Node list; //头指针 void init(){ Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); list = n1; //头指针指向头节点 n1.next = n2; n2.next = n3; } void printList(){ Node p = list; //头指针 while (p!=null){ System.out.println(p.data+" "); p = p.next; } System.out.println(); } public static void main(String[] args) { LinkList ll = new LinkList(); ll.init(); ll.printList(); } }
相比带头节点的插入,增加k=1的情况处理(因为k=1,按照之前的判断逻辑就找不到k之前的节点了,不能完成k位置的前面插入)
package dataStructure.LinkList; //不带头节点 class Node{ int data; Node next; Node(int data){ this.data = data; } } public class LinkList { Node list; //头指针 void init(){ Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); list = n1; //头指针指向头节点 n1.next = n2; n2.next = n3; } boolean insertOld(int k ,Node node){ if(k<1) return false; //第一个元素 int i = 1; Node p =list; while (i<k-1&&p!=null){ i++; p = p.next; } if(p==null) return false; node.next = p.next; p.next = node; return true; } boolean insert(int k ,Node node){ if(k<1) return false; if(k==1){ node.next = list; list = node; return true; } //第一个元素 int i = 1; Node p =list; while (i<k-1&&p!=null){ i++; p = p.next; } if(p==null) return false; node.next = p.next; p.next = node; return true; } void printList(){ Node p = list; //头指针 while (p!=null){ System.out.println(p.data+" "); p = p.next; } System.out.println(); } public static void main(String[] args) { LinkList ll = new LinkList(); ll.init(); ll.printList(); //之前插入 ll.insertOld(4,new Node(4)); ll.printList(); //之前插入 ll.insertOld(2,new Node(22)); ll.printList(); //如果是第一个位置,无法找到1前面的位置,会导致在后面插入了。。 ll.insertOld(1,new Node(11)); ll.printList(); //1的前面插入 ll.insert(1,new Node(111)); ll.printList(); } }
优化一下代码逻辑,用变量存储表长。。
时间复杂度
package dataStructure.LinkList; //不带头节点 class Node{ int data; Node next; Node(int data){ this.data = data; } } public class LinkList { Node list; //头指针 void init(){ Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); list = n1; //头指针指向头节点 n1.next = n2; n2.next = n3; } boolean insertOld(int k ,Node node){ if(k<1) return false; //第一个元素 int i = 1; Node p =list; while (i<k-1&&p!=null){ i++; p = p.next; } if(p==null) return false; node.next = p.next; p.next = node; return true; } boolean insert(int k ,Node node){ if(k<1) return false; if(k==1){ node.next = list; list = node; return true; } //第一个元素 int i = 1; Node p =list; while (i<k-1&&p!=null){ i++; p = p.next; } if(p==null) return false; node.next = p.next; p.next = node; return true; } //k也是实际位置 boolean delete(int k){ if(k<1) return false; //删除第一个节点 if(k==1){ list = list.next; return true; } int i = 1; Node p = list;//指向第一个节点 //先找待插入节点之前的节点 while (i<k-1&&p!=null){ i++; p = p.next; } p.next= p.next.next; return true; } void printList(){ Node p = list; //头指针 while (p!=null){ System.out.print(p.data+" "); p = p.next; } System.out.println(); } public static void main(String[] args) { LinkList ll = new LinkList(); ll.init(); ll.printList(); //之前插入 ll.insertOld(4,new Node(4)); ll.printList(); //之前插入 ll.insertOld(2,new Node(22)); ll.printList(); //如果是第一个位置,无法找到1前面的位置,会导致在后面插入了。。 ll.insertOld(1,new Node(11)); ll.printList(); //1的前面插入 ll.insert(1,new Node(111)); ll.printList(); System.out.println("删除第2个节点"); ll.delete(2); ll.printList(); System.out.println("删除第1个节点"); ll.delete(1); ll.printList(); } }
时间复杂度
package dataStructure.LinkList; //不带头节点 class Node{ int data; Node next; Node(int data){ this.data = data; } } public class LinkList { Node list; //头指针 void init(){ Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); list = n1; //头指针指向头节点 n1.next = n2; n2.next = n3; } boolean insertOld(int k ,Node node){ if(k<1) return false; //第一个元素 int i = 1; Node p =list; while (i<k-1&&p!=null){ i++; p = p.next; } if(p==null) return false; node.next = p.next; p.next = node; return true; } boolean insert(int k ,Node node){ if(k<1) return false; if(k==1){ node.next = list; list = node; return true; } //第一个元素 int i = 1; Node p =list; while (i<k-1&&p!=null){ i++; p = p.next; } if(p==null) return false; node.next = p.next; p.next = node; return true; } //k也是实际位置 boolean delete(int k){ if(k<1) return false; //删除第一个节点 if(k==1){ list = list.next; return true; } int i = 1; Node p = list;//指向第一个节点 //先找待插入节点之前的节点 while (i<k-1&&p!=null){ i++; p = p.next; } p.next= p.next.next; return true; } Node getNode(int k ){ if(k<1) return null; int i =1; Node p = list; while (i<k&&p!=null){ i++; p = p.next; } return p; } void printList(){ Node p = list; //头指针 while (p!=null){ System.out.print(p.data+" "); p = p.next; } System.out.println(); } public static void main(String[] args) { LinkList ll = new LinkList(); ll.init(); ll.printList(); //之前插入 ll.insertOld(4,new Node(4)); ll.printList(); //之前插入 ll.insertOld(2,new Node(22)); ll.printList(); //如果是第一个位置,无法找到1前面的位置,会导致在后面插入了。。 ll.insertOld(1,new Node(11)); ll.printList(); //1的前面插入 ll.insert(1,new Node(111)); ll.printList(); System.out.println("删除第2个节点"); ll.delete(2); ll.printList(); System.out.println("删除第1个节点"); ll.delete(1); ll.printList(); System.out.println(ll.getNode(1).data); } }
package dataStructure.LinkList2; import dataStructure.LinkList.LinkList; //带头节点 class Node{ int data; Node next; Node(){ System.out.println("调用了空构造"); } Node(int data){ this.data = data; } } public class LinkList2 { Node head;//头节点 void init(){ head = new Node(); head.next=null; Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); head.next = n1; n1.next = n2; n2.next = n3; } void printList(){ Node p = head.next;//p是指向第一个元素的指针(头节点的下一个元素) while (p!=null){ System.out.print(p.data+" "); p = p.next; } System.out.println(" "); } public static void main(String[] args) { LinkList2 ll =new LinkList2(); ll.init(); ll.printList(); } }
插入代码如下:
额外引入 i(下标)
package dataStructure.LinkList2; import dataStructure.LinkList.LinkList; //带头节点 class Node{ int data; Node next; Node(){ System.out.println("调用了空构造"); } Node(int data){ this.data = data; } } public class LinkList2 { Node head;//头节点 void init(){ head = new Node(); head.next=null; } void printList(){ Node p = head.next;//p是指向第一个元素的指针(头节点的下一个元素) while (p!=null){ System.out.print(p.data+" "); p = p.next; } System.out.println(" "); } //k也是实际位置 boolean insert(int k, Node node) { if (k<1) return false; int i =0; Node p = head;//初始化最开始的位置 //将p指针移动到待插入的位置 while (i<k-1&&p!=null){ i++; p = p.next; } if (p==null) return false; node.next = p.next; p.next = node; return true; } public static void main(String[] args) { LinkList2 ll =new LinkList2(); ll.init(); //开始插入节点 Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); ll.insert(1,n1); ll.insert(2,n2); ll.insert(3,n3); ll.printList(); } }
在位置K之后插入:
public static void main(String[] args) { LinkList2 ll =new LinkList2(); ll.init(); //开始插入节点 Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); Node n4 = new Node(22); ll.insert(1,n1); ll.insert(2,n2); ll.insert(3,n3); //在2位置之后插入 ll.insert(2+1,n4); ll.printList(); }
优化一下判断逻辑,在头节点里面存储单链表表长
时间复杂度
先找第k-1个节点。。
指向后继的后继
package dataStructure.LinkList2; import dataStructure.LinkList.LinkList; //带头节点 class Node{ int data; Node next; Node(){ System.out.println("调用了空构造"); } Node(int data){ this.data = data; } } public class LinkList2 { Node head;//头节点 void init(){ head = new Node(); head.next=null; } void printList(){ Node p = head.next;//p是指向第一个元素的指针(头节点的下一个元素) while (p!=null){ System.out.print(p.data+" "); p = p.next; } System.out.println(" "); } //k也是实际位置 boolean insert(int k, Node node) { if (k<1) return false; int i =0; Node p = head;//初始化最开始的位置 //将p指针移动到待插入的位置 while (i<k-1&&p!=null){ i++; p = p.next; } if (p==null) return false; node.next = p.next; p.next = node; return true; } //k也是实际位置 boolean delete(int k){ if(k<1) return false; int i = 0; Node p = head;//指向头节点 //先找待插入节点之前的节点 while (i<k-1&&p!=null){ i++; p = p.next; } p.next = p.next.next; return true; } public static void main(String[] args) { LinkList2 ll =new LinkList2(); ll.init(); //开始插入节点 Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); Node n4 = new Node(22); ll.insert(1,n1); ll.insert(2,n2); ll.insert(3,n3); //在2位置之后插入 ll.insert(2+1,n4); ll.printList(); System.out.println("删除第二个位置元素"); ll.delete(2); ll.printList(); System.out.println("删除第1个位置元素"); ll.delete(1); ll.printList(); } }
时间复杂度
package dataStructure.LinkList2; import dataStructure.LinkList.LinkList; //带头节点 class Node{ int data; Node next; Node(){ System.out.println("调用了空构造"); } Node(int data){ this.data = data; } } public class LinkList2 { Node head;//头节点 void init(){ head = new Node(); head.next=null; } void printList(){ Node p = head.next;//p是指向第一个元素的指针(头节点的下一个元素) while (p!=null){ System.out.print(p.data+" "); p = p.next; } System.out.println(" "); } //k也是实际位置 boolean insert(int k, Node node) { if (k<1) return false; int i =0; Node p = head;//初始化最开始的位置 //将p指针移动到待插入的位置 while (i<k-1&&p!=null){ i++; p = p.next; } if (p==null) return false; node.next = p.next; p.next = node; return true; } //k也是实际位置 boolean delete(int k){ if(k<1) return false; int i = 0; Node p = head;//指向头节点 //先找待插入节点之前的节点 while (i<k-1&&p!=null){ i++; p = p.next; } p.next = p.next.next; return true; } Node getNode(int k ){ if(k<1) return null; int i =0; Node p = head; while (i<k&&p!=null){ i++; p = p.next; } return p; } public static void main(String[] args) { LinkList2 ll =new LinkList2(); ll.init(); //开始插入节点 Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); Node n4 = new Node(22); ll.insert(1,n1); ll.insert(2,n2); ll.insert(3,n3); //在2位置之后插入 ll.insert(2+1,n4); ll.printList(); System.out.println("删除第二个位置元素"); ll.delete(2); ll.printList(); System.out.println("删除第1个位置元素"); ll.delete(1); ll.printList(); System.out.println(ll.getNode(1).data); } }
尾插
最后尾指针后移
先找第k-1个节点,然后执行插入操作。
注意非空判断
删除(中间节点)
d
对于a
c
插入操作:(尾节点之后插入)
然后把尾节点加入进来
最后尾节点后移
删除操作:(删除尾节点,需要寻找尾节点之前的节点)
核心代码:
a
a
a
a
b
a
链式存储不用移动
a
top是指向栈顶的下一个位置。。
完成入栈操作。。
注意判空条件
完成出栈操作。。
a
b
d
带入一些例子,一个一个去试一试就行。。。
a
a
a
入栈
出栈
栈只有打印所有元素的时候需要变量链表。。。
c
d
栈顶指针一直是指向栈顶元素的下一个元素。。
栈2不插入任何元素,栈1插入4个元素后,栈满。
栈2一直插入元素,栈1不插入任何元素。
也符合
判断队列为空:
插入:
出队(删除)
读取队头元素
取模运算
同样他,对头出队也是需要取模运算。
判空就得用size计数了。。
入队
出队(返回出队的节点)
对于只有一个元素的出队。。(需要移动队尾指针了)
结合起来出队的完整代码就是:
获取对头元素
d
d
b
d
d
在对于B.D进一步的去验证。。
a
a
b
队列的出对序列就是他的入队序列;同时也是栈的出栈序列。
D
对于B,插入
B删除
都是O1
对于D
2栈可以模拟队列,反之不行。。
d
c
b
b
c
c
d
计算公式来源:
返回起始位置
进一步匹配
匹配成功
加上限制条件
完整代码如下:
时间复杂度
平均的时间复杂度:
前缀:
后缀:
计算不同位置的next值:
再一个例子:
b
b
(之间有那个KMP前后缀的方法套就行。。)
a
b
带首地址的计算第i个元素的地址:
不带首地址的计算第i个元素的地址:
行优先存储:
下标从0开始
下标从1开始:
列优先存储:
下标从0开始:
下标从1开始:
总结
当i==j的时候,按行存储和按列存储的偏移量是一样的。
c
b
b
对称矩阵压缩为一维数组:
存储的元素个数:
下标从0开始,i>=j(下三角)
下标从0开始,j>=i(上三角)
交换i和J就行
总结
当下标从1开始:
按行存储
总结
三元组表
十字链表
a
也可代入一个数字去运算。。
a
a
带入一个值计算一下
c
d
b
注意:i小于j,是上三角
b
树的度:树中节点度的最大值。
第一个例子
第二个例子
带入每一层节点的数量,再等比求和。
例子:
例子:
例子2:
需要上取整。最小高度为3
b
c
叶子节点的度为0
一共两种节点:度为0的节点和度为k的节点
关于二叉树性质4:
b
带入具体的数值来计算(注意区分下取整符号和上取整的符号)
对于B的一个不成立的例子
d
d
d
c
C
如果有5个节点:
d
最高 1024
最低(完全二叉)
带入公式
或者用性质2求出区间
数组来存储
完全二叉树利用率高,非完全二叉树利用率低
空指针的数量:
对于n个节点的二叉链表,一共有:
个空指针
对于三叉链表来说:
n个节点的三叉链表的空指针域为:
为n+2个空指针域
a
d
b
三叉链表中,指针的数量是当前图片中的线段数乘以2
指针为10个
6个节点,每个节点的指针为3,一共为18个指针
空指针为18-10=8个空指针
或者直接用公式:n+2
c
d
一个小小的汇总:
中序是必不可少的
1:
2:
3:
4:
5:
6:
1:
2:
3:
4:
5:
6:
1:
2:
3:
4:
5:
6:
7:
c
b
a
d
方法一:通过根节点的位置来判断
我的方法:
7开始,所以必然是右开头
然后根节点在中间
就是:右根左
b
1:
2:
3:
4:
5:
6:
b
c
对于a节点
对于C节点
对于B节点
因此,此二叉树为平衡二叉树:
同时也是完全二叉树
完全二叉树是平衡二叉树
平衡二叉树不一定是完全二叉树,例子如下:
中序遍历二叉排序树就是有序序列
关键字序列的第一个元素为根节点:
1:
2:
3:
4:
5:
6:
7:
8:
9:
c
c
找5
c
d对了
b
路径长度:
节点的带权路径长度:
树的带权路径长度:
哈夫曼树:
其中,b为哈夫曼树
1:
2:
3:
4:
5:
6:
树的带权路径长度为:
权值大的节点距离根节点进,权值小的节点距离根节点远
叶子节点是存在的节点,分支节点是构造出来的节点
根据之前的公式:
0:
1:
2:
3:
4:
结束:
一个例子:
两个例子:
等长编码:
编码方法如下:
左分支标0,右分支标1
编码为:
译码过程为:
一个例子如下:
压缩比:
等长编码-哈夫曼编码/等长编码
b
c
c
b
等长编码:
哈夫曼编码:
压缩比:
d(之前的性质里面讲了)
b
a
ac
a
等长编码为:
哈夫曼编码为:
压缩比为:
d
哈夫曼树的节点的度为0或者2(不存在只有一个子树的节点)
a
a
c的直接前驱是b
c的直接后继是a
节点没有左右孩子就直接向直接前驱和后继
节点d:
d有右孩子,指向e,值为0
d没有左孩子,指向直接前驱a,值为1
线索二叉树就是普通二叉树的基础上,改变了一下存储结构
a
完全二叉树一定是平衡二叉树
c
最优二叉树只有度为0和度为1的节点
b
度:无向图
出度和入度:有向图
对于无向图来说:
度 为 边的数量乘以2
有向图同理:
最多和最少边的问题:
多的情况参照完全图
d
b
关于无向图:
邻接表适合存储稀疏图
邻接矩阵适合存储稠密图
c
c
a
a
b
关键是回溯操作,,
2.
4. (v5没有后续的节点了,回溯到v2)
6.(v4的后续节点也都被访问过了,继续回溯到v2)
7.(v2都后续节点也都被访问过了。继续回溯到v1)
8.
9.(v3的后续节点都被访问过了,回溯到v1)
结束遍历
递归调用的存储结构图如下:
对于有向图:
采用递归的思想求解的
对于无向图:
队列来实现的
2.
3.
4.
5.
6.
深度优先遍历和广度优先遍历的时间复杂度相同,只是和存储结构相关
c
a
a
b
a
强连通图:1是有向图 2任意两个节点之间存在路径
d
b
aov网:有向无环图
a
c
c
a
b
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。