实验7 堆和搜索树

0x01 实验目的

掌握堆和搜索树的基本概念,插入、删除方法。

0x02 实验内容

  1. 输入一系列不为零的正整数(最多不超过20个),遇到0代表输入结束(0不作为输入数据参与其中)。
  2. 根据上面输入的数据序列,用初始化方法创建最大堆(不要用节点依次插入的办法创建最大堆),然后输出最大堆的层次序列。
  3. 输出用堆排序后的排序结果。
  4. 根据上面输入的数据,创建二叉搜索树(关键字不允许重复,如遇重复,则不重复插入该关键字),输出二叉搜索树的前序序列、中序序列(分行输出)。

0x03 实验步骤

maxHeap的初始化操作

函数传入两个参数:一个是数组,另一个是数组中元素的个数。

  1. 直接将原数组释放掉,然后将新数组赋值给原数组。
  2. 将传入的数组元素个数赋值给类中的堆的大小。
  3. 从数组大小的二分之一处进行调整,最终调整为最大堆。
template<class T>
void maxHeap<T>::initialize(T theHeap[], int theSize) {
	delete []heap;
	heap = theHeap;
	heapSize = theSize;
	//copy(theHeap, theHeap + sizeof(theHeap), heap);
	//memcpy(heap,theHeap,sizeof(theHeap));
	for(int root = heapSize / 2; root >= 1; root--) {
	    //获取需要调整节点的值
		T rootElement = heap[root];
		//找到该节点的左子节点的索引
		int child = 2 * root;
		//如果子节点的索引小于等于堆的大小,就一直调整。
		while(child <= heapSize) {
		    //找到左子节点和右子节点大的那一个节点的索引
			if(child < heapSize && heap[child] < heap[child+1]) child++;
			//如果根节点大于最大的那一个子节点的值,说明该根节点不需要调整,直接跳出循环。
			if(rootElement >= heap[child]) break;
			//否则,根节点的值为最大那个子节点的值
			heap[child / 2] = heap[child];
			//子节点下移一层,继续调整。
			child *= 2;
		}
		heap[child / 2] = rootElement;
	}
}

maxHeap的层次遍历

直接输出heap数组

堆排序

template<class T>
void maxHeap<T>::heapSort() {
    /*
    记录堆的大小,因为pop操作时会使堆的大小不断减小
    而我们只排个序而已,没必要这样,后面用这个给恢复过来
    */
	int temp = heapSize;
	for(int i = heapSize - 1; i >= 1; i--) {
	    //获取最大元素
		T x = top();
		//删除最大元素,并重排(数组会前移一位)
		pop();
		//最大元素放在最后前移空出来的那一位
		heap[i+1] = x;
	}
	//恢复堆的大小
	heapSize = temp;
	//deactivateArray();
}

创建二叉搜索树

说明: 创建二叉搜索树,是按照我们输入的数组顺序来的,不是排序后的数组。按照数组顺序依次插入即可。

  1. 一般的节点类
class Node {
	public:
		Node() {
			leftChild = NULL;
			rightChild = NULL;
			key = 0;
		}
		Node(int element) {
			key = element;
			leftChild = NULL;
			rightChild = NULL;
		}
		Node *leftChild;
		Node *rightChild;
		int key;
};
  1. bsTree类
class bsTree {
	public:
		bsTree() {
			root = NULL;
		};
		void insert(int);
		void preOrder(Node*);
		void inOrder(Node*);
		Node *root;
};
  1. 插入操作
//插入操作,很简单,就是双指针+比较大小
void bsTree::insert(int element) {
	Node *n = new Node(element);
	if(root == NULL) root = n;
	else {
		Node *current = root;
		Node *pre = root;
		while(current) {
			pre = current;
			if(current->key > element) {
				current = current->leftChild;
			} else current = current->rightChild;
		}
		if(pre->key > element) pre->leftChild = n;
		else pre->rightChild = n;
		//只是将指针移到了n,但没改变指向。
		//current = n;
	}
}

二叉搜索树的前序遍历和中序遍历

  1. 中序遍历和堆排序后的结果差不多,可以直接去重输出。
  2. 遍历本身并不难,感觉比较复杂的是逗号的输出,可看完整代码理解,在此不作赘述。
void bsTree::inOrder(Node *node) {
	if(node == NULL) return;
	if(node->leftChild == NULL && flag == false) {
		flag = true;
		inOrder(node->leftChild);
		cout<<node->key;
		inOrder(node->rightChild);
	} else {
		inOrder(node->leftChild);
		cout<<","<<node->key;
		inOrder(node->rightChild);
	}

}
void bsTree::preOrder(Node *node) {
	if(node == NULL) return;
	if(root == node) {
		cout<<node->key;
		preOrder(node->leftChild);
		preOrder(node->rightChild);
	} else {
		cout<<","<<node->key;
		preOrder(node->leftChild);
		preOrder(node->rightChild);
	}
}

0x04 最终代码

#include<bits/stdc++.h>
using namespace std;
const int M = 100000;
int arr[M];
int brr[M];
bool crr[M];
bool flag = false;
class Node {
	public:
		Node() {
			leftChild = NULL;
			rightChild = NULL;
			key = 0;
		}
		Node(int element) {
			key = element;
			leftChild = NULL;
			rightChild = NULL;
		}
		Node *leftChild;
		Node *rightChild;
		int key;
};
class bsTree {
	public:
		bsTree() {
			root = NULL;
		};
		void insert(int);
		void preOrder(Node*);
		void inOrder(Node*);
		Node *root;
};
void bsTree::inOrder(Node *node) {
	if(node == NULL) return;
	if(node->leftChild == NULL && flag == false) {
		flag = true;
		inOrder(node->leftChild);
		cout<<node->key;
		inOrder(node->rightChild);
	} else {
		inOrder(node->leftChild);
		cout<<","<<node->key;
		inOrder(node->rightChild);
	}
}
void bsTree::preOrder(Node *node) {
	if(node == NULL) return;
	if(root == node) {
		cout<<node->key;
		preOrder(node->leftChild);
		preOrder(node->rightChild);
	} else {
		cout<<","<<node->key;
		preOrder(node->leftChild);
		preOrder(node->rightChild);
	}
}
//插入操作
void bsTree::insert(int element) {
	Node *n = new Node(element);
	if(root == NULL) root = n;
	else {
		Node *current = root;
		Node *pre = root;
		while(current) {
			pre = current;
			if(current->key > element) {
				current = current->leftChild;
			} else current = current->rightChild;
		}
		if(pre->key > element) pre->leftChild = n;
		else pre->rightChild = n;
		//只是将指针移到了n,但没改变指向。
		//current = n;
	}
}
template <class T>
class maxHeap {
	public:
		maxHeap() {
			heapSize = 0;
			arrayLength = 0;
			heap = new T[arrayLength];
			//flag = false;
		};
		void initialize(T theHeap[], int size);
		void levelOutput();
		void heapSort();
		T top();
		void pop();
		//void deactivateArray();
	private:
		int heapSize;
		int arrayLength;
		T* heap;
		//bool flag;
};
//template<class T>
//void maxHeap<T>::deactivateArray(){
//	flag = true;
//}
template<class T>
void maxHeap<T>::pop() {
	if(heapSize == 0) return;
	//if(flag == false)
	//删除最大元素
	heap[1].~T();
	T last = heap[heapSize--];
	int current = 1;
	int child = 2;
	//与初始化有异曲同工之妙
	while(child <= heapSize) {
		//找两个孩子的大者
		if(child < heapSize && heap[child] < heap[child+1]) child++;
		if(last >= heap[child]) break;
		heap[current] = heap[child];
		current = child;
		child = child * 2;
	}
	heap[current] = last;
	//flag = false;
}
template<class T>
T maxHeap<T>::top() {
	return heap[1];
}
template<class T>
void maxHeap<T>::heapSort() {
	int temp = heapSize;
	for(int i = heapSize - 1; i >= 1; i--) {
		T x = top();
		pop();
		heap[i+1] = x;
	}
	heapSize = temp;
	//deactivateArray();
}
template<class T>
void maxHeap<T>::initialize(T theHeap[], int theSize) {
	delete []heap;
	heap = theHeap;
	heapSize = theSize;
	//copy(theHeap, theHeap + sizeof(theHeap), heap);
	//memcpy(heap,theHeap,sizeof(theHeap));
	for(int root = heapSize / 2; root >= 1; root--) {
		T rootElement = heap[root];
		int child = 2 * root;
		while(child <= heapSize) {
			if(child < heapSize && heap[child] < heap[child+1]) child++;
			if(rootElement >= heap[child]) break;
			heap[child / 2] = heap[child];
			child *= 2;
		}
		heap[child / 2] = rootElement;
	}
}
template<class T>
void maxHeap<T>::levelOutput() {
	for(int i = 1; i <= heapSize; i++) {
		if(i == 1) cout<<heap[i];
		else cout<<","<<heap[i];
	}
	cout<<endl;
}
int main() {
	cout<<"Input"<<endl;
	int index = 0;
	int temp;
	do {
		index++;
		cin>>temp;
		arr[index] = temp;
		brr[index] = temp;
	} while(temp != 0);
	maxHeap<int> heap;
	heap.initialize(arr, index - 1);
	cout<<"Output"<<endl;
	heap.levelOutput();
	heap.heapSort();
	heap.levelOutput();
	bsTree bstree;
	for(int i = 1; i < index; i++) {
		if(crr[brr[i]] == false) {
			crr[brr[i]] = true; 
			bstree.insert(brr[i]);
		}
	}
	bstree.preOrder(bstree.root);
	cout<<endl;
	bstree.inOrder(bstree.root);
	cout<<endl;
	cout<<"End"<<endl;
	return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值