Skip to content

Commit

Permalink
常用数据结构与算法
Browse files Browse the repository at this point in the history
  • Loading branch information
mmc-maodun committed Mar 30, 2014
0 parents commit 9edfc57
Show file tree
Hide file tree
Showing 55 changed files with 4,663 additions and 0 deletions.
242 changes: 242 additions & 0 deletions Huffman tree/Function.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"data_structure.h"

/*
根据给定的n个权值构造一棵赫夫曼树,wet中存放n个权值
*/
HuffmanTree create_HuffmanTree(int *wet,int n)
{
//一棵有n个叶子节点的赫夫曼树共有2n-1个节点
int total = 2*n-1;
HuffmanTree HT = (HuffmanTree)malloc(total*sizeof(HTNode));
if(!HT)
{
printf("HuffmanTree malloc faild!");
exit(-1);
}
int i;

//以下初始化序号全部用-1表示,
//这样在编码函数中进行循环判断parent或lchild或rchild的序号时,
//不会与HT数组中的任何一个下标混淆而造成误判

//HT[0],HT[1]...HT[n-1]中存放需要编码的n个叶子节点
for(i=0;i<n;i++)
{
HT[i].parent = -1;
HT[i].lchild = -1;
HT[i].rchild = -1;
HT[i].weight = *wet;
wet++;
}

//HT[n],HT[n+1]...HT[2n-2]中存放的是中间构造出的每棵二叉树的根节点
for(;i<total;i++)
{
HT[i].parent = -1;
HT[i].lchild = -1;
HT[i].rchild = -1;
HT[i].weight = 0;
}

int min1,min2; //用来保存每一轮选出的两个weight最小且parent为0的节点
//每一轮比较后选择出min1和min2构成一课二叉树,最后构成一棵赫夫曼树
for(i=n;i<total;i++)
{
select_minium(HT,i,min1,min2);
HT[min1].parent = i;
HT[min2].parent = i;
//这里左孩子和右孩子可以反过来,构成的也是一棵赫夫曼树,只是所得的编码不同
HT[i].lchild = min1;
HT[i].rchild = min2;
HT[i].weight =HT[min1].weight + HT[min2].weight;
}
return HT;
}

/*
从HT数组的前k个元素中选出weight最小且parent为-1的两个,分别将其序号保存在min1和min2中
*/
void select_minium(HuffmanTree HT,int k,int &min1,int &min2)
{
min1 = min(HT,k);
min2 = min(HT,k);
}

/*
从HT数组的前k个元素中选出weight最小且parent为-1的元素,并将该元素的序号返回
*/
int min(HuffmanTree HT,int k)
{
int i = 0;
int min; //用来存放weight最小且parent为-1的元素的序号
int min_weight; //用来存放weight最小且parent为-1的元素的weight值

//先将第一个parent为-1的元素的weight值赋给min_weight,留作以后比较用。
//注意,这里不能按照一般的做法,先直接将HT[0].weight赋给min_weight,
//因为如果HT[0].weight的值比较小,那么在第一次构造二叉树时就会被选走,
//而后续的每一轮选择最小权值构造二叉树的比较还是先用HT[0].weight的值来进行判断,
//这样又会再次将其选走,从而产生逻辑上的错误。
while(HT[i].parent != -1)
i++;
min_weight = HT[i].weight;
min = i;

//选出weight最小且parent为-1的元素,并将其序号赋给min
for(;i<k;i++)
{
if(HT[i].weight<min_weight && HT[i].parent==-1)
{
min_weight = HT[i].weight;
min = i;
}
}

//选出weight最小的元素后,将其parent置1,使得下一次比较时将其排除在外。
HT[min].parent = 1;

return min;
}

/*
从叶子节点到根节点逆向求赫夫曼树HT中n个叶子节点的赫夫曼编码,并保存在HC中
*/
void HuffmanCoding(HuffmanTree HT,HuffmanCode &HC,int n)
{
//用来保存指向每个赫夫曼编码串的指针
HC = (HuffmanCode)malloc(n*sizeof(char *));
if(!HC)
{
printf("HuffmanCode malloc faild!");
exit(-1);
}

//临时空间,用来保存每次求得的赫夫曼编码串
//对于有n个叶子节点的赫夫曼树,各叶子节点的编码长度最长不超过n-1
//外加一个'\0'结束符,因此分配的数组长度最长为n即可
char *code = (char *)malloc(n*sizeof(char));
if(!code)
{
printf("code malloc faild!");
exit(-1);
}

code[n-1] = '\0'; //编码结束符,亦是字符数组的结束标志
//求每个字符的赫夫曼编码
int i;
for(i=0;i<n;i++)
{
int current = i; //定义当前访问的节点
int father = HT[i].parent; //当前节点的父节点
int start = n-1; //每次编码的位置,初始为编码结束符的位置
//从叶子节点遍历赫夫曼树直到根节点
while(father != -1)
{
if(HT[father].lchild == current) //如果是左孩子,则编码为0
code[--start] = '0';
else //如果是右孩子,则编码为1
code[--start] = '1';
current = father;
father = HT[father].parent;
}

//为第i个字符的编码串分配存储空间
HC[i] = (char *)malloc((n-start)*sizeof(char));
if(!HC[i])
{
printf("HC[i] malloc faild!");
exit(-1);
}
//将编码串从code复制到HC
strcpy(HC[i],code+start);
}

free(code); //释放保存编码串的临时空间
}

/*
从根节点到叶子节点无栈非递归遍历赫夫曼树HT,求其中n个叶子节点的赫夫曼编码,并保存在HC中
*/
void HuffmanCoding2(HuffmanTree HT,HuffmanCode &HC,int n)
{
//用来保存指向每个赫夫曼编码串的指针
HC = (HuffmanCode)malloc(n*sizeof(char *));
if(!HC)
{
printf("HuffmanCode malloc faild!");
exit(-1);
}

//临时空间,用来保存每次求得的赫夫曼编码串
//对于有n个叶子节点的赫夫曼树,各叶子节点的编码长度最长不超过n-1
//外加一个'\0'结束符,因此分配的数组长度最长为n即可
char *code = (char *)malloc(n*sizeof(char));
if(!code)
{
printf("code malloc faild!");
exit(-1);
}

int cur = 2*n-2; //当前遍历到的节点的序号,初始时为根节点序号
int code_len = 0; //定义编码的长度

//构建好赫夫曼树后,把weight用来当做遍历树时每个节点的状态标志
//weight=0表明当前节点的左右孩子都还没有被遍历
//weight=1表示当前节点的左孩子已经被遍历过,右孩子尚未被遍历
//weight=2表示当前节点的左右孩子均被遍历过
int i;
for(i=0;i<cur+1;i++)
{
HT[i].weight = 0;
}

//从根节点开始遍历,最后回到根节点结束
//当cur为根节点的parent时,退出循环
while(cur != -1)
{
//左右孩子均未被遍历,先向左遍历
if(HT[cur].weight == 0)
{
HT[cur].weight = 1; //表明其左孩子已经被遍历过了
if(HT[cur].lchild != -1)
{ //如果当前节点不是叶子节点,则记下编码,并继续向左遍历
code[code_len++] = '0';
cur = HT[cur].lchild;
}
else
{ //如果当前节点是叶子节点,则终止编码,并将其保存起来
code[code_len] = '\0';
HC[cur] = (char *)malloc((code_len+1)*sizeof(char));
if(!HC[cur])
{
printf("HC[cur] malloc faild!");
exit(-1);
}
strcpy(HC[cur],code); //复制编码串
}
}

//左孩子已被遍历,开始向右遍历右孩子
else if(HT[cur].weight == 1)
{
HT[cur].weight = 2; //表明其左右孩子均被遍历过了
if(HT[cur].rchild != -1)
{ //如果当前节点不是叶子节点,则记下编码,并继续向右遍历
code[code_len++] = '1';
cur = HT[cur].rchild;
}
}

//左右孩子均已被遍历,退回到父节点,同时编码长度减1
else
{
HT[cur].weight = 0;
cur = HT[cur].parent;
--code_len;
}

}
free(code);
}
28 changes: 28 additions & 0 deletions Huffman tree/data_structure.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
赫夫曼树的存储结构,它也是一种二叉树结构,
这种存储结构既适合表示树,也适合表示森林。
*/
typedef struct Node
{
int weight; //权值
int parent; //父节点的序号,为-1的是根节点
int lchild,rchild; //左右孩子节点的序号,为-1的是叶子节点
}HTNode,*HuffmanTree; //用来存储赫夫曼树中的所有节点
typedef char **HuffmanCode; //用来存储每个叶子节点的赫夫曼编码


//根据给定数量的权值构造一棵赫夫曼树
HuffmanTree create_HuffmanTree(int *,int);

//从所有节点中选出权值最小的根节点,并将其在数组中的序号返回
//该函数主要是供select_minium函数调用
int min(HuffmanTree ,int);

//从所有节点中选出权值最小的两个根节点,并将其序号分别保存在后两个参数中
void select_minium(HuffmanTree,int,int &,int &);

//从叶子节点到根节点逆向求每个字符的赫夫曼编码
void HuffmanCoding(HuffmanTree,HuffmanCode &,int);

//从根节点到叶子节点无栈非递归遍历赫夫曼树,并求叶子节点的赫夫曼编码
void HuffmanCoding2(HuffmanTree,HuffmanCode &,int);
37 changes: 37 additions & 0 deletions Huffman tree/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"data_structure.h"

int main()
{
int n; //需要编码的字符的个数
printf("请输入需要编码的字符的个数(>1):");
scanf("%d",&n);
while(n<=1)
{
printf("字符个数必须大于1,请重新输入:");
scanf("%d",&n);
}

int i;
int *wet = (int *)malloc(n*sizeof(int)); //存放每个字符的权值
printf("请依次输入这%d个字符的权值(整型):",n);
for(i=0;i<n;i++)
{
scanf("%d",wet+i);
}

HuffmanCode HC; //保存赫夫曼编码
HuffmanTree HT = create_HuffmanTree(wet,n); //生成赫夫曼树
HuffmanCoding(HT,HC,n); //第一种方法求每个字符的赫夫曼编码
// HuffmanCoding2(HT,HC,n); //第二种方法求每个字符的赫夫曼编码

for(i=0;i<n;i++)
{
puts(HC[i]);
}
free(wet);

return 0;
}
22 changes: 22 additions & 0 deletions Trie Tree/data_structure.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#define MAX 26 //字符集的大小

/*
字典树的存储结构
*/
typedef struct Node
{
struct Node *next[MAX]; //每个节点下面可能有MAX个字符
int count; //以从根节点到当前节点的字符串为公共前缀的字符串数目
}TrieNode,*TrieTree;

//创建一课只有根节点的字典树
TrieTree create_TrieTree();

//向字典树中插入字符串
void insert_TrieTree(TrieTree,char *);

//统计字典树中有给定公共前缀的字符串的数目
int count_TrieTree(TrieTree ,char *);

//销毁字典树
void destroy_TrieTree(TrieTree);
Loading

0 comments on commit 9edfc57

Please sign in to comment.