⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 deftree.c

📁 windows gzip source code
💻 C
字号:
//
// deftree.c
//
// Tree creation for the compressor
//
#include "deflate.h"
#include <string.h>
#include <crtdbg.h>


//
// MAX_LITERAL_TREE elements is the largest number of elements that will ever be passed
// in to this routine
//
typedef struct 
{
    // Made left_right a single long array for performance reasons.  We always access them
    // one after the other, so there is no disadvantage.
    // left[] in lower 16 bits, right[] in upper 16 bits
//	short           left[2*MAX_LITERAL_TREE_ELEMENTS];
//	short           right[2*MAX_LITERAL_TREE_ELEMENTS];
    unsigned long   left_right[2*MAX_LITERAL_TREE_ELEMENTS];

	int             heap[MAX_LITERAL_TREE_ELEMENTS+1];

	int				num_elements;

	// Maximum allowable code length (7 for pre-tree, 15 for other trees)
	int				max_code_length;

	unsigned short *freq; // passed in as parameter
	unsigned short *code; // passed in as parameter
	
	short *			sortptr;
	int				depth;
	int				heapsize;
	int             len_cnt[17];
} t_tree_context;



static void countLen(t_tree_context *context, int i)  /* call with i = root */
{
	if (i < context->num_elements)
	{
		// check for max code length allowed
		context->len_cnt[(context->depth < context->max_code_length) ? context->depth : context->max_code_length]++;
	}
	else
	{
        unsigned long lr_value = context->left_right[i];

		context->depth++;
		countLen(context, lr_value & 65535); // formerly left[i]
		countLen(context, lr_value >> 16); // formerly right[i]
		context->depth--;
	}
}


static void makeLen(t_tree_context *context, int root, BYTE *len)
{
	int		k;
	int		cum;
	int		i;

	for (i = 0; i <= 16; i++)
		context->len_cnt[i] = 0;

	countLen(context, root);

	cum = 0;

	for (i = context->max_code_length; i > 0; i--)
		cum += (context->len_cnt[i] << (context->max_code_length - i));

	while (cum != (1 << context->max_code_length))
	{
		context->len_cnt[context->max_code_length]--;

		for (i = context->max_code_length-1; i > 0; i--)
		{
			if (context->len_cnt[i] != 0)
			{
				context->len_cnt[i]--;
				context->len_cnt[i+1] += 2;
				break;
			}
		}

		cum--;
	}

	for (i = 16; i > 0; i--)
	{
		k = context->len_cnt[i];

		while (--k >= 0)
			len[ *context->sortptr++ ] = (byte) i;
	}
}


/* priority queue; send i-th entry down heap */
static void downHeap(t_tree_context *context, int i)
{
	int j, k;

	k = context->heap[i];

	while ((j = (i<<1)) <= context->heapsize)
	{
		if (j < context->heapsize && 
			context->freq[context->heap[j]] > context->freq[context->heap[j + 1]])
	 		j++;

		if (context->freq[k] <= context->freq[context->heap[j]])
			break;

		context->heap[i] = context->heap[j];
		i = j;
	}

	context->heap[i] = k;
}


//
// Reverse the bits, len > 0
//
static unsigned int bitReverse(unsigned int code, int len)
{
	unsigned int new_code = 0;

	do
	{
		new_code |= (code & 1);
		new_code <<= 1;
		code >>= 1;

	} while (--len > 0);

	return new_code >> 1;
}


void makeCode(int num_elements, const int *len_cnt, const BYTE *len, USHORT *code)
{
	int start[18];
	int i;
	
	start[1] = 0;

	for (i = 1; i <= 16; i++)
		start[i + 1] = (start[i] + len_cnt[i]) << 1;

	for (i = 0; i < num_elements; i++)
	{
		unsigned int unreversed_code;
		
		unreversed_code = start[len[i]]++;
		code[i] = (USHORT) bitReverse(unreversed_code, len[i]);
	}
}


void makeTree(
	int					num_elements,
	int					max_code_length,
	unsigned short *	freq,
	unsigned short *	code,
	byte *				len
)
{
	t_tree_context	tree;
	int				k;
	int				avail;
	int				i;

    _ASSERT(num_elements <= MAX_LITERAL_TREE_ELEMENTS);

	// init tree context
	tree.depth	= 0;
	tree.freq	= freq;
	tree.code	= code;
	tree.num_elements = num_elements;
	tree.max_code_length = max_code_length;

	avail				= num_elements;
	tree.heapsize		= 0;
	tree.heap[1]		= 0;

	for (i = 0; i < tree.num_elements; i++)
	{
		len[i] = 0;

		if (tree.freq[i] != 0)
			tree.heap[++tree.heapsize] = i;
	}

	//
	// Less than 2 elements in the tree?
	//
	if (tree.heapsize < 2)
	{
		if (tree.heapsize == 0)
		{
			//
			// No elements in the tree?
			//
			// Then insert two fake elements and retry.
			//
			tree.freq[0] = 1;
			tree.freq[1] = 1;
		}	
		else
		{
			//
			// One element in the tree, so add a fake code
			//
			// If our only element is element #0 (heap[1] == 0), then
			// make element #1 have a frequency of 1.
			//
			// Else make element #0 have a frequency of 1.
			//
			if (tree.heap[1] == 0)
				tree.freq[1] = 1;
			else
				tree.freq[0] = 1;
		}

		//
		// Retry with these new frequencies
		//
		makeTree(num_elements, max_code_length, freq, code, len);
		return;
	}

	for (i = tree.heapsize >> 1; i >= 1; i--)
		downHeap(&tree, i);  /* make priority queue */

	tree.sortptr = tree.code;

	do
	{
		int i, j;

		/* while queue has at least two entries */
		i = tree.heap[1];  /* take out least-freq entry */

		if (i < tree.num_elements)
			*tree.sortptr++ = (short) i; 

		tree.heap[1] = tree.heap[tree.heapsize--];
		downHeap(&tree, 1);

		j = tree.heap[1];  /* next least-freq entry */

		if (j < tree.num_elements)
			*tree.sortptr++ = (short) j; 

		k = avail++;  /* generate new node */

		tree.freq[k] = tree.freq[i] + tree.freq[j];
		tree.heap[1] = k;
		downHeap(&tree, 1);  /* put into queue */

//		tree.left[k] = (short) i;
//		tree.right[k] = (short) j;
		tree.left_right[k] = (j << 16) | i;

	} while (tree.heapsize > 1);

	tree.sortptr = tree.code;

	makeLen(&tree, k, len);
	makeCode(num_elements, tree.len_cnt, len, code);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -