1
+ // Prior Quneue,完全用数组形式实现的最大堆功能
2
+ typedef struct MaxPriorQue {
3
+ int * * heap ; // 二维数组 heap[i][0/1] 0是idx,1是val
4
+ int size ; // 当前队列大小
5
+ int capcity ; // 队列最大容量
6
+ } MaxPriorQueStru , * pMaxPriorQueStru ;
7
+
8
+ void init (pMaxPriorQueStru p , int size )
9
+ {
10
+ p -> size = 0 ;
11
+ p -> heap = (int * * )malloc ((size + 1 ) * sizeof (int * ));
12
+ // if (p->heap == NULL) { return NULL;}
13
+ p -> capcity = size + 1 ;
14
+
15
+ int i ;
16
+ for (i = 0 ; i < p -> capcity ; i ++ ) {
17
+ p -> heap [i ] = (int * )malloc (2 * sizeof (int ));
18
+ // if (p->heap[i] == NULL) { return NULL; }
19
+ }
20
+
21
+ return ;
22
+ }
23
+
24
+ int cmpValOrIdx (int * a , int * b )
25
+ {
26
+ return a [1 ] == b [1 ] ? a [0 ] - b [0 ] : a [1 ] - b [1 ]; // 优先比较数值,再比较下标
27
+ }
28
+
29
+ // 完全用数组形式实现的最大堆功能
30
+ void push (pMaxPriorQueStru p , int idx , int val )
31
+ {
32
+ // 已保证堆足够大,不用担心溢出
33
+ p -> size += 1 ;
34
+
35
+ // 先放末端节点
36
+ p -> heap [p -> size ][0 ] = idx ;
37
+ p -> heap [p -> size ][1 ] = val ;
38
+
39
+ // 通过与上层节点不断比较交换,找到合适位置
40
+ int i0 = p -> size >> 1 ;
41
+ int i1 = p -> size ;
42
+ while (i0 > 0 && cmpValOrIdx (p -> heap [i0 ], p -> heap [i1 ]) < 0 ) {
43
+ int * tmp = p -> heap [i0 ]; // 交换二级指针指向的一级指针地址
44
+ p -> heap [i0 ] = p -> heap [i1 ];
45
+ p -> heap [i1 ] = tmp ;
46
+ i1 = i0 ; // 继续往上一层末端节点比较
47
+ i0 >>= 1 ;
48
+ }
49
+
50
+ return ;
51
+ }
52
+
53
+ void pop (pMaxPriorQueStru p )
54
+ {
55
+ // 将顶端的值与末尾节点交换,再自减容量
56
+ int * tmp = p -> heap [1 ]; // 交换二级指针指向的一级指针地址
57
+ p -> heap [1 ] = p -> heap [p -> size ];
58
+ p -> heap [p -> size ] = tmp ;
59
+ p -> size -- ;
60
+
61
+ // 调整堆,把末尾节点下沉到合适位置
62
+ int i = 1 ; // 从顶端开始
63
+ while (i <= p -> size ) {
64
+ int l = i << 1 ; // 左孩子索引
65
+ int r = l + 1 ; // 右孩子索引
66
+ int max = i ;
67
+ if (l <= p -> size && cmpValOrIdx (p -> heap [max ], p -> heap [l ]) < 0 ) {
68
+ max = l ;
69
+ }
70
+ if (r <= p -> size && cmpValOrIdx (p -> heap [max ], p -> heap [r ]) < 0 ) {
71
+ max = r ;
72
+ }
73
+ if (max == i ) { // 如果父节点就已是最大值,则调整完毕,顶端交换的值已找到合适位置
74
+ break ;
75
+ }
76
+ // 需要交换
77
+ int * tmp = p -> heap [i ]; // 交换二级指针指向的一级指针地址
78
+ p -> heap [i ] = p -> heap [max ];
79
+ p -> heap [max ] = tmp ;
80
+
81
+ i = max ; // 和max的指针交换后,当前max索引是被交换到顶端的底部值,待进一步下沉比较
82
+ }
83
+ // i下沉到最末端或者末尾节点已下沉到合适位置,结束调整
84
+
85
+ return ;
86
+ }
87
+
88
+ int * top (pMaxPriorQueStru p )
89
+ {
90
+ return p -> heap [1 ]; // 为方便下标引用,索引0空置不用
91
+ }
92
+
93
+ void SetFree (pMaxPriorQueStru p )
94
+ {
95
+ int i ;
96
+ for (i = 0 ; i < p -> capcity ; i ++ ) {
97
+ free (p -> heap [i ]);
98
+ }
99
+ free (p -> heap );
100
+ free (p );
101
+ return ;
102
+ }
103
+
104
+ // 利用最大堆队列数据结构来完成
105
+ int * maxSlidingWindow (int * nums , int numsSize , int k , int * returnSize )
106
+ {
107
+ if (k == 1 ) {
108
+ * returnSize = numsSize ;
109
+ return nums ;
110
+ }
111
+
112
+ // 压入前k个数据
113
+ pMaxPriorQueStru q = (pMaxPriorQueStru )malloc (sizeof (MaxPriorQueStru ));
114
+ if (q == NULL ) { return NULL ; }
115
+ init (q , numsSize );
116
+
117
+ int resSize = numsSize - k + 1 ;
118
+ int * resArr = (int * )malloc (resSize * sizeof (int ));
119
+ if (resArr == NULL ) { return NULL ; }
120
+
121
+ int end = 0 ;
122
+ int i ;
123
+ for (i = 0 ; i < k ; i ++ ) {
124
+ push (q , i , nums [i ]);
125
+ }
126
+ int * heap = top (q );
127
+ // resArr[*returnSize++] = heap[1]; // 作用是:resArr[*returnSize], 再returnSize++,加在地址上了,与预期不符
128
+ resArr [end ++ ] = heap [1 ];
129
+ //printf("%d \n", *returnSize);
130
+ //printf("%d ", heap[1]);
131
+
132
+ // 从k往后移动
133
+ for (i = k ; i < numsSize ; i ++ ) {
134
+ push (q , i , nums [i ]);
135
+ heap = top (q );
136
+ while (heap [0 ] <= i - k ) {
137
+ pop (q );
138
+ heap = top (q );
139
+ }
140
+ //resArr[*returnSize++] = heap[1];
141
+ resArr [end ++ ] = heap [1 ];
142
+ // printf("%d \n", *returnSize);
143
+ // printf("%d ", heap[1]);
144
+ }
145
+ //printf("%d \n", *returnSize);
146
+
147
+ * returnSize = end ;
148
+ SetFree (q );
149
+
150
+ return resArr ;
151
+ }
0 commit comments