双更撒花~是不是很勤快!(我才不会说是因为我的大会员到期了才空出时间写代码了嘿嘿嘿)
7.1 ?的概念
树的特性:
1、一棵树中的任意两个结点有且仅有唯一的一条路径连通。
2、一棵树如果有n个结点,那么它一定恰好有n-1条边。
3、在一棵树中加一条边将会构成一条回路。
深度:根到该结点的层数(根是第一层)
7.2 二叉树?的概念
满二叉树:二叉树中每个内部结点都有两个儿子,即满二叉树的所有的叶结点都有同样的深度
完全二叉树:除了最后一排结点缺失若干个,前面符合满二叉树要求的树。
如果一个父结点编号为k,则它的左孩子编号为2k,右孩子编号为2k+1。如果孩子的编号为x,则它的父结点编号为x/2。
如果一个完全二叉树(不包括满二叉树)有N个结点,则它的高度为logN+1。
7.3 堆
7.3.1 向下调整
import java.util.Scanner;
class Test{
static int n;
static int[] heap=new int[100];
public void swap(int i,int j){
int tmp;
tmp=heap[i];
heap[i]=heap[j];
heap[j]=tmp;
}
public void shiftdown(int i){
int min;
int flag=0;
while(i*2<=n&&flag==0){
if(heap[i]>heap[2*i])
min=2*i;
else
min=i;
if(i*2+1<=n) {
if (heap[min] > heap[2 * i + 1])
min=2*i+1;
}
if(min!=i) {
swap(i, min);
i = min;
}
else
flag=1;
}
}
public static void main(String[] args){
Test t=new Test();
System.out.println("请输入结点数量");
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
System.out.println("请输入结点");
for(int i=1;i<=n;i++)
heap[i]=sc.nextInt();
for(int i=n/2;i>=1;i--)
t.shiftdown(i);
for(int i=1;i<=n;i++)
System.out.print(heap[i]+" ");
}
}
7.3.2 向上调整。它的复杂度为什么是O(n),小啾想了一种解释,不知道对不对,复杂度O<n/21+n/42+n/83+n/164…最后是一个k*n的形式,可推断其复杂度为n级。好像有点不严谨…看着玩儿好啦。
import java.util.Scanner;
class Test{
static int n;
static int[] heap=new int[100];
public void swap(int i,int j){
int tmp;
tmp=heap[i];
heap[i]=heap[j];
heap[j]=tmp;
}
public void shiftup(int i){
int flag=0;
if(i==1) return;
while(i!=1&&flag==0){
if(heap[i]<heap[i/2])
swap(i,i/2);
else flag=1;
i=i/2;
}
}
public static void main(String[] args){
Test t=new Test();
System.out.println("请输入结点数量");
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
System.out.println("请输入结点");
for(int i=1;i<=n;i++)
heap[i]=sc.nextInt();
for(int i=n;i>=1;i--)
t.shiftup(i);
for(int i=1;i<=n;i++)
System.out.print(heap[i]+" ");
}
}
7.3.3 堆排序-最小堆
import java.util.Scanner;
class Test{
static int n;
static int[] heap=new int[100];
public void swap(int i,int j){
int tmp;
tmp=heap[i];
heap[i]=heap[j];
heap[j]=tmp;
}
public void shiftdown(int i){
int min;
int flag=0;
while(i*2<=n&&flag==0){
if(heap[i]>heap[2*i])
min=2*i;
else
min=i;
if(i*2+1<=n) {
if (heap[min] > heap[2 * i + 1])
min=2*i+1;
}
if(min!=i) {
swap(i, min);
i = min;
}
else
flag=1;
}
}
public int deletetop(){
int tmp=heap[1];
heap[1]=heap[n];
n--;
shiftdown(1);
return tmp;
}
public static void main(String[] args){
Test t=new Test();
System.out.println("请输入结点数量");
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
System.out.println("请输入结点");
for(int i=1;i<=n;i++)
heap[i]=sc.nextInt();
for(int i=n/2;i>=1;i--)
t.shiftdown(i);
int total=n;
for(int i=1;i<=total;i++)
System.out.print(t.deletetop()+" ");
}
}
/*
99 5 36 7 22 17 46 12 2 19 25 28 1 92
*/
7.3.4 堆排序-最大堆
import java.util.Scanner;
class Test{
static int n;
static int[] heap=new int[100];
public void swap(int i,int j){
int tmp;
tmp=heap[i];
heap[i]=heap[j];
heap[j]=tmp;
}
public void shiftdown(int i){
int max;
int flag=0;
while(i*2<=n&&flag==0){
if(heap[i]<heap[2*i])
max=2*i;
else
max=i;
if(i*2+1<=n) {
if (heap[max] <heap[2 * i + 1])
max=2*i+1;
}
if(max!=i) {
swap(i, max);
i = max;
}
else
flag=1;
}
}
public int deletetop(){
int tmp=heap[1];
heap[1]=heap[n];
n--;
shiftdown(1);
return tmp;
}
void heapsort(){
while(n>1){
swap(1,n);
n--;
shiftdown(1);
}
}
public static void main(String[] args){
Test t=new Test();
System.out.println("请输入结点数量");
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
System.out.println("请输入结点");
for(int i=1;i<=n;i++)
heap[i]=sc.nextInt();
int total=n;
for(int i=n/2;i>=1;i--)
t.shiftdown(i);
t.heapsort();
for(int i=1;i<=total;i++)
System.out.print(heap[i]+" ");
}
}
/*
99 5 36 7 22 17 46 12 2 19 25 28 1 92
*/
一个是取最小堆顶部值输出再调换,轮次进行,一个是最大堆最大值调换到底部,然后底部减一,继续取当前最大值(除了最大值之外的n-1个数比较),再减一,依次进行,直到全部调换完成后再输出。
专注太难了,晚饭后就玩儿到现在,果然我只有午夜能静得下心来。
7.4 并查集
试了一下,只有令右结点的祖宗结点的父结点是左结点才行,如果只令右结点的祖宗结点是左结点的话,那么他原本的父结点就会脱节,这也是为什么sum输出为6。这是个坑哪~~
import java.util.Scanner;
class Test{
static int n;
static int[] f=new int[101];
public void init(){
for(int i=1;i<=n;i++)
f[i]=i;
}
public int getf(int x){
if(f[x]==x)
return x;
else {
f[x]=getf(f[x]);
return f[x];
}
}
public void merge(int x,int y){
int t1=getf(x);
int t2=getf(y);
if(t1!=t2){
f[getf(y)]=x;
}
}
public static void main(String[] args){
Test t=new Test();
int m;
System.out.println("请输入强盗和线索的数量");
Scanner sc=new Scanner(System.in);
n=sc.nextInt();//robbers
m=sc.nextInt();//clues
t.init();
System.out.println("请输入线索");
for(int i=1;i<=m;i++){
int r1=sc.nextInt();
int r2=sc.nextInt();
t.merge(r1,r2);
}
int sum=0;
for(int i=1;i<=n;i++){
if(t.getf(i)==i) {
sum++;
}
}
System.out.println(sum);
}
}
/*
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4
*/
第七章也就此结束啦,第八章是其他算法的扩展,应该不会很细了,我打算总结一下前面的345章再继续。
晚安~~