数据结构学习第十五天

11:36:53 2019-08-30

学习

带权路径长度(WPL) (Weighted Path Length of Tree),设二叉树有n个叶子节点,每个叶子节点带有权值${w_k}$,从根节点到每个叶子节点的长度为${l_k}$,则每个叶子节点的带权路径长度之和就是:${WPL}=\displaystyle \sum_{k=1}^n{w_k}{l_k}$

最优二叉树或哈夫曼树:WPL最小的二叉树

哈夫曼树的构造:每次把权值最小的两课二叉树合并

利用最小堆 实现哈夫曼树:

  1 #include<stdio.h>
  2 #include<malloc.h>
  3 
  4 typedef struct TreeNode* HuffmanTree;
  5 struct TreeNode
  6 {
  7     int Weight;    //权重
  8     HuffmanTree Right, Left;
  9 };
 10 typedef struct HeapStruct* MinHeap;
 11 struct HeapStruct
 12 {
 13     HuffmanTree* Elements;
 14     int Capacity;
 15     int Size;
 16 };
 17 
 18 MinHeap Create(int MaxSize);   //创造一个空的最小堆
 19 int IsFull(MinHeap H);
 20 void Insert(MinHeap H, HuffmanTree T);
 21 HuffmanTree DeleteMin(MinHeap H);   //删除一个权重最小的节点 并返回
 22 
 23 MinHeap Create(int MaxSize)
 24 {
 25     MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
 26     H->Elements = (HuffmanTree*)malloc(sizeof(struct TreeNode) * (MaxSize + 1));
 27     H->Capacity = MaxSize;
 28     H->Size = 0;
 29     H->Elements[0]->Weight = -1;  //设置哨兵
 30     return H;
 31 }
 32 int IsFull(MinHeap H)
 33 {
 34     return (H->Size == H->Capacity) ? 1 : 0;
 35 }
 36 void Insert(MinHeap H, HuffmanTree T)
 37 {
 38     if (IsFull(H))
 39         return;
 40     int i = ++H->Size;
 41     for (; T->Weight < H->Elements[i / 2]->Weight; i /= 2)
 42         H->Elements[i] = H->Elements[i / 2];
 43     H->Elements[i] = T;
 44 }
 45 HuffmanTree DeleteMin(MinHeap H)
 46 {
 47     if (IsFull(H))
 48         return;
 49     HuffmanTree MinItem = H->Elements[1];
 50     HuffmanTree Tmp = H->Elements[H->Size--];
 51     int Parent, Child;   //这俩个记录的是位置
 52     for (Parent = 1; Parent * 2 <= H->Size; Parent = Child)
 53     {
 54         Child = Parent * 2;
 55         if (Child != H->Size && H->Elements[Child]->Weight > H->Elements[Child + 1]->Weight)
 56             Child++;
 57         if (Tmp->Weight <= H->Elements[Child]->Weight)break;   //注意这边  找到后就立即结束循环 这样才能添加到正确位置
 58         else
 59             H->Elements[Parent] = H->Elements[Child];
 60     }
 61     H->Elements[Parent] = Tmp;
 62     return MinItem;
 63 }
 64 
 65 //建立最小堆
 66 //元素已经读入
 67 void PercDown(MinHeap H, int i)
 68 {
 69     int Parent, Child;
 70     HuffmanTree Tmp = H->Elements[i];
 71     for (Parent = i; Parent * 2 <= H->Size; Parent = Child)
 72     {
 73         Child = Parent * 2;
 74         if ((Child != H->Size) && (H->Elements[Child]->Weight > H->Elements[Child + 1]->Weight))
 75             Child++;
 76         if (Tmp->Weight <= H->Elements[Child]->Weight)break;
 77         else
 78             H->Elements[Parent] = H->Elements[Child];    
 79     }
 80     H->Elements[Parent] = Tmp;
 81 }
 82 void BuildMinHeap(MinHeap H)
 83 {
 84     for (int i = H->Size / 2; i > 0; i--)   //从最后一个有子节点的父节点开始
 85         PercDown(H, i);
 86 }
 87 
 88 //利用最小堆 构建哈夫曼树 
 89 //每次把权值最小的两颗二叉树合并
 90 HuffmanTree Huffman(MinHeap H)
 91 { //假设H->Size个权值已经存在H->Elements[]->Weight里
 92     int i;
 93     HuffmanTree T;
 94     BuildMinHeap(H);  //将H->Elements[]按照权重调整为最小堆
 95     for (int i = 1; i < H->Size; i++)   //H->Size个元素合并 总共需要H->Size-1次
 96     {
 97         T = (HuffmanTree)malloc(sizeof(struct TreeNode));
 98         T->Left = DeleteMin(H);  //取出权重最小的元素 作为T的左节点
 99         T->Right = DeleteMin(H); //取出权重最小的元素 作为T的右节点
100         T->Weight = T->Left->Weight + T->Right->Weight;  //计算新的权重
101         Insert(H, T);  //将新T插入最小堆中;
102     }
103     T = DeleteMin(H);
104     return T;
105 }
View Code

哈夫曼树的特点:

①没有度为1的节点

②n个叶子节点的哈夫曼树公有2n-1个节点

因为$n_0=n_2+1$

③哈夫曼树的任意非叶节点的左右子树交换后任是哈夫曼树

④对同一组权值 可能会存在不同构的哈夫曼树 但他们的WPL是一样的

PTA第12题  读入一串数 将其处理为 最小堆 并输出 从某个下标i到根节点的数据(因为最大堆是一个完全二叉树)

要注意数据个数 以及数据最小值 我最开始取 哨兵H[0]=-1  那么肯定负数 就无法正确处理

还有发现的问题是  用的方法不一样 生成的最小(大)堆结果不一样

建立最大(小)堆的方式有两种(就我所知):

① 通过插入操作 不断将元素插入 复杂度为 ${O(NLogN)}$

② 先将数据按顺序存入(满足完全二叉树的特征)  在调整各个节点的位置 复杂度为 ${O(LogN)}$

利用插入操作:

 1 #define _CRT_SECURE_NO_WARNINGS   
 2 #include<stdio.h>
 3 #include<malloc.h>
 4 
 5 typedef struct HeapStruct* MinHeap;
 6 struct HeapStruct
 7 {
 8     int* Elements;
 9     int Size;
10     int Capacity;
11 };
12 int IsFull(MinHeap H)
13 {
14     return (H->Capacity == H->Size) ? 1:0;
15 }
16 MinHeap Create(int MaxSize)
17 {
18     MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
19     H->Elements = (int*)malloc(sizeof(int) * (MaxSize + 1));
20     H->Capacity = MaxSize;
21     H->Size = 0;
22     H->Elements[0] = -10001;
23     return H;
24 }
25 void Print(MinHeap H, int num)
26 {
27     for (int i = num; i >= 1; i /= 2)
28     {
29         if (i > 1)
30             printf("%d ", H->Elements[i]);
31         else
32             printf("%d", H->Elements[i]);
33     }
34     printf("\n");
35 }
36 void Insert(MinHeap H, int Element)
37 {
38     if (IsFull(H))
39         return;
40     int i = ++H->Size;
41     for (; Element < H->Elements[i / 2]; i /= 2)
42         H->Elements[i] = H->Elements[i / 2];
43     H->Elements[i] = Element;
44 }
45 
46 int main()
47 {
48     MinHeap H;
49     H = Create(1001);
50     int N, M;
51     scanf("%d %d\n", &N, &M);
52     for (int i = 1; i < N + 1; i++)
53     {
54         int num;
55         scanf("%d", &num);
56         Insert(H, num);
57     }
58     for (int i = 0; i < M; i++)
59     {
60         int num;
61         scanf("%d", &num);
62         Print(H, num);
63     }
64     return 0;
65 }
View Code

利用读入 再 转换的操作

 1 #define _CRT_SECURE_NO_WARNINGS   
 2 #include<stdio.h>
 3 #include<malloc.h>
 4 
 5 typedef struct HeapStruct* MinHeap;
 6 struct HeapStruct
 7 {
 8     int* Elements;
 9     int Size;
10     int Capacity;
11 };
12 
13 MinHeap Create(int MaxSize)
14 {
15     MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
16     H->Elements =(int*)malloc(sizeof(int) * (MaxSize + 1));
17     H->Capacity = MaxSize;
18     H->Size = 0;
19     H->Elements[0]= -10001;
20     return H;
21 }
22 //建立最小堆
23 void PrecDown(MinHeap H, int i)  //下滤
24 {
25     int Parent, Child;
26     int Tmp = H->Elements[i];
27     for (Parent = i; Parent * 2 <= H->Size; Parent = Child)
28     {
29         Child = Parent * 2;
30         if ((Child != H->Size) && (H->Elements[Child]>H->Elements[Child + 1]))
31             Child++;
32         if (Tmp <= H->Elements[Child])break;
33         else
34             H->Elements[Parent] = H->Elements[Child];
35     }
36 
37     H->Elements[Parent] = Tmp;
38 }
39 void BuildMinHeap(MinHeap H)
40 {
41     int i;
42     for (i = H->Size / 2; i > 0; i--)
43         PrecDown(H, i);
44 }
45 void Print(MinHeap H, int num)
46 {
47     for (int i = num; i >= 1; i /= 2)
48     {
49         if(i>1)
50             printf("%d ", H->Elements[i]);
51         else
52             printf("%d", H->Elements[i]);
53     }
54     printf("\n");
55 }
56 int main()
57 {
58     MinHeap H;
59     H = Create(1001);
60     int N, M;
61     scanf("%d %d\n", &N, &M);
62     for (int i = 1; i < N+1; i++)
63     {
64         int num;
65         scanf("%d", &num);
66         H->Elements[++H->Size] = num;
67     }
68     BuildMinHeap(H);
69     for (int i = 0; i < M; i++)
70     {
71         int num;
72         scanf("%d", &num);
73         Print(H, num);
74     }
75     return 0;
76 }
View Code

PTA第13题  

并查集算法的实践  听了一点课后就做 答案部分正确 我的思路比较简单 

课上讲利用数组来 简化表示集合 因为$N$个元素可以一一映射到${0}\sim{N-1}$

每次读入俩个数据 若是连接 就把第一个元素的父节点设置为第二个元素

若是判断是否连接 就插叙两个元素的父节点是否相等

这样做出来答案是错误的 没有Union操作 没有压缩路径操作

 1 #define _CRT_SECURE_NO_WARNINGS  
 2 #include<stdio.h>
 3 
 4 typedef int ElementType;
 5 typedef ElementType SetName;
 6 typedef ElementType SetType[10001];
 7 
 8 SetName Find(SetType S, ElementType X)
 9 {
10     for (; S[X] >= 0; X = S[X]);
11     return X;
12 }
13 
14 void Union(SetType S, ElementType X1, ElementType X2)
15 {
16     SetName Root1 = Find(S, X1);
17     SetName Root2 = Find(S, X2);
18     if (Root1 != Root2) S[Root2] = Root1;
19 }
20 
21 int main()
22 {
23     SetType S;
24     for (int i = 0; i < 20; i++) S[i] = -1;
25     int N;
26     scanf("%d\n", &N);
27     char Cand;
28     while (scanf("%c",&Cand)&&Cand!='S')
29     {
30         int Com1, Com2;
31         scanf("%d%d\n", &Com1, &Com2);
32         if (Cand == 'C')
33         {
34             if (Find(S, Com1) == Find(S, Com2))
35                 printf("yes\n");
36             else
37                 printf("no\n");
38         }
39         else if (Cand == 'I')
40         {
41             S[Com1] = Com2;
42         }
43     }
44     int Size = 0;
45     for (int i = 0; i < N; i++)
46     {
47         if (S[i] == -1)
48             Size++;
49     }
50     if (Size == 1)
51         printf("The network is connected.");
52     else
53         printf("There are %d components.", Size);
54     return 0;
55 }
View Code

猜你喜欢

转载自www.cnblogs.com/57one/p/11434189.html
今日推荐