【C程序设计语言】习题6-2----------详细分析

题目:编写一个程序,用以读入一个C语言程序,并按字母表顺序分组打印变量名,要求每一组内各变量名的前6各字符相同,其他字符不一样.字符串和注释中的单词不予考虑,请将6做为一个可在命令行中设定的参数.


我的分析:这里题目用到了的结构

首先定义一个树的结构

struct tnode	        //树的节点
{
	char *word;	//指向单词的指针
	int match;		//是否打印
	struct tnode *left;    //左子节点
	struct tnode *right;	//右子节点
};
 

而后下面这是一个添加节点的子程序

struct tnode *addtreex(struct tnode *p, char *w, int num, int *found)
{
	int cond;

		if (p == NULL)		//该单词是一个新单词
	{
		//p = talloc();	//建立一个新节点
		p = (struct tnode *)malloc(sizeof(struct tnode));
		p->word = strdup(w);
		p->match = *found;
		p->left = p->right = NULL;
	}
	else if ((cond = compare(w, p, num, found)) < 0)	//首字母ASCALL比当前节点单词的首字母ASCALL的值小
	{
		p->left = addtreex(p->left, w, num, found);
	}
	else if (cond>0)	//首字母ASCALL比当前节点单词的首字母ASCALL的值大  或者 前六个字母相同的新单词
	{
		p->right = addtreex(p->right, w, num, found);
	}
	return p;
}

调用这个子程序返回的p指针永远是头节点的指针
这是一个递归的子程序
因此在调用的时候传入头节点,返回的也是头节点
这一个程序要求打印出来的时候按照首字母排序
下面的一个子程序起到了关键的做用

int compare(char *s, struct tnode *p, int num, int *found)
{
	int i;
	char *t = p->word;

	for (i = 0; *s == *t; i++, s++, t++)
	{
		if (*s == '\0')
		{
			//输入的单词和结构里的单词匹配
			return 0;
		}
	}
	//单词长度>num 默认为6
	if (i >= num)
	{
		*found = YES;
		p->match = YES;
	}
	//返回首字母ASCII码之差
	return *s - *t;
}

这个子程序的返回值是返回首字母ASCII码之差 
按照这个就能实现首字母的比较
前面的子程序addtreex中
下面有一个判断语句,单独摘抄出来给你们看看

else if ((cond = compare(w, p, num, found)) < 0)	//首字母ASCALL比当前节点单词的首字母ASCALL的值小
	{
		p->left = addtreex(p->left, w, num, found);
	}
	else if (cond>0)	//首字母ASCALL比当前节点单词的首字母ASCALL的值大  或者 前六个字母相同的新单词
	{
		p->right = addtreex(p->right, w, num, found);
	}

这个首先比较首字母
若是 首字母ASCALL比当前节点单词的首字母ASCALL的值小 则放在左树
若是 首字母ASCALL比当前节点单词的首字母ASCALL的值大  或者 前六个字母相同的新单词 则放在右树
而下面这个打印的子程序

void treexprint(struct tnode *p)
{
	if (p != NULL)
	{
		treexprint(p->left);
		if (p->match)
		{
			printf("%s\n", p->word);
		}
		treexprint(p->right);
	}
}

它是先打印左树再打印右树 
因此就可以按照字母排序打印出单词




完整的程序

#define _CRT_SECURE_NO_DEPRECATE 
#define _CRT_NONSTDC_NO_DEPRECATE 

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

struct tnode				//树的节点
{
	char *word;				//指向单词的指针
	int match;				//是否打印
	struct tnode *left;		//左子节点
	struct tnode *right;	//右子节点
};

#define MAXWORD	100
#define YES		1
#define NO		0

struct tnode *addtreex(struct tnode *, char *, int, int *);
void treexprint(struct tnode *);
int getword(char *, int);

int main(int argc,char *argv[])
{
	struct tnode *root;
	char word[MAXWORD];
	int found = NO;
	int num;

	num = (--argc && (*++argv)[0] == '-') ? atoi(argv[0] + 1) : 6;
	root = NULL;

	while (getword(word, MAXWORD) != EOF)
	{
		if (isalpha(word[0]) && strlen(word) >= num)
		{
			root = addtreex(root, word, num, &found);
		}
		found = NO;
	}
	treexprint(root);
	return 0;
}

//返回出来永远是返回头节点
struct tnode *addtreex(struct tnode *p, char *w, int num, int *found)
{
	int cond;

		if (p == NULL)		//该单词是一个新单词
	{
		//p = talloc();	//建立一个新节点
		p = (struct tnode *)malloc(sizeof(struct tnode));
		p->word = strdup(w);
		p->match = *found;
		p->left = p->right = NULL;
	}
	else if ((cond = compare(w, p, num, found)) < 0)	//首字母ASCALL比当前节点单词的首字母ASCALL的值小
	{
		p->left = addtreex(p->left, w, num, found);
	}
	else if (cond>0)	//首字母ASCALL比当前节点单词的首字母ASCALL的值大  或者 前六个字母相同的新单词
	{
		p->right = addtreex(p->right, w, num, found);
	}
	return p;
}

int compare(char *s, struct tnode *p, int num, int *found)
{
	int i;
	char *t = p->word;

	for (i = 0; *s == *t; i++, s++, t++)
	{
		if (*s == '\0')
		{
			//输入的单词和结构里的单词匹配
			return 0;
		}
	}
	//单词长度>num 默认为6
	if (i >= num)
	{
		*found = YES;
		p->match = YES;
	}
	//返回首字母ASCII码之差
	return *s - *t;
}

void treexprint(struct tnode *p)
{
	if (p != NULL)
	{
		treexprint(p->left);
		if (p->match)
		{
			printf("%s\n", p->word);
		}
		treexprint(p->right);
	}
}

int getch2(void);
void ungetch2(int);

int comment(void)
{
	int c;
	while ((c = getch2()) != EOF)
	{
		if (c == '*')
		{
			if ((c = getch2()) == '/')
			{
				break;
			}
			else
			{
				ungetch2(c);
			}
		}
	}
	return c;
}

//从输入中读取下一个单词或字符
//lim是限制最长的长度
int getword(char *word, int lim)
{
	int comment(void);
	int c, d;
	char *w = word;

	while (isspace(c = getch2()))
		;

	if (c != EOF)
	{
		*w++ = c;
	}
	if (isalpha(c) || c == '_' || c == '#')
	{
		for (; --lim; w++)	//填充字符 
		{
			if (!isalnum(*w = getch2()) && *w != '_')
			{
				ungetch2(*w);
				break;
			}
		}
	}
	else if (c == '\'' || c == '"')
	{
		for (; --lim > 0; w++)
		{
			if ((*w = getch2()) == '\\')	//???
			{
				*++w = getch2();
			}
			else if (*w == c)	//碰到堆成的符号
			{
				w++;
				break;
			}
			else if (*w == EOF)
			{
				break;
			}

		}
	}
	else if (c == '/')
	{
		if ((d = getch2()) == '*')
		{
			c = comment();	//忽略注释的内容
		}
		else
		{
			ungetch2(d);
		}
	}
	*w = '\0';
	return c;
}

#define BUFSIZE 100

char buf[BUFSIZE];
int bufp = 0;

int getch2(void)
{
	return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch2(int c)
{
	if (bufp >= BUFSIZE)
	{
		printf("ungetch:too many characters\n");
	}
	else
	{
		buf[bufp++] = c;
	}
}