C Primer Plus (第五版) 第十七章 高级数据显示 编程练习

  1. 修改程序清单17.2,使其既能以正序又能以逆序显示电影列表。一种方法修改链表定义以使链表能被双向遍历;另一种方法是使用递归。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TSIZE 45
typedef struct film {
	char title[TSIZE];
	int rating;
	struct film * next;
	struct film * up;
}Film;

void positive(Film * p);	//正序显示
void reversed(Film * p);	//逆序显示
void recursion(Film * p);	//逆序递归显示
void empty(Film * p);

int main(void)
{
	Film * head = NULL;	//指向链表头结点的指针,始终指向头结点保持不变
	Film * current;		//动态内存分配的地址。
	Film * prev;		//尾结点,可变,每次用来更新结构体内指针变量的值和自身的值。
	char input[TSIZE];

	puts("Enter first movie title: ");
	while (gets(input) != NULL && input[0] != ‘\0‘)
	{
		current = (Film *)malloc(sizeof(Film));
		/*
		if ((current = (Film *)malloc(sizeof(Film))) == NULL)
		{
			printf("内存分配失败:\n");
			exit(EXIT_FAILURE);
		}
		*/
		if (head == NULL)
		{
			head = current;
			current->up = NULL;
		}
		else
		{
			prev->next = current;
			current->up = prev;
		}
		current->next = NULL;
		strcpy(current->title, input);
		puts("Enter your rating <0-10>: ");
		scanf("%d", &current->rating);
		while (getchar() != ‘\n‘)
			continue;
		puts("Enter next movie title (empty line to stop): ");
		prev = current;
	}

	if (head == NULL)
		printf("No data entered. ");
	else
	{
		printf("Here is the movie list: \n");
		positive(head);
		printf("\n");
		printf("Here is the movie list: \n");
		reversed(prev);
		printf("\n");
		printf("Here is the movie list: \n");
		recursion(head);
	}

	printf("Bye!\n");

	return 0;
}

void positive(Film * p)
{
	while (p != NULL)
	{
		printf("Movie: %s Rating: %d\n", p->title, p->rating);
		p = p->next;
	}
}
void reversed(Film * p)
{
	while (p != NULL)
	{
		printf("Movie: %s Rating: %d\n", p->title, p->rating);
		p = p->up;
	}
}
void recursion(Film * p)
{
	if (p->next != NULL)
		recursion(p->next);
	printf("Movie: %s Rating: %d\n", p->title, p->rating);
}
void empty(Film * p)
{
	Film * temp;

	while (p != NULL)
	{
		temp = p;
		p = p->next;;
		free(temp);
	}
}

2.假设list.h(程序清单17.3)如下定义列表:

typedef struct list

{

Node * nead; /*指向列表首*/

Node * end; /*指向列表尾*/

}List;

根据这个定义,重写list.c(程序清单17.5)函数,并用films3.c(程序清单17.4)测试结果代码。

/* 重写list.c */
#include <stdio.h>
#include <stdlib.h>
#include "list_17_3.h"

static void CopyToNode(Item item, Node * pnode);

void InitializeList(List * plist)
{
	//plist = NULL;	//Error plist是一个变量地址,只能改变变量的值 ,不能改变地址。
	plist->head = NULL;
	plist->end = NULL;
}

bool ListIsEmpty(const List * plist)
{
	if (plist->head == NULL)
		return true;
	else
		return false;
}

bool ListIsFull(const List * plist)
{	//判定内存是否有足够空间,可以不传递形参
	Node * pt;
	bool full;

	pt = (Node *)malloc(sizeof(Node));
	if (pt == NULL)
		full = true;
	else
		full = false;
	free(pt);
	return full;
}

unsigned int ListItemCount(const List * plist)
{
	unsigned int count = 0;
	Node * pnode = plist->head;	

	while (pnode != NULL)
	{
		++count;
		pnode = pnode->next;
	}

	return count;
}

bool AddItem(Item item, List * plist)
{
	Node * pnew;
	Node * scan = plist->head;

	pnew = (Node *)malloc(sizeof(Node));
	if (pnew == NULL)
		return false;	

	CopyToNode(item, pnew);
	pnew->next = NULL;
	if (scan == NULL)
		plist->head = pnew;
	else
		plist->end->next = pnew;
	plist->end = pnew;
	return true;
}

void Traverse(const List * plist, void(*pfun)(Item item))
{
	Node * pnode = plist->head;
	while (pnode != NULL)
	{
		(*pfun)(pnode->item);
		pnode = pnode->next;
	}
}

void EmptyTheList(List * plist)
{
	Node * psave;
	while (plist->head != NULL)
	{
		psave = plist->head->next;
		free(plist->head);
		plist->head = psave;
	}
}

static void CopyToNode(Item item, Node * pnode)
{
	pnode->item = item;
}

3.假设list.h(程序清单17.3)如下定义列表:

#define MAXZIZE 100

typedef struct list

{

Item entries[MAXAIZE];    /*项目数组*/

int items;        /*列表中项目的个数*/

}List;

根据这个定义,重写list.c(程序清单17.5)函数,并用films3.c(程序清单17.4)测试结果代码

/* 重写list.c */
#include <stdio.h>
#include <stdlib.h>
#include "list_17_3.h"

static void CopyToNode(Item item, Item * pnode);

void InitializeList(List * plist)
{
	plist->items = 0;
}

bool ListIsEmpty(const List * plist)
{
	if (plist->items == 0)
		return true;
	else
		return false;
}

bool ListIsFull(const List * plist)
{
	if (plist->items < MAXSIZE)
		return false;
	else
		return true;
}

unsigned int ListItemCount(const List * plist)
{
	return plist->items;
}

bool AddItem(Item item, List * plist)
{
	int i = plist->items;
	if (i < MAXSIZE)
	{
		CopyToNode(item, &plist->entries[i]);
		plist->items++;
		return true;
	}

	return false;
}

void Traverse(const List * plist, void(*pfun)(Item item))
{
	int i;
	for (i = 0; i < plist->items; i++)
		(*pfun)(plist->entries[i]);
}

void EmptyTheList(List * plist)
{
	plist->items = 0;
}

static void CopyToNode(Item item, Node * pnode)
{
	pnode->item = item;
}

4.重写mall.c(程序清单17.7)使其用两个队列模拟两个摊位。

//mall.c明明是程序清单17.9,书上搞错了???

/* 重写mall.c 用两个队列模拟二个摊位*/
/* 
	以分钟为单位程序有局限性。
	当有两个摊位时,因为每分钟才会有一个顾客生成,所以一个小时最多只可能有60个顾客
	就算每个顾客都要三分钟,那么两个摊位可以接客40人,再加上两个队列可容纳20人
	所以永远不可能出现被拒绝加入队列的情况。
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "queue.h"
#define MIN_PER_HR 60.0

bool newcustomer(double x);
Item customertime(long when);

int main(void)
{
	Queue line1, line2;
	Item temp;
	int hours;
	int perhour;
	long cycle, cyclelimit;
	long turnaways = 0;
	long customers = 0;
	long served1 = 0, served2 = 0;
	long sum_line1 = 0, sum_line2 = 0;
	int wait_time1 = 0, wait_time2 = 0;
	double min_per_cust;
	long line_wait1 = 0, line_wait2 = 0;

	InitQueue(&line1);
	InitQueue(&line2);

	srand((unsigned)time(NULL));

	puts("Case Study: Sigmund Lander‘s Advice Booth");
	puts("Enter the number of simulation hours:");
	scanf("%d", &hours);
	//以秒为单位
	cyclelimit = MIN_PER_HR * hours;

	puts("Enter the average number of customers per hour: ");
	scanf("%d", &perhour);
	min_per_cust = perhour / MIN_PER_HR;
	printf("%.2lf\n", min_per_cust);
	int i = 0;
	for (cycle = 0; cycle < cyclelimit; cycle++)
	{
		if (newcustomer(min_per_cust))
		{
			i++;
			if (QueueIsFull(&line1) && QueueIsFull(&line2))
				turnaways++;
			else
			{
				customers++;
				temp = customertime(cycle);
				if (QueueItemCount(&line1) < QueueItemCount(&line2))
					EnQueue(temp, &line1);
				else
					EnQueue(temp, &line2);
			}
		}
		if (wait_time1 <= 0 && !QueueIsEmpty(&line1))
		{
			DeQueue(&temp, &line1);
			wait_time1 = temp.processtime;
			line_wait1 += cycle - temp.arrive;
			served1++;
		}
		if (wait_time2 <= 0 && !QueueIsEmpty(&line2))
		{
			DeQueue(&temp, &line2);
			wait_time2 = temp.processtime;
			line_wait2 += cycle - temp.arrive;
			served2++;
		}
		if (wait_time1 > 0) wait_time1--;
		if (wait_time2 > 0)	wait_time2--;
		sum_line1 += QueueItemCount(&line1);
		sum_line2 += QueueItemCount(&line1);
	}
	if (customers > 0)
	{	//两个摊位总的营业情况
		printf("customers accepted: %ld\n", customers);
		printf("   custmers served: %ld\n", served1 + served2);
		printf("		 turnaways: %ld\n", turnaways);
		printf("average queue size: %.2f\n", (double)(sum_line1 + sum_line2) / cyclelimit);
		printf("average wait time: %.2f minutes\n", (double)(line_wait1 + line_wait2) / (served1 + served2));
	}
	else
		puts("No customers!");

	printf("i = %d\n", i);
	return 0;
}

bool newcustomer(double x)
{
	if (rand()*x / RAND_MAX < 1)
		return true;
	else
		return false;
}

Item customertime(long when)
{
	Item cust;

	cust.processtime = rand() % 3 + 1;
	cust.arrive = when;

	return cust;
}

5.编写一个程序,让您输入一个字符串。该程序将此字符串中的字符逐个地压入一个栈(请参见复习题5),然后弹出这些字符并显示。结果是将字符串按逆序显示。

/* stack.h -- 栈接口 */
#ifndef _STACK_H_
#define _STACK_H_
#include <stdbool.h>

typedef char Item;

typedef struct node
{
	Item item;
	struct node * next;
} Node;

typedef struct stack{
	Node * top;
	Node * bottom;
}Stack;

void InitStack(Stack * ps);
bool StackIsFull(const Stack * ps);
bool StackIsEmpty(const Stack * ps);
int StackItemCount(const Stack * ps);
bool push(Item item, Stack * ps);
bool Pop(Item * pitem, Stack * ps);

#endif
/* stack.c -- 栈相关函数定义 */
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"

static void CopyToNode(Item item, Node * pn);
static void CopyToItem(Node * pn, Item * pi);

void InitStack(Stack * ps)
{
	ps->bottom = ps->top = NULL;
}
bool StackIsFull(const Stack * ps)
{
	Node * temp;
	temp = (Node *)malloc(sizeof(Node));
	if (temp == NULL)
		return true;
	else
		free(temp);
	return false;
}
bool StackIsEmpty(const Stack * ps)
{
	return ps->top == NULL;
}
bool push(Item item, Stack * ps)
{
	Node * pnew;

	if (StackIsFull(ps))
		return false;
	pnew = (Node *)malloc(sizeof(Node));
	if (pnew == NULL)
	{
		fprintf(stderr, "Unable to allocate memory!\n");
		exit(1);
	}
	CopyToNode(item, pnew);
	if (StackIsEmpty(ps))
	{
		pnew->next = NULL;
		ps->bottom = pnew;
	}
	else
		pnew->next = ps->top;
	ps->top = pnew;

	return true;
}
bool Pop(Item * pitem, Stack * ps)
{
	Node * pt;

	if (StackIsEmpty(ps))
		return false;
	CopyToItem(ps->top, pitem);
	pt = ps->top;
	ps->top = ps->top->next;
	free(pt);
	if (ps->top == NULL)
		ps->bottom = NULL;
	return true;
}
static void CopyToNode(Item item, Node * pn)
{
	pn->item = item;
}
static void CopyToItem(Node * pn, Item * pi)
{
	*pi = pn->item;
}
/* test.c -- 测试栈,与stack.c一起编译 */
#include <stdio.h>
#include "stack.h"
#define STRLEN 80
int main(void)
{
	char str[STRLEN];
	Stack stack;
	int i;
	Item ch;

	InitStack(&stack);
	printf("请输入字符串:");
	gets(str);

	for (i = 0; str[i] != ‘\0‘ && i < STRLEN; i++)
		push(str[i], &stack);
	printf("出栈输出字符串:");
	while (Pop(&ch, &stack))
		putchar(ch);

	putchar(‘\n‘);

	return 0;
}

6.写一个接受3个参数的函数。这3个参数为:存有已排序的整数的数组名,数组元素个数和要查找的整数。如果该整数在数组中,函数返回1;否则返回0。函数用折半搜索法实现。

/*
折半查找1-99中有哪些数包含在数组中
*/

#include <stdio.h>
#include <stdbool.h>

int search(int table[], int max, int number);

#define M 10

//前提条件:数组要求有序排列
int table[M] = { 1, 3, 5, 6, 9, 13, 19, 21, 34, 45 };

int main(void)
{
	int i ;
	for (i = 0; i<100; i++)
	if (search(table, M-1, i))
		printf("%d ", i);
	printf("\n");
	return 0;
}

int search(int table[], int max, int number)
{
	int min = 0, half;
	int i = 0;
	while (1)
	{
		i++;
		half = (min + max) / 2;		//最小数加最大数除以2等于这两个数的中间数
		if (number > table[half])
		{
			min = half + 1;			//确定最小数
		}
		else
		{
			if (number < table[half])
				max = half - 1;		//确定最大数
			else
				return true;
		}			

		if (min + 1 == max)
		{	//如果重合说明中中间已没有数,直接判断临的两个数
			if (number == table[min] || number == table[max])
				return true;
			else
				return false;
		}
	}
}

7.编写一个程序,能打开、读入一个文本文件并统计文件中每个单词出现的次数。用改进的二叉搜索树存储单词及出现的次数。程序读入文件后,会提供一个有三个选项的菜单。第一个选项为列出所有的单词连同其出现的次数。第二个选项为让您输入一个单词,程序报告该单词在文件中出现的次数。第三个选项为退出。

/* tree.h */
#ifndef _TEST_H_
#define _TEST_H_
#include <stdbool.h>
#define WORDLEN 55
typedef struct item
{
	char word[WORDLEN];
	int word_size;
}Item;
typedef struct node
{
	Item item;
	struct node * left;
	struct node * right;
}Node;
typedef struct tree
{
	Node * root;
	int node_size;
}Tree;
void InitTree(Tree * pt);
bool TreeIsEmpty(Tree * pt);
bool TreeIsFull(Tree * pt);
int TreeItemCount(const Tree * pt);
bool AddItem(const Item * pi, Tree * pt);
Node * InItem(const Item * pi, Tree * pt);
bool DeItem(const Item * pi, Tree * pt);
void traverse(const Tree * pt, void(* pfun)(Item item));
void DeAll(Tree * pt);
#endif
/* tree.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tree.h"

typedef struct pair
{
	Node * parent;
	Node * child;
}Pair;

/* 局部函数 */
static Node * MakeNode(const Item * pi);
static bool ToLeft(const Item * i1, const Item * i2);
static bool ToRight(const Item * i1, const Item * i2);
static void AddNode(Node * new_node, Node * root);
static void InOrder(const Node * root, void(*pfun)(Item item));
static Pair SeekItem(const Item * pi, const Tree * ptree);
static void DeNode(Node ** ptr);
static void DeAllNodes(Node * ptr);

void InitTree(Tree * pt)
{
	pt->node_size = 0;
	pt->root = NULL;
}
bool TreeIsEmpty(Tree * pt)
{
	return pt->root == NULL;
}
bool TreeIsFull(Tree * pt)
{
	Node * ptemp;
	ptemp = (Node *)malloc(sizeof(Node));
	if (ptemp == NULL)
		return true;
	else
		return false;
}
int TreeItemCount(const Tree * pt)
{
	return pt->node_size;
}
bool AddItem(const Item * pi, Tree * pt)
{
	Node * new_node;
	if (TreeIsFull(pt))
	{
		fprintf(stderr, "Tree is full\n");
		return false;
	}
	new_node = MakeNode(pi);
	if (new_node == NULL)
	{
		fprintf(stderr, "Couldn‘t create node\n");
		return false;
	}
	if (SeekItem(pi, pt).child != NULL)
	{
		SeekItem(pi, pt).child->item.word_size++;
		free(new_node);
		return true;
	}
	if (pt->root == NULL)
		pt->root = new_node;
	else
		AddNode(new_node, pt->root);
	pt->node_size++;
	return true;
}
Node * InItem(const Item * pi, Tree * pt)
{
	return SeekItem(pi, pt).child;
}
bool DeItem(const Item * pi, Tree * pt)
{
	Pair look;
	look = SeekItem(pi, pt);
	if (look.child == NULL)
		return false;
	if (look.parent == NULL)
		DeNode(&pt->root);
	else if (look.parent->left == look.child)
		DeNode(&look.parent->left);
	else if (look.parent->right == look.child)
		DeNode(&look.parent->right);
	pt->node_size--;
	return true;
}
void traverse(const Tree * pt, void(*pfun)(Item item))
{
	if (pt != NULL)
		InOrder(pt->root, pfun);
}
void DeAll(Tree * pt)
{
	if (pt != NULL)
		DeAllNodes(pt->root);
	pt->node_size = 0;
	pt->root = NULL;
}

static Node * MakeNode(const Item * pi)
{
	Node * new_node;
	new_node = (Node *)malloc(sizeof(Node));
	if (new_node != NULL)
	{
		new_node->item = *pi;
		new_node->left = NULL;
		new_node->right = NULL;
	}
	return new_node;
}
static bool ToLeft(const Item * i1, const Item * i2)
{
	if (strcmp(&i1->word[0], &i2->word[0]) < 0)
		return true;
	else
		return false;
}
static bool ToRight(const Item * i1, const Item * i2)
{
	if (strcmp(&i1->word[0], &i2->word[0]) > 0)
		return true;
	else
		return false;
}
static void AddNode(Node * new_node, Node * root)
{
	if (ToLeft(&new_node->item, &root->item))
	{
		if (root->left == NULL)
			root->left = new_node;
		else
			AddNode(new_node, root->left);
	}
	else
	{
		if (ToRight(&new_node->item, &root->item))
		{
			if (root->right == NULL)
				root->right = new_node;
			else
				AddNode(new_node, root->right);
		}
	}
}
static void InOrder(const Node * root, void(*pfun)(Item item))
{
	if (root != NULL)
	{
		InOrder(root->left, pfun);
		(*pfun)(root->item);
		InOrder(root->right, pfun);
	}
}
static Pair SeekItem(const Item * pi, const Tree * ptree)
{
	Pair look;
	look.parent = NULL;
	look.child = ptree->root;

	if (look.child == NULL)
		return look;
	while (look.child != NULL)
	{
		if (ToLeft(pi, &look.child->item))
		{
			look.parent = look.child;
			look.child = look.child->left;
		}
		else
		{
			if (ToRight(pi, &look.child->item))
			{
				look.parent = look.child;
				look.child = look.child->right;
			}
			else
				break;
		}
	}
	return look;
}
static void DeNode(Node ** ptr)
{	//形参ptr是父节点中用来保存子节点地址的变量,实参让其初始化为父节点的指针域
	//*ptr是子节点本身,也就是要删除的节点。
	//子节点删除后,将*ptr指向新的节点也就更改了父节点的指针域。
	//ptr的值只要不更改,*ptr永远是父节点的指向。
	Node * temp;
	puts((*ptr)->item.word);
	if ((*ptr)->left = NULL)
	{
		temp = *ptr;
		*ptr = (*ptr)->right;
		free(temp);
	}
	else
	{
		if ((*ptr)->right == NULL)
		{
			temp = *ptr;
			*ptr = (*ptr)->left;
			free(temp);
		}
		else
		{
			temp = (*ptr)->left;
			while (temp->right != NULL)
				temp = temp->right;
			temp->right = (*ptr)->right;
			temp = *ptr;
			*ptr = (*ptr)->left;
			free(temp);
		}
	}
}
static void DeAllNodes(Node * root)
{
	Node * temp;
	if (root != NULL)
	{
		/*
		保存右子树指针
		找到左子树为空的节点,释放节点内存
		用保存的右子指针找左子树为空的节点,释放内存
		直到右子树指针为空
		*/
		temp = root->right;
		DeAllNodes(root->left);
		free(root);
		DeAllNodes(temp);
	}

}
/* test.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "tree.h"

void menu(void);
int get_ch(char * str);
void printItem(Item item);

int main(void)
{
	FILE * fp;
	Tree tree;
	Item word = { {‘\0‘}, 1 };
	char ch;
	bool n = false;

	InitTree(&tree);
	if ((fp = fopen("f:\\test\\emma.txt", "r")) == NULL)
	{
		fprintf(stderr, "文件打开失败\n");
		exit(EXIT_FAILURE);
	}

	while ((ch=getc(fp)) != EOF)
	{
		int i = 0;
		while (isalpha(ch))
		{
			word.word[i++] = ch;
			ch = getc(fp);
		}
		if (i > 0)
		{
			word.word[i++] = ‘\0‘;
			AddItem(&word, &tree);
		}
		//putchar(‘a‘);
	}
	putchar(‘\n‘);
	fclose(fp);
	menu();
	while ((ch = get_ch("abq")) != ‘q‘)
	{
		if (ch == ‘a‘)
		{
			puts("包含的单词\t\t单词出现的次数");
			traverse(&tree, printItem);
		}
		if (ch == ‘b‘)
		{
			puts("请输入要查找的单词:");
			scanf("%s", word.word);
			while (getchar() != ‘\n‘)
				;
			if (InItem(&word, &tree))
			{
				printf("单词%s在文件中出现%d次\n",
					word.word, InItem(&word, &tree)->item.word_size);
			}
			else
				printf("文件中没有找到单词%s\n", word.word);

		}
		printf("\n");
		menu();
	}
}

void menu(void)
{
	puts("请输入选项:");
	puts("a)列出所有的单词连同其出现的次数");
	puts("b)输入一个单词,程序报告该单词在文件中出现的次数");
	puts("q)退出程序");
}
int get_ch(char * str)
{
	int ch;

	ch = getchar();
	while (getchar() != ‘\n‘)
		;
	while (strchr(str, ch) == NULL)
	{

		printf("请输入正确的选项%s:", str);
		ch = getchar();
		while (getchar() != ‘\n‘)
			;
	}

	return ch;
}
void printItem(Item item)
{
	printf("%10s\t\t%14d\n", item.word, item.word_size);
}

8.修改宠物俱乐部程序,使所有同名的宠物存储在相同节点中的一个列表中。当用户选择查找一个宠物时,程序要求用户给出宠物名,而后列出所有具有此名字的宠物(连同它们的种类)。

// tree.h -- 二叉搜索树接口
#ifndef _TREE_H
#define _TREE_H
#include <stdbool.h>
#define TREEMAX 20

typedef struct item
{
	char petname[20];
	char petkind[20];
}Item;

typedef struct node_list
{
	Item item;
	struct node_list * next;
}List;
typedef struct node_tree
{
	List * list;				//同名宠物的项目列表
	int list_size;			//列表中项目个数
	struct node_tree * left;		//指向左分支的指针
	struct node_tree * right;	//指向右分支的指针
}Node;

typedef struct tree
{
	Node * root;	//指向树根的指针
	int size;		//树中项目的个数
}Tree;

void InitTree(Tree * ptree);
bool TreeIsEmpty(const Tree * ptree);
bool TreeIsFull(const Tree * ptree);
int TreeItemCount(const Tree * ptree);
bool InTree(const Item * pi, const Tree * ptree);
bool AddTreeItem(const Item * pi, Tree * ptree);
bool DeleteItem(const Item * pi, Tree * ptree);
void Traverse(const Tree * ptree, void(*pfun)(List * list));
void DeleteAll(Tree * ptree);

#endif
//tree.c -- 接口函数定义
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tree.h"

typedef struct pair
{
	Node * parent;
	Node * child;
}Pair;

//局部函数声明
static bool AddListItem(const Item * pi, Node * root);
static List * MakeListNode(const Item * pi);
static Node * MakeTreeNode(const Item * pi);
static void AddTreeNode(Node * new_node, Node * root);
static Pair SeekItem(const Item * pi, const Tree * ptree);
static bool ToLeft(const Item * i1, const Item * i2);
static bool ToRight(const Item * i1, const Item * i2);
static bool SeekListItem(const Item * pi, List * pl);
static void DeNode(const Item * pi, Node ** ptr);
static List * DeListNode(const Item * pi, List * pl);
static void InOrder(const Node * root, void(*pfun)(List * list));
static void DeleteAllNodes(Node * root);
static void DeList(List * list);
static void DeleteAllList(Node * root);

//局部函数定义
static bool AddListItem(const Item * pi, Node * root)
{	//OK
	List * new_listnode, *temp = root->list;
	new_listnode = MakeListNode(pi);
	if (new_listnode == NULL)
	{
		fprintf(stderr, "新的成员生成失败\n");
		return false;
	}
	while (NULL != temp->next)
		temp = temp->next;
	temp->next = new_listnode;
	root->list_size++;
	return true;
}
static List * MakeListNode(const Item* pi)
{	//OK
	List * new_list;
	new_list = (List *)malloc(sizeof(List));
	if (new_list != NULL)
	{
		new_list->item = *pi;
		new_list->next = NULL;
	}
	return new_list;
}
static Node * MakeTreeNode(const Item * pi)
{	//OK
	Node * new_node;
	List * new_list_node;

	new_list_node = MakeListNode(pi);
	if (new_list_node == NULL)
		return NULL;
	new_node = (Node *)malloc(sizeof(Node));
	if (new_node != NULL)
	{
		new_node->list = new_list_node;
		new_node->list_size = 1;
		new_node->left = NULL;
		new_node->right = NULL;
	}
	return new_node;
}
static void AddTreeNode(Node * new_node, Node * root)
{	//OK
	if (ToLeft(&new_node->list->item, &root->list->item))
	{
		if (NULL == root->left)
			root->left = new_node;
	}
	else if (ToRight(&new_node->list->item, &root->list->item))
	{
		if (NULL == root->right)
			root->right = new_node;
	}

}
static bool ToLeft(const Item * i1, const Item * i2)
{	//OK
	if (strcmp(i1->petname, i2->petname) < 0)
		return true;
	return false;
}
static bool ToRight(const Item * i1, const Item * i2)
{	//OK
	if (strcmp(i1->petname, i2->petname) > 0)
		return true;
	return false;
}
static bool SeekListItem(const Item * pi, List * pl)
{	//OK
	List * temp = pl;
	while (NULL != temp)
	{
		if (strcmp(pi->petkind, temp->item.petkind) == 0)
			return true;
		temp = temp->next;
	}

	return false;
}
static Pair SeekItem(const Item * pi, const Tree * ptree)
{	//OK
	Pair look;
	look.parent = NULL;
	look.child = ptree->root;

	if (NULL == look.child)
		return look;
	while (NULL != look.child)
	{
		if (ToLeft(pi, &look.child->list->item))
		{
			look.parent = look.child;
			look.child = look.child->left;
		}
		else if (ToRight(pi, &look.child->list->item))
		{
			look.parent = look.child;
			look.child = look.child->right;
		}
		else
		{
			break;
		}

	}
	return look;
}
static void DeNode(const Item * pi, Node ** ptr)
{	//OK
	Node * temp;
	if (1 == (*ptr)->list_size)
	{	//列表内只有一个项目,删整个节点
		if (NULL == (*ptr)->left)
		{
			temp = *ptr;
			*ptr = (*ptr)->right;
			free(temp);
		}
		else if (NULL == (*ptr)->right)
		{
			temp = *ptr;
			*ptr = (*ptr)->left;
			free(temp);
		}
		else
		{
			temp = (*ptr)->left;
			while (NULL != temp->right)
				temp = temp->right;
			temp->right = (*ptr)->right;
			temp = *ptr;
			*ptr = (*ptr)->left;
			free(temp);
		}
	}
	else if ((*ptr)->list_size > 1)
	{	//列表内有多个项目,删列表中的一个项目
		(*ptr)->list = DeListNode(pi, (*ptr)->list);
		(*ptr)->list_size--;
	}
}
static List * DeListNode(const Item * pi, List * pl)
{	//OK
	List * phead = pl;	//保存链表头指针
	List * temp;
	if (strcmp(pi->petkind, phead->item.petkind) == 0)
	{
		phead = pl->next;
		free(pl);
	}
	else
	{
		do
		{
			temp = pl;
			pl = pl->next;
		} while (strcmp(pi->petkind, pl->item.petkind) != 0);

		temp->next = pl->next;
		free(pl);
	}
	return phead;
}
static void InOrder(const Node * root, void(*pfun)(List * list))
{	//OK
	if (root != NULL)
	{
		InOrder(root->left, pfun);
		(*pfun)(root->list);
		InOrder(root->right, pfun);
	}
}
static void DeleteAllNodes(Node * root)
{
	Node * temp = root;

	if (root != NULL)
	{
		temp = root->right;
		DeleteAllNodes(root->left);
		DeList(root->list);
		free(root);
		DeleteAllNodes(temp);
	}
}
static void DeList(List * list)
{
	List * temp;

	while (list != NULL)
	{
		temp = list;
		list = list->next;
		free(temp);
	}

}

//全局函数定义
void InitTree(Tree * ptree)
{	//OK
	ptree->root = NULL;
	ptree->size = 0;
}
bool TreeIsEmpty(const Tree * ptree)
{	//OK
	return ptree->root == NULL;
}
bool TreeIsFull(const Tree * ptree)
{	//OK
	return ptree->size >= TREEMAX;
}
int TreeItemCount(const Tree * ptree)
{	//OK
	return ptree->size;
}
bool InTree(const Item * pi, const Tree * ptree)
{
	Pair look = SeekItem(pi, ptree);
	return look.child != NULL && SeekListItem(pi, look.child->list);
}
bool AddTreeItem(const Item * pi, Tree * ptree)
{	//OK
	Node * new_node;
	Pair seek;

	if (TreeIsFull(ptree))
	{
		fprintf(stderr, "Tree is ull\n");
		return false;
	}
	seek = SeekItem(pi, ptree);
	if (seek.child != NULL)
	{
		if (AddListItem(pi, seek.child));
		return true;
		return false;
	}
	new_node = MakeTreeNode(pi);
	if (new_node == NULL)
	{
		fprintf(stderr, "Couldn‘t create node\n");
		return false;
	}
	if (ptree->root == NULL)
		ptree->root = new_node;
	else
		AddTreeNode(new_node, ptree->root);
	ptree->size++;

	return true;
}
bool DeleteItem(const Item * pi, Tree * ptree)
{	//OK
	Pair look;
	look = SeekItem(pi, ptree);
	int i = TreeItemCount(ptree);
	if (NULL == look.child)
		return false;	//是否找到同名项
	if (!SeekListItem(pi, look.child->list))
		return false;	//是否找到同类项
	DeNode(pi, &look.child);
	int j = TreeItemCount(ptree);
	if (i == j)
		ptree->size--;
	if (ptree->size == 0)
		ptree->root = NULL;

	return true;
}
void Traverse(const Tree * ptree, void(*pfun)(List * list))
{	//OK
	if (ptree->root != NULL)
		InOrder(ptree->root, pfun);
}
void DeleteAll(Tree * ptree)
{
	if (ptree->root != NULL)
		DeleteAllNodes(ptree->root);
	ptree->size = 0;
}
//test_tree.c -- 测试二叉搜索树
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "tree.h"

char menu(void);					//显示菜单,判定用用户输入
void addpet(Tree * pt);				//添加内容
void droppet(Tree * pt);			//删除项目
void showpets(const Tree * pt);		//显示整个树
void findpet(const Tree * pt);		//搜索某个项目是否在树中
void printitem(List * list);			//打印项目内容
void uppercase(char * str);			//转换大写
int ListItemCount(Node * root);

int main(void)
{
	Tree pets;		//定义树变量
	char choice;
	int conut=0, temp=0;

	InitTree(&pets);
	while ((choice = menu()) != ‘q‘)
	{
		switch (choice)
		{
		case ‘a‘: addpet(&pets);
			break;
		case ‘l‘: showpets(&pets);
			break;
		case ‘f‘: findpet(&pets);
			break;
		case ‘n‘: 
			conut = ListItemCount(pets.root);
			conut -= temp;
			temp += conut;
			printf("%d pets in club\n", conut);
			break;
		case ‘d‘: droppet(&pets);
			break;
		default: puts("Switching error");
		}
	}
	DeleteAll(&pets);
	puts("Bye.");

	return 0;
}

char menu(void)
{
	int ch;

	puts("Nerfville pet Club Membership Program");
	puts("Enter the letter corresponding to your choice: ");
	puts("a)add a per		l)show list of pets");
	puts("n)number of pets	f)find pets");
	puts("d)delete apet		q)quit");
	while ((ch = getchar()) != EOF)
	{
		while (getchar() != ‘\n‘)	//丢弃输入行的剩余部分
			continue;
		ch = tolower(ch);
		if (strchr("alrfndq", ch) == NULL)
			puts("Please enter an a, l, f, n, d, or q: ");
		else
			break;
	}
	if (ch == EOF)		//令EOF导致程序退出
		ch = ‘q‘;

	return ch;
}

void addpet(Tree * pt)
{
	Item temp;

	if (TreeIsFull(pt))		//树已满
		puts("No room in the club!");	//提示无空间
	else
	{	//
		puts("Please enter name of pet: ");
		gets(temp.petname);
		puts("Please enter pet kind: ");
		gets(temp.petkind);
		uppercase(temp.petname);
		uppercase(temp.petkind);
		AddTreeItem(&temp, pt);
	}
}

void showpets(const Tree * pt)
{
	if (TreeIsEmpty(pt))
		puts("No enteries!");
	else
		Traverse(pt, printitem);
}

void printitem(List * list)
{
	while (list != NULL)
	{
		printf("pet: %-19s kind: %-19s\n", list->item.petname,
			list->item.petkind);
		list = list->next;
	}
}

void findpet(const Tree * pt)
{
	Item temp;

	if (TreeIsEmpty(pt))
	{
		puts("No entries!");
		return;
	}

	puts("Please enter name of pet you wish to find: ");
	gets(temp.petname);
	puts("Please enter pet kind: ");
	gets(temp.petkind);
	uppercase(temp.petname);
	uppercase(temp.petkind);
	printf("%s the %s ", temp.petkind, temp.petname);
	if (InTree(&temp, pt))
		printf("is a member.\n");
	else
		printf("is not a member .\n");
}

void droppet(Tree * pt)
{
	Item temp;

	if (TreeIsEmpty(pt))
	{
		puts("No entries!");
		return;
	}
	puts("Please enter name of pet you wish to delete: ");
	gets(temp.petname);
	puts("Please enter pet dind: ");
	gets(temp.petkind);
	uppercase(temp.petname);
	uppercase(temp.petkind);
	printf("%s the %s ", temp.petname, temp.petkind);

	if (DeleteItem(&temp, pt))
		printf("is dropped from the club.\n");
	else
		printf("is not a member.\n");
}

void uppercase(char * str)
{
	while (*str)
	{
		*str = toupper(*str);
		str++;
	}
}

int ListItemCount(Node * root)
{
	static int conut = 0;

	if (root != NULL)
	{
		ListItemCount(root->left);
		conut += root->list_size;
		ListItemCount(root->right);
	}

	return conut;
}
时间: 2024-11-06 22:32:58

C Primer Plus (第五版) 第十七章 高级数据显示 编程练习的相关文章

C primer plus 第五版十二章习题

看完C prime plus(第五版)第十二章,随带完成了后面的习题. 1.不使用全局变量,重写程序清单12.4的程序. 先贴出12.4的程序,方便对照: 1 /* global.c --- 使用外部变量 */ 2 #include <stdio.h> 3 int units = 0; //一个外部变量 4 void critic(void); 5 int main(void) 6 { 7 extern int units; 8 9 printf ("How many pounds

C++primer(第五版)第二章的学习笔记(也有对部分习题的解答和指出c++11特性)

算术类型分为两类:整型(字符和bool在内)和浮点型. C/C++算术类型 类型 含义 最小尺寸 bool 布尔类型 未定义 char 字符 8位 wchar_t 宽字符 16位 char16_t Unicode字符 16位 char32_t Unicode字符 32位 short 短整型 16位 int  整型 16位 long 长整型 32位 long long 长整型 64位 unsigned long 无符号长整型 32位 double 双精度浮点数 10位有效数字 long doubl

C++ Primer【第五版】习题参考答案——第六章(函数)

本系列文章会不断更新,但是时间不能保证.另外基本上都是自己做的答案,仅供参考,如果有疑问欢迎交流. #include <iostream> #include <initializer_list> using namespace std; int test_Ex_6_27(std::initializer_list<int> li); int main() { cout << test_Ex_6_27({23,78,89,76,90}) << en

c++ primer(第五版)学习笔记及习题答案代码版(第十四章)重载运算与类型转换

笔记较为零散,都是自己不熟悉的知识点. 习题答案至于一个.h 和.cc 中,需要演示某一题直接修改 #define NUM****, 如运行14.30题为#define NUM1430: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful f

C++ Primer【第五版】习题参考答案——第五章(语句)

#include <iostream> #include <vector> #include <string> using namespace std; /******************************************************************* Ex_5_1: 空语句就是只含有一个分号的语句. 如果在程序的某个地方,语法上要求有一条语句,但是逻辑上不需要, 这时就需要一条空语句. Ex_5_2: 块就是由花括号包围的复合语句

c++ primer(第五版)学习笔记及习题答案代码版(第十一章)关联容器

笔记较为零散,都是自己不熟悉的知识点. 习题答案至于一个.cc 中,包含Chapter7.h头文件,读入文件包括./test ./rules .需要演示某一题直接修改 #define NUM****, 如运行11.23题为#define NUM1123: chapter 11 1.  关联容器不支持顺序容器的位置相关的操作,例如push_front或push_back.原因是关联容器中元素是根据关键字存储的,这些操作对 关联容器没有意义.而且关联容器也不支持构造函数或插入操作这些接收一个元素值和

c++ primer(第五版)学习笔记及习题答案代码版(第六章)函数

笔记较为零散,都是自己不熟悉的知识点. 习题答案至于一个.cc 中,编译需要包含Chapter6.h头文件. 需要演示某一题直接修改 #define NUM***, 如运行6.23题为#define NUM623: chapter 6 1. 形参初始化的机理与变量初始化一样. 当形参是引用类型时,它对应的实参被引用传递或者函数被传引用调用. 2. const和实参 void fcn(const int i){ /*fcn能够读取i,但是不能向i写值*/} void fcn(int i){ /*.

C++ Primer(第五版) 笔记 C01-02

C01 ++val; 优于 val++; 对数量不定的输入数据:while(cin>>value)... 遇到无效的输入或eof后,cin变为无效状态,条件变为假. 来自标准库的头文件用<>包围,不属于标准库的用""包围. 文件重定向工作:exename.exe <infile >outfile 点运算符:左侧运算对象是类类型的,右侧是该类型的成员. 参数 = 实参 = 值,形参指出调用函数可使用什么实参. 定义在函数内部的内置类型通常不初始化. C

《C++Primer》第五版习题详细答案--目录

作者:cosefy ps: 答案是个人学习过程的记录,仅作参考. <C++Primer>第五版习题答案目录 第一章:引用 第二章:变量和基本类型 第三章:字符串,向量和数组 第四章:表达式 原文地址:https://www.cnblogs.com/cosefy/p/12180771.html