左神算法基础class2——题目3 堆heapInsert、heapify、堆排序C++实现

1.基础知识

1.完全二叉树有两种:
5
/ \
1 2
/ \ /
3 4 2 6
满二叉树
5
/ \
1 2
/
1
从左到右排序的二叉树
2.完全二叉树可等价为堆,堆可用数组实现
其中第i结点的左孩子:2i+1,第i结点的右孩子:2i+2,第i结点的父节点:(i-1)/2
3.大根堆:指任意子树的最大值是其头部的结点
小根堆:指任意子树的最小值是其头部的结点

2.heapInsert:新结点加入进来并向上调整为大根堆的过程

把数组变为大根堆,建立堆结构

分析

如果当前插入的元素大于其父节点的元素,那么交换父节点与当前节点的位置。接着考察更换结点后的插入元素与新位置的父节点大小,如果还是大于还要继续交换。
eg。例[2,1,3,6]变换为大根堆
位置0,1,2,3
(1)2插入,父节点(0-1)/2 = 0位置,自己和自己不动;
(2)1插入,父节点(1-1)/2 = 0位置,1<2,不动;
(3)3插入,父节点(2-1)/2 = 0位置,3>2,交换位置;此时3的位置变为0,父节点(0-1)/2 = 0位置,自己和自己不动;
此时:
3
/
1 2
(4)6插入,父节点(3-1)/2 = 1位置,6>1,交换位置;此时6的位置变为1,父节点(1-1)/2 = 0位置;6>3,继续交换;
6
/
3 2
/
1

核心代码

(index-1)/2是index父节点的位置

void heapinsert(int arr[],int index)
{
	while(arr[index] > arr[(index-1)/2])
	{
		swap(arr[index],arr[(index-1)/2]);
		index = (index-1)/2;
	}
}

使用for循环遍历数组,调用heapinsert

for(int i = 0;i < length;i++ )
	{
		heapinsert(arr,i);//用for循环传入要处理的index
	}

完整代码

#include<iostream>

#define length 5
using namespace std;

void swap(int &a,int &b)
{
	int temp = a;
	a = b;
	b = temp;

}
void heapinsert(int arr[],int index)
{
	while(arr[index] > arr[(index-1)/2])
	{
		swap(arr[index],arr[(index-1)/2]);
		index = (index-1)/2;
	}
}

int main()
{
	//int arr[length] = {2,1,3,6,0,4};
	int arr[length] = {3,4,5,1,2};
	int heapsize = length;
	for(int i = 0;i < length;i++ )
	{
		heapinsert(arr,i);//用for循环传入要处理的index
	}


	system("pause");
	return 0;
}

时间复杂度

加一个数需要比较树的高度次,O(logN),当0到i-1加入一个数需要比较log(I-1)次;N个数需要log1+log2+…+log(N-1)=log(N)

3.heapify:假设数组中一个值变小了,重新调整为大根堆的过程

分析

1.找出这个数的左右孩子中的最大值,将这个最大值与改变的值进行比较,如果改变的值大于左右孩子的最大值,则交换两个数,接着找到交换后的左右孩子,继续比较。
2.继续比较的条件:左孩子未越界。

核心代码

比较左右孩子和当前的数,找出最大值赋给largest;如果当前数是largest则跳出,如果不是,则交换两个数,更新index,和左孩子位置,继续比较。

void heapify(int arr[],int index,int heapsize)
{
	int left = index * 2 + 1; 
	while(left < heapsize)
	{
		int largest = left + 1 < heapsize && arr[left]<arr[left + 1] ? 
			left + 1:left;
		largest = arr[largest] > arr[index] ? largest : index;
		if(largest == index)
			break;
		swap(arr[largest],arr[index]);
		index = largest;
		left =  index * 2 + 1;
	}
}

完整代码

#include<iostream>

#define length 6
using namespace std;

void swap(int &a,int &b)
{
	int temp = a;
	a = b;
	b = temp;

}
void heapify(int arr[],int index,int heapsize)
{
	int left = index * 2 + 1; 
	while(left < heapsize)
	{
		int largest = left + 1 < heapsize && arr[left]<arr[left + 1] ? 
			left + 1:left;
		largest = arr[largest] > arr[index] ? largest : index;
		if(largest == index)
			break;
		swap(arr[largest],arr[index]);
		index = largest;
		left =  index * 2 + 1;
	}
}

int main()
{
	//int arr[length] = {2,1,3,6,0,4};
	int arr[length] = {6,5,4,3,5,2};
	int heapsize = length;
	arr[0] = 1;
	heapify(arr,0,heapsize);


	system("pause");
	return 0;
}

4.堆排序

分析

heapinsert结合heapify。
(1)让数组变为大根堆(heapinsert);
(2)让最后一位和堆顶交换,堆大小减一(保存最大值)
(3)再重新变为大根堆,相当于把堆顶元素变小再重排(heapify)
(4)直到堆大小为1停止。

核心代码

1.heapinsert

void heapinsert(int arr[],int index)
{
	while(arr[index] > arr[(index-1)/2])
	{
		swap(arr[index],arr[(index-1)/2]);
		index = (index-1)/2;
	}
}

2.heapify

void heapify(int arr[],int index,int heapsize)
{
	int left = 2*index+1;
	while (left < heapsize)
	{
		int largest = left+1<heapsize && arr[left+1]>arr[left]?
			left+1:left;
		largest = arr[index] < arr[largest]?largest:index;
		if(index == largest)
			break;
		swap(arr[index],arr[largest]);
		index = largest;
		left = 2*index+1;
	}
}

3.heapsort

void heapsort(int arr[],int heapsize)
{
	while(heapsize > 1)
	{
		swap(arr[0],arr[heapsize-1]);
		heapsize--;
		heapify(arr,0,heapsize);
	}
}

完整代码

#include<iostream>
#include<time.h>
#define length 10
using namespace std;

void swap(int &a,int &b)
{
	int temp = a;
	a = b;
	b = temp;
}

void heapify(int arr[],int index,int heapsize)
{
	int left = 2*index+1;
	while (left < heapsize)
	{
		int largest = left+1<heapsize && arr[left+1]>arr[left]?
			left+1:left;
		largest = arr[index] < arr[largest]?largest:index;
		if(index == largest)
			break;
		swap(arr[index],arr[largest]);
		index = largest;
		left = 2*index+1;
	}

}


void heapsort(int arr[],int heapsize)
{
	while(heapsize > 1)
	{
		swap(arr[0],arr[heapsize-1]);
		heapsize--;
		heapify(arr,0,heapsize);
	}
}


void heapinsert(int arr[],int index)
{
	while(arr[index] > arr[(index-1)/2])
	{
		swap(arr[index],arr[(index-1)/2]);
		index = (index-1)/2;
	}
}


int main()
{
	srand((unsigned)time(NULL));
	
	int arr[length]  ;
	int heapsize = length ;
	cout<<"arr = ";
	for(int i = 0;i<heapsize;i++)
	{
		arr[i] = rand()%10;
		cout<<arr[i]<<" ";
		heapinsert(arr,i);
	}
	cout<<endl<<"arr1 = ";

	heapsort(arr,heapsize);

	for(int i = 0;i<length;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl;

	//system("pause");
	return 0;
}

时间复杂度

O(N*logN),不考虑建立堆的过程,每次排序logN,排N个。

发布了51 篇原创文章 · 获赞 1 · 访问量 1394

猜你喜欢

转载自blog.csdn.net/shi_xiao_xuan/article/details/103508459
今日推荐