二分查找和二分搜索树(含插入,查找的递归非递归)

有序顺序表顺序搜索判定树:
在这里插入图片描述
扩充二叉树(用于分析的判定树):在这里插入图片描述
其中第i个内部节点刚好处于第i-1个外部节点和i+1个内部节点之间

#include<iostream>
#include<queue>
using namespace std;


//设置为左闭右开
//二分查找非递归
int BinarySearch(int a[], int low, int high, int x) {
	while (low < high) {//左闭右开取等的时候越界
		int mid = (low + high) / 2;
		if (x < a[mid])
			high = mid;//high是不能取到的 所以不是mid-1
		else if (a[mid] < x)
			low = mid + 1;
		else
			return mid;
	}
	return -1;
}
//设置为左闭右开
//二分查找递归
int ReverseBinarySearch(int a[], int low, int high, int x) {
	if (low < high) {//同样要满足这个条件
		int mid = (low + high) / 2;
		if (a[mid] == x)
			return mid;
		else if (a[mid] < x) {
			return ReverseBinarySearch(a, mid + 1, high, x);//层层return需要return回去
		}
		else
			return ReverseBinarySearch(a, low, mid, x);
	}
	return -1;//不满足返回-1
}

struct tree {
	int val;
	tree* lchild;
	tree* rchild;
};
class BinarySearchTree {
public:
	BinarySearchTree() {
		root = NULL;
	}

	~BinarySearchTree() {
		//层次遍历
		//queue<tree*>q;
		//if (root) {
		//	q.push(root);
		//	while (!q.empty()) {
		//		root = q.front(); q.pop();
		//		if (root->lchild)
		//			q.push(root->lchild);
		//		if (root->rchild)
		//			q.push(root->rchild);
		//		delete root;
		//	}
		//}

		//后序遍历
		// 如果不用后序遍历,那么则需要将当前的根节点缓存,否则delete掉之后,找不到他的左右节点了
		free(root);

	}
	void free(tree* root) {
		if (root) {
			free(root->lchild);
			free(root->rchild);
			delete root;
		}
	}
	tree* create(int a[], int length) {//对一个数组建立二叉搜索树

		for (int i = 0; i < length; ++i) {
			Insert(root, a[i]);
		}
		return root;
	}
	//递归
	bool RecursionInsert(tree*& root, int x) {//加了引用之后导致函数里的任何更改都可以导致root的变化
		if (root == NULL) {
			root = new tree;
			root->val = x;
			root->lchild = root->rchild = NULL;//一定要赋值为NULL啊 我晕
			return true;
		}
		else if (x < root->val)
			return RecursionInsert(root->lchild, x);
		else if (root->val < x)
			return RecursionInsert(root->rchild, x);
		else
			return false;//在二叉搜索树里面就有
	}
	bool Insert(tree*& root, int x) {//记得引用
		//非递归不像递归,递归最后return回去的是最开始的根节点root.所以递归要用head来保存最开始的节点,像单链表一样
		tree* p = root, * head = root;
		if (!root) {
			root = new tree();//每次new了,接受的是新的地址
			head = root;//所以如果没有这句话,那么会导致head保存的是原来的root的地址,而不是新的
			root->val = x;
			root->lchild = root->rchild = NULL;
			root = head;
			return 1;
		}
		else {
			while (root) {
				if (x < root->val) {
					p = root, root = root->lchild;//这种情况可以记录前驱节点
				}
				else if (root->val < x) {
					p = root, root = root->rchild;
				}
				else {
					root = head;//只要一返回就应该把root置为原来那个
					return 0;
				}
			}
			if (x < p->val) {
				p->lchild = new tree();//因为本来为NULL,所以新赋值一个地址
				p->lchild->val = x;
				p->lchild->lchild = p->lchild->rchild = NULL;
			}
			else {
				p->rchild = new tree();
				p->rchild->val = x;
				p->rchild->lchild = p->rchild->rchild = NULL;
			}
			root = head;
			return 1;
		}


	}
	//递归
	tree* RecursionSearch(int x, tree* root) {
		if (root == NULL)
			return NULL;
		else if (x < root->val)
			return RecursionSearch(x, root->rchild);//老是忘记+return!
		else if (root->val < x)
			return RecursionSearch(x, root->rchild);
		else
			return root;
	}
	tree* Search(int x, tree* root) {
		while (root) {
			if (x < root->val)
				root = root->lchild;
			else if (root->val < x)
				root = root->rchild;
			else
				return root;
		}
		return NULL;
	}
	bool del(int x, tree*& root) {
		tree* p, * q;
		if (root) {
			if (x < root->val)
				return del(x, root->lchild);
			else if (root->val < x)
				return del(x, root->rchild);
			else {
				//当左右子树都不为空的时候,找到右子树的中序遍历第一个节点(本文算法)或者是左子树中序遍历最后一个节点
				//右子树的中序遍历第一个节点就是右子树中最小的但又比原来根节点大的
				if (root->lchild && root->rchild) {
					p = root->rchild;
					while (p->lchild)
						p = p->lchild;

					root->val = p->val;
					return del(p->val, root->rchild);//然后删除这个中序遍历的第一个节点,即进入函数后进入这里所在的下一个else分支
				}

				//可以迭代,算法如下

				/*
				if (root->lchild && root->rchild) {
					q=root;
					p = root->rchild;
					while (p->lchild)
						q=p,p = p->lchild;
					root->val = p->val;
					if(q!=p)
						q->lchild=p->rchild;
					else
						q->rchild=p->rchild;
					delete p;
				}
				*/
				else {
					p = root;
					if (!root->lchild)
						root = root->rchild;//因为是引用 可以直接链接 把地址传过去
					else
					//可以合并到一块去
						root = root->lchild;
					
					delete p;
					return true;
				}
			}
		}
		return false;
	}
private:
	tree* root;
};


int main() {
	int b[] = { 0,1,2,3,4,5,6,7,8,9 };
	cout << "BinarySearch  " << BinarySearch(b, 0, 10, 0) << endl;
	cout << "ReverseBinarySearch  " << ReverseBinarySearch(b, 0, 10, 0) << endl;
	cout << "BinarySearch  " << BinarySearch(b, 0, 10, -1) << endl;
	cout << "ReverseBinarySearch  " << ReverseBinarySearch(b, 0, 10, -1) << endl;
	cout << "BinarySearch  " << BinarySearch(b, 0, 10, 9) << endl;
	cout << "ReverseBinarySearch  " << ReverseBinarySearch(b, 0, 10, 9) << endl;
	cout << "BinarySearch  " << BinarySearch(b, 0, 10, 5) << endl;
	cout << "ReverseBinarySearch  " << ReverseBinarySearch(b, 0, 10, 5) << endl;
	BinarySearchTree BT; tree* root;
	int a[] = { 6,3,5,2,1,4 };
	root = BT.create(a, 6);
	cout << " b.RecursionInsert(root, 1); " << BT.RecursionInsert(root, 1) << endl;
	cout << " b.Insert(root, 8); " << BT.Insert(root, 8) << endl;
	cout << "b.RecursionSearch(6,root);  " << BT.RecursionSearch(6, root) << endl;
	cout << "b.search(6,root);  " << BT.Search(6, root) << endl;
	cout << "b.del(5, root);  " << BT.del(5, root) << endl;

	return 0;//不写这个会导致不进行析构函数,我之前的所有的delete真是delete个寂寞。无语。
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值