1. 程式人生 > >C實現二叉樹

C實現二叉樹

建立介面

/*tree.h -- 二叉查詢樹*/
#pragma once                  //只編譯一次
#define SLEN 20

/*根據具體情況定義Item*/
typedef struct item
{
	char petname[SLEN];
	char petkind[SLEN];
}Item;

#define MAXITEMS 10
typedef struct trnode
{
	Item item;
	struct trnode *left;
	struct trnode *right;
}Trnode;

typedef struct tree
{
	Trnode *root;
	int size;
}Tree;


void InitializeTree(Tree *ptree);   //初始化

bool TreeIsEmpty(const Tree *ptree); //判斷是否為空

bool TreeIsFull(const Tree *ptree);  //判斷是否已滿

int TreeItemCount(const Tree *ptree);  //返回樹的項數

bool AddItem(const Item *pi, Tree *ptree); //新增項

bool InTree(const Item *pi, const Tree *ptree); //查詢

bool DeleteItem(const Item *pi, Tree *ptree); //刪除項

/*把函式應用於樹中的每一項(遍歷樹)*/
void Traverse(const Tree *ptree, void(*pfun)(Item item));

void DeleteAll(Tree *ptree);  //清空樹

實現介面

/*function.cpp,實現介面*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"tree.h"

/*區域性資料型別*/
typedef struct pair {   /*包含兩個指向樹節點的指標*/
	Trnode *child;     /*用於SeekItem()函式*/
	Trnode *parent;
}Pair;

/////////////////////////////////////////////////////
/*區域性函式的原型*/
static Trnode *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(Trnode *new_node, Trnode *root);
static void DeleteNode(Trnode **ptr);
static Pair SeekItem(const Item *pi, const Tree *ptree);
static void InOrder(const Trnode *root, void(*pfun)(Item item));
static void DeleteAllNodes(Trnode *root);
//////////////////////////////////////////////////////

/*為新節點分配記憶體  MakeNode()函式*/
static Trnode * MakeNode(const Item *pi) 
{
	Trnode *new_node;
	new_node = (Trnode *)malloc(sizeof(Trnode));
	if (new_node != NULL)
	{
		new_node->item = *pi;
		new_node->left = NULL;
		new_node->right = NULL;
	}
	return new_node;
}

/*新增節點到非空樹中   AddNode()函式*/
static bool ToLeft(const Item *i1, const Item *i2)
{
	int comp1;
	if ((comp1 = strcmp(i1->petname, i2->petname)) < 0)
		return true;
	else if (comp1 == 0 && strcmp(i1->petkind, i2->petkind) < 0)
		return true;
	else
		return false;
}
static bool ToRight(const Item *i1, const Item *i2)
{
	int comp1;
	if ((comp1 = strcmp(i1->petname, i2->petname)) > 0)
		return true;
	else if (comp1 == 0 && strcmp(i1->petkind, i2->petkind) > 0)
		return true;
	else
		return false;
}
static void AddNode(Trnode *new_node, Trnode *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);
	}
	else 
	{
		fprintf(stderr, "location error in AddNode()\n");
		exit(1);
	}
}

/*查詢項   SeekItem()函式*/
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;   //look,child目標項的節點
	}
	return look;
}
/*刪除一個節點,用於DeleteItem()*/
static void DeleteNode(Trnode **ptr)
/*ptr是指向目標節點的父節點指標成員的地址*/
{
	Trnode *temp;
	if ((*ptr)->left == NULL)
	{
		temp = *ptr;
		*ptr = (*ptr)->right;
		free(temp);
	}
	else if ((*ptr)->right == NULL)
	{
		temp = *ptr;
		*ptr = (*ptr)->left;
		free(temp);
	}
	else /*被刪除的節點有兩個子節點*/
	{
		/*找到重新連線右子樹的位置*/
		for (temp = (*ptr)->left; temp->right != NULL; temp = temp->right)
			continue;
		temp->right = (*ptr)->right;
		temp = *ptr;
		*ptr = (*ptr)->left;
		free(temp);
	}
}
/*InOrder()用於Traverse()*/
static void InOrder(const Trnode *root, void(*pfun)(Item item))
{
	if (root != NULL)
	{
		InOrder(root->left, pfun);
		(*pfun)(root->item);
		InOrder(root->right, pfun);
	}
}
/*DeleteAllNodes()用於DeleteAll()*/
static void DeleteAllNodes(Trnode *root) //主要作用為釋放記憶體
{
	Trnode *pright;
	if (root != NULL)
	{
		pright = root->right;
	    DeleteAllNodes(root->left);
	    free(root);
	    DeleteAllNodes(pright);
	}
}
//-------------------------------------------------------------------------------

/*$初始化*/
void InitializeTree(Tree *ptree)
{
	ptree->root = NULL;
	ptree->size = 0;
}

/*$判斷樹是否為空*/
bool TreeIsEmpty(const Tree *ptree)
{
	if (ptree->root == NULL)
		return true;
	else
		return false;
}

/*$判斷樹是否已滿*/
bool TreeIsFull(const Tree *ptree)
{
	if (ptree->size == MAXITEMS)
		return true;
	else
		return false;
}

/*$返回樹的項數*/
int TreeItemCount(const Tree *ptree)
{
	return ptree->size;
}

/*$新增項*/
bool AddItem(const Item *pi, Tree *ptree)  
{
	Trnode *new_node;
	if (TreeIsFull(ptree))
	{
		fprintf(stderr, "Tree is full!\n");
		return false;
	}
	if (SeekItem(pi, ptree).child != NULL)
	{
		fprintf(stderr, "Attempted to add duplicate item\n");
		return false;
	}
	new_node = MakeNode(pi);
	if (new_node == NULL)
	{
		fprintf(stderr, "couldn't create node\n");
		return false;
	}
	/*成功建立了一個新的節點*/
	ptree->size++;
	if (ptree->root == NULL)    /*情況1:樹為空*/
		ptree->root = new_node; /*新節點是根節點*/
	else						/*情況2:樹不為空*/
		AddNode(new_node, ptree->root);/*在樹中新增一個節點*/
	return true;
}

/*$查詢項*/
bool InTree(const Item *pi, const Tree *ptree)
{
	return (SeekItem(pi, ptree).child == NULL )? false : true;
}

/*$刪除一個項(承接上面,主要功能為將節點與特定項關聯)*/
bool DeleteItem(const Item *pi, Tree *ptree)
{
	Pair look;
	look = SeekItem(pi, ptree);
	if (look.child == NULL)
		return false;
	if (look.parent == NULL) //刪除根節點
		DeleteNode(&ptree->root);//此時根節點即為所尋找的節點
	else if (look.parent->left == look.child)
		DeleteNode(&look.parent->left);
	else
		DeleteNode(&look.parent->right);
	ptree->size--;
	return true;
}

/*$遍歷樹*/
void Traverse(const Tree *ptree, void(*pfun)(Item item))
{
	if (ptree != NULL)
		InOrder(ptree->root, pfun);
}

/*$清空樹*/
void DeleteAll(Tree *ptree)
{
	if (ptree != NULL)
		DeleteAllNodes(ptree->root);
	ptree->root = NULL;
	ptree->size = 0;
}

使用介面
/*petclub.cpp--使用二叉樹*/
#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(Item item);
void uppercase(char *str);
char *s_gets(char *st, int n);

int main()
{
	Tree pets;
	char choice;
	InitializeTree(&pets);
	while ((choice = menu()) != 'q')
	{
		switch (choice)
		{
		case 'a':addpet(&pets);break;	
		case 'l':showpets(&pets); break;
		case 'f':findpet(&pets); break;
		case 'n':printf("%d pets in club\n", TreeItemCount(&pets));
			break;
		case 'd':droppet(&pets); break;
		default:puts("Switching error");
		}
	}
	DeleteAll(&pets);
	puts("Bye!");
	return 0;
}

//
char menu(void)
{
	int ch;
	puts("Enter the letter corresponding to your choice:");
	puts("a.add a pet          l.show list of pets");
	puts("n.number of pets     f.find pets");
	puts("d.delete a pet       q.quit");
	while ((ch = getchar()) != EOF)
	{
		while (getchar() != '\n')
			continue;
		ch = tolower(ch);
		if (strchr("alnfdgq", ch) == NULL)
			puts("please enter an a,l,n,f,d,g,q:");
		else
			break;
	}
	if (ch == 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:");
		s_gets(temp.petname, SLEN);
		puts("Please enter petkind:");
		s_gets(temp.petkind, SLEN);
		uppercase(temp.petname);
		uppercase(temp.petkind);
		AddItem(&temp, pt);
	}
}

void showpets(const Tree *pt)
{
	if (TreeIsEmpty(pt))
		puts("No entries!");
	else
		Traverse(pt, printitem);
}
void printitem(Item item)
{
	printf("Pet:%-19s  kind:%-19s\n", item.petname, item.petkind);
}

void findpet(const Tree *pt)
{
	Item temp;
	if (TreeIsEmpty(pt))
	{
		puts("empty!");
		return;
	}
	puts("Please enter name:");
	s_gets(temp.petname, SLEN);
	puts("And then enter kind:");
	s_gets(temp.petkind, SLEN);
	uppercase(temp.petname);
	uppercase(temp.petkind);
	printf("%s the %s", temp.petname, temp.petkind);
	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 members.");
		return;
	}
	puts("Enter the name:");
	s_gets(temp.petname, SLEN);
	puts("Then enter kind:");
	s_gets(temp.petkind, SLEN);
	uppercase(temp.petname);
	uppercase(temp.petkind);
	printf("%s the %s", temp.petname, temp.petkind);
	if (DeleteItem(&temp, pt))
		printf("Done!\n");
	else
		puts("Fault!");
}

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

char *s_gets(char *st, int n)
{
	char *ret_val;
	char *find;
	ret_val = fgets(st, n, stdin);
	if (ret_val)
	{
		find = strchr(st, '\n'); //查詢換行符
		if (find)
			*find = '\0';     //在此處放置一個空字元
		else
			while (getchar() != '\n')
				continue;      //處理輸入行的剩餘內容
	}
	return ret_val;
}