數據結構之二叉排序樹的基本操作

前言

二叉排序樹,又稱爲二叉查找樹,它具有以下特點:
若它的左子樹不空,則左子樹所有結點值均小於它的根結點的值
若它的右子樹不空,則右子樹所有結點值均大於它的根結點的值
它的左,右子樹也分別爲二叉排序樹
可以爲空
前提是二叉樹,然後也採用了遞歸的定義方法

二叉排序樹中序遍歷就一有序表

構造一顆二叉樹,就是把一無序的順序表變爲有序的數集,中序遍歷二叉排序表就是一有序的表,其目的,並不是爲了排序,而是爲了提高查找和刪除關鍵字的速度。

1.關鍵字

二叉排序樹的結構體定義和二叉樹的結構體定義完全一樣
我們存儲的數據都是關鍵字,說白了就是編號,查找的時候也是,因此在本篇中關鍵字是唯一的,不能出現兩個相同的關鍵字。

2.二叉排序樹的查找操作

查找函數,我們定義爲一個可遞歸運行的函數,函數調用時的語句爲:SearchBT(T,key,f,p);參數T爲一個二叉鏈表,key爲查找的關鍵字,f爲指向T的雙親,p爲了得到查找到的結點位置。
代碼如下:

Status SearchBT(BTree T,TElemType key,BTree f,BTree *p)
{
	if(!T)//查找不成功
	{
		*p = f;
		return FALSE;
	}
	else if(key == T->data)//查找成功
	{
		*p = T;
		return TRUE;
	}
	else if(key < T->data)
	{
		return SearchBT(T->lchild,key,T,p);
	}
	else
		return SearchBT(T->rchild,key,T,p);
}

2.二叉排序樹的插入操作

只有查得不到的時候,纔會進行插入操作,並且將關鍵字放到樹中合適的位置。
代碼如下:

Status InsertBT(BTree *T,TElemType key)
{
	BTree p,s;
	if(!SearchBT(*T,key,NULL,&p))//查找失敗
	{
		s = (BTree)malloc(sizeof(BTNode));
		s->data = key;
		s->lchild = s->rchild = NULL;
		if(!p)
			*T = s;//插入s爲新的根結點
		else if(key < p->data)
			p->lchild = s;//插入s爲左孩子
		else
			p->rchild = s;//插入s爲右孩子
		return TRUE;
	}
	else
		return FALSE;
}

3.二叉排序樹的刪除操作

刪除操作分爲三種情況
1.要刪除的結點只有左子樹,刪除後,將他的左子樹整個移動到結點位置

2.要刪除的結點只有右子樹,刪除後,將他的右子樹整個移動到結點位置

3.要刪除的結點既有左子樹又有右子樹。找到此結點p的有序直接前驅(或直接後驅)s,用s來替換結點p。然後再刪除結點s。

代碼如下

Status Delete(BTree *p)
{
	BTree q,s;
	if((*p)->rchild == NULL)//右子樹空只需連接它的左子樹
	{
		q = *p; *p = (*p)->lchild; free(q);
	}
	else if((*p)->lchild == NULL)//左子樹空只需連接它的右子樹
	{
		q = *p; *p = (*p)->rchild; free(q);
	}
	else//左右子樹均不空
	{
		q = *p; s = (*p)->lchild;
		while(s->rchild)//轉左,然後向右到盡頭
		{
			q = s;s = s->rchild;
		}
		(*p)->data = s->data;
		if(q != *p)
			q->rchild = s->lchild;//重接q的右子樹
		else
			q->lchild = s->lchild;//重接q的左子樹
		free(s);
	}
	return TRUE;
}

4.總結

二叉排序樹其實就是一種把無序的順序表變爲一個有序表,二叉排序樹中序遍歷就是有序表。
查找利用了類似二分查找的原理

完整代碼

以數組
a[10] = {62,88,58,47,35,73,51,99,37,93};
爲例:

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

#define TRUE  1
#define FALSE 0
typedef int Status;
typedef int TElemType;

typedef struct BTNode
{
	TElemType data;
	struct BTNode *lchild,*rchild;
}BTNode,*BTree;

Status SearchBT(BTree T,TElemType key,BTree f,BTree *p);//查找算法
Status InsertBT(BTree *T,TElemType key);//插入算法
Status Delete(BTree *p);//刪除數據算法
Status DeleteBT(BTree *T,TElemType key);//刪除算法
void InOrderTraverse(BTree T);//中序遍歷二叉樹

int main()
{
	int i,x,n,m;
	BTree p = NULL;
	BTree T = NULL;
	int a[10] = {62,88,58,47,35,73,51,99,37,93};
	for(i=0;i<10;i++)
	{
		InsertBT(&T,a[i]);
	}

	while(1)
	{
		printf("1.中序遍歷 2.刪除算法 3.添加算法 4.查找算法\n");
		scanf("%d",&n);
		switch(n)
		{
		case 1:
			printf("中序遍歷二叉樹\n");
			InOrderTraverse(T);
			printf("\n");
			break;
		case 2:
			printf("輸入要刪除的數\n");
			scanf("%d",&x);
			m = DeleteBT(&T,x);
			if(m==TRUE)
			{
				InOrderTraverse(T);
				printf("\n");
			}
			else
				printf("刪除失敗\n");
			break;
		case 3:
			printf("輸入要添加的數\n");
			scanf("%d",&x);
			m = InsertBT(&T,x);
			if(m==TRUE)
			{
				InOrderTraverse(T);
				printf("\n");
			}
			else
				printf("添加失敗\n");
			break;
		case 4:
			printf("輸入要查找的數\n");
			scanf("%d",&x);
			m = SearchBT(T,x,NULL,&p);
			if(m==TRUE)
			{
				printf("查得:%d\n",x);
			}
			else
				printf("查找失敗\n");
			break;
		}
	}
}


Status SearchBT(BTree T,TElemType key,BTree f,BTree *p)
{
	if(!T)//查找不成功
	{
		*p = f;
		return FALSE;
	}
	else if(key == T->data)//查找成功
	{
		*p = T;
		return TRUE;
	}
	else if(key < T->data)
	{
		return SearchBT(T->lchild,key,T,p);
	}
	else
		return SearchBT(T->rchild,key,T,p);
}

Status InsertBT(BTree *T,TElemType key)
{
	BTree p,s;
	if(!SearchBT(*T,key,NULL,&p))//查找失敗
	{
		s = (BTree)malloc(sizeof(BTNode));
		s->data = key;
		s->lchild = s->rchild = NULL;
		if(!p)
			*T = s;//插入s爲新的根結點
		else if(key < p->data)
			p->lchild = s;//插入s爲左孩子
		else
			p->rchild = s;//插入s爲右孩子
		return TRUE;
	}
	else
		return FALSE;
}

Status Delete(BTree *p)
{
	BTree q,s;
	if((*p)->rchild == NULL)//右子樹空只需連接它的左子樹
	{
		q = *p; *p = (*p)->lchild; free(q);
	}
	else if((*p)->lchild == NULL)//左子樹空只需連接它的右子樹
	{
		q = *p; *p = (*p)->rchild; free(q);
	}
	else//左右子樹均不空
	{
		q = *p; s = (*p)->lchild;
		while(s->rchild)//轉左,然後向右到盡頭
		{
			q = s;s = s->rchild;
		}
		(*p)->data = s->data;
		if(q != *p)
			q->rchild = s->lchild;
		else
			q->lchild = s->lchild;
		free(s);
	}
	return TRUE;
}

Status DeleteBT(BTree *T,TElemType key)
{
	if(!*T)//要刪除的數不存在
		return FALSE;
	else
	{
		if(key == (*T)->data)
			return Delete(T);
		else if(key < (*T)->data)
			return DeleteBT(&(*T)->lchild,key);
		else
			return DeleteBT(&(*T)->rchild,key);
	}
}

void InOrderTraverse(BTree T)
{
	if(T == NULL)
		return;
	InOrderTraverse(T->lchild);
	printf("%d ",T->data);
	InOrderTraverse(T->rchild);
}

運行結果

運行結果

後記

二叉排序樹其實就是爲了動態查找而產生的
還記得動態查找是什麼嗎:
動態查找在查找過程中插入不存在的元素,刪除已存在的元素。

今天的內容就是二叉排序樹的基本操作及其內容,喜歡我的多多支持哦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章