OSDN Git Service

io.c:fllbuf() was refined
[lha/olha.git] / maketree.c
index f96ddc3..d689268 100644 (file)
-/***********************************************************\r
-       maketree.c -- make Huffman tree\r
-***********************************************************/\r
-#include "ar.h"\r
-\r
-static int    n, heapsize;\r
-static short  heap[NC + 1];\r
-static ushort *freq, *sortptr, len_cnt[17];\r
-static uchar  *len;\r
-\r
-static void count_len(int i)  /* call with i = root */\r
-{\r
-       static int depth = 0;\r
-\r
-       if (i < n) len_cnt[(depth < 16) ? depth : 16]++;\r
-       else {\r
-               depth++;\r
-               count_len(left [i]);\r
-               count_len(right[i]);\r
-               depth--;\r
-       }\r
-}\r
-\r
-static void make_len(int root)\r
-{\r
-       int i, k;\r
-       uint cum;\r
-\r
-       for (i = 0; i <= 16; i++) len_cnt[i] = 0;\r
-       count_len(root);\r
-       cum = 0;\r
-       for (i = 16; i > 0; i--)\r
-               cum += len_cnt[i] << (16 - i);\r
-       while (cum != (1U << 16)) {\r
-               fprintf(stderr, "17");\r
-               len_cnt[16]--;\r
-               for (i = 15; i > 0; i--) {\r
-                       if (len_cnt[i] != 0) {\r
-                               len_cnt[i]--;  len_cnt[i+1] += 2;  break;\r
-                       }\r
-               }\r
-               cum--;\r
-       }\r
-       for (i = 16; i > 0; i--) {\r
-               k = len_cnt[i];\r
-               while (--k >= 0) len[*sortptr++] = i;\r
-       }\r
-}\r
-\r
-static void downheap(int i)\r
-       /* priority queue; send i-th entry down heap */\r
-{\r
-       int j, k;\r
-\r
-       k = heap[i];\r
-       while ((j = 2 * i) <= heapsize) {\r
-               if (j < heapsize && freq[heap[j]] > freq[heap[j + 1]])\r
-                       j++;\r
-               if (freq[k] <= freq[heap[j]]) break;\r
-               heap[i] = heap[j];  i = j;\r
-       }\r
-       heap[i] = k;\r
-}\r
-\r
-static void make_code(int n, uchar len[], ushort code[])\r
-{\r
-       int    i;\r
-       ushort start[18];\r
-\r
-       start[1] = 0;\r
-       for (i = 1; i <= 16; i++)\r
-               start[i + 1] = (start[i] + len_cnt[i]) << 1;\r
-       for (i = 0; i < n; i++) code[i] = start[len[i]]++;\r
-}\r
-\r
-int make_tree(int nparm, ushort freqparm[],\r
-                               uchar lenparm[], ushort codeparm[])\r
-       /* make tree, calculate len[], return root */\r
-{\r
-       int i, j, k, avail;\r
-\r
-       n = nparm;  freq = freqparm;  len = lenparm;\r
-       avail = n;  heapsize = 0;  heap[1] = 0;\r
-       for (i = 0; i < n; i++) {\r
-               len[i] = 0;\r
-               if (freq[i]) heap[++heapsize] = i;\r
-       }\r
-       if (heapsize < 2) {\r
-               codeparm[heap[1]] = 0;  return heap[1];\r
-       }\r
-       for (i = heapsize / 2; i >= 1; i--)\r
-               downheap(i);  /* make priority queue */\r
-       sortptr = codeparm;\r
-       do {  /* while queue has at least two entries */\r
-               i = heap[1];  /* take out least-freq entry */\r
-               if (i < n) *sortptr++ = i;\r
-               heap[1] = heap[heapsize--];\r
-               downheap(1);\r
-               j = heap[1];  /* next least-freq entry */\r
-               if (j < n) *sortptr++ = j;\r
-               k = avail++;  /* generate new node */\r
-               freq[k] = freq[i] + freq[j];\r
-               heap[1] = k;  downheap(1);  /* put into queue */\r
-               left[k] = i;  right[k] = j;\r
-       } while (heapsize > 1);\r
-       sortptr = codeparm;\r
-       make_len(k);\r
-       make_code(nparm, lenparm, codeparm);\r
-       return k;  /* return root */\r
-}\r
+/***********************************************************
+       maketree.c -- make Huffman tree
+***********************************************************/
+#include "ar.h"
+
+struct heap_t {
+    short buf[NC + 1];          /* buf[0] is not used */
+    int size;
+    unsigned short *freq;       /* priority */
+};
+
+struct tree_t {
+    ushort left[2 * NC - 1];
+    ushort right[2 * NC - 1];
+    ushort len_cnt[17];
+};
+
+static void
+count_len(struct tree_t *t, int i, int n, int *depth)
+{                               /* call with i = root */
+    if (i < n)
+        t->len_cnt[(*depth < 16) ? *depth : 16]++;
+    else {
+        ++*depth;
+        count_len(t, t->left[i], n, depth);
+        count_len(t, t->right[i], n, depth);
+        --*depth;
+    }
+}
+
+static void
+make_len(struct tree_t *t, int root, int n, uchar *len, ushort *sortptr)
+{
+    int i, k;
+    uint cum;
+    int depth = 0;
+
+    for (i = 0; i <= 16; i++)
+        t->len_cnt[i] = 0;
+    count_len(t, root, n, &depth);
+    cum = 0;
+    for (i = 16; i > 0; i--)
+        cum += t->len_cnt[i] << (16 - i);
+    while (cum != (1U << 16)) {
+        t->len_cnt[16]--;
+        for (i = 15; i > 0; i--) {
+            if (t->len_cnt[i] != 0) {
+                t->len_cnt[i]--;
+                t->len_cnt[i + 1] += 2;
+                break;
+            }
+        }
+        cum--;
+    }
+    for (i = 16; i > 0; i--) {
+        k = t->len_cnt[i];
+        while (--k >= 0)
+            len[*sortptr++] = i;
+    }
+}
+
+static void
+downheap(struct heap_t *heap, int i)
+        /* priority queue; send i-th entry down heap */
+{
+    int j, k;
+
+    k = heap->buf[i];
+    while ((j = 2 * i) <= heap->size) {
+        if (j < heap->size && heap->freq[heap->buf[j]] > heap->freq[heap->buf[j + 1]])
+            j++;
+        if (heap->freq[k] <= heap->freq[heap->buf[j]])
+            break;
+        heap->buf[i] = heap->buf[j];
+        i = j;
+    }
+    heap->buf[i] = k;
+}
+
+static void
+make_code(struct tree_t *t, int n, uchar len[], ushort code[])
+{
+    int i;
+    ushort start[18];
+
+    start[1] = 0;
+    for (i = 1; i <= 16; i++)
+        start[i + 1] = (start[i] + t->len_cnt[i]) << 1;
+    for (i = 0; i < n; i++)
+        code[i] = start[len[i]]++;
+}
+
+int
+make_tree(int nparm, ushort freqparm[], uchar lenparm[], ushort codeparm[])
+        /* make tree, calculate len[], return root */
+{
+    int i, j, k, avail;
+    struct heap_t heap;
+    struct tree_t t;
+    int n;
+    unsigned short *sortptr;
+
+    n = nparm;
+    heap.freq = freqparm;
+    avail = n;
+    heap.size = 0;
+    heap.buf[1] = 0;
+    for (i = 0; i < n; i++) {
+        lenparm[i] = 0;
+        if (heap.freq[i])
+            heap.buf[++heap.size] = i;
+    }
+    if (heap.size < 2) {
+        codeparm[heap.buf[1]] = 0;
+        return heap.buf[1];
+    }
+    for (i = heap.size / 2; i >= 1; i--)
+        downheap(&heap, i);            /* make priority queue */
+    sortptr = codeparm;
+    do {                        /* while queue has at least two entries */
+        i = heap.buf[1];        /* take out least-freq entry */
+        if (i < n)
+            *sortptr++ = i;
+        heap.buf[1] = heap.buf[heap.size--];
+        downheap(&heap, 1);
+
+        j = heap.buf[1];       /* next least-freq entry */
+        if (j < n)
+            *sortptr++ = j;
+
+        k = avail++;            /* generate new node */
+        heap.freq[k] = heap.freq[i] + heap.freq[j];
+        heap.buf[1] = k;
+        downheap(&heap, 1);     /* put into queue */
+        t.left[k] = i;
+        t.right[k] = j;
+    } while (heap.size > 1);
+    make_len(&t, k, n, lenparm, codeparm);
+    make_code(&t, nparm, lenparm, codeparm);
+    return k;                   /* return root */
+}