数据结构与算法学习笔记(九)(补堆排序)

堆排序

利用大根堆来对数组从小到大排序。

思路:

利用数组来表达堆,把目标排序数组复制给堆数组,对堆数组先进行下沉法,让节点都遵循父节点总比子节点大的规律,再利用另一种重载下沉法,弹出数组中的最大值,并把最大值复制给目标排序数组。

堆类基本成员:

class HeapSort
{
public:
	int* heap;
	int N;

	

	void exch(int i, int j)
	{
		int temp;
		temp = heap[i];
		heap[i] = heap[j];
		heap[j] = temp;
	}

    	bool less(int i, int j)
	{
		if (heap[i] < heap[j])
		{
			return true;
		}
		return false;
	}
……

排序入口函数sort():

	void sort(int* source,int len)
	{
		creatHeap(source,len);
		for (int i = N-1; i>=0; i--)
		{
			source[i] = delMax();        //弹出最大值,赋给原数组
		}
	}

创建有序数组函数creatHeap():

	void creatHeap(int* source,int len)
	{
		//拷贝新数组
		copySource(source,len);
		//对heap中的元素做调整,从长度的一半处sink,不从长度一般遍历也行,具体看接下来的sink2()
		for (int i = N / 2; i > 0; i--)
		{
			sink2(i);
		}
	}

复制函数copySource():

	void copySource(int* source,int len)
	{

		N = len;
		cout << "len=" << len << endl;
		this->heap = new int[len+1];
		for (int i = 0; i < len+1; i++)
		{
			heap[i + 1] = source[i];
		}
	}

下沉函数sink2():

void sink2(int i)
	{
		int max = 0;
		while (i * 2 <= N)			//N为数组元素量,在复制时有赋值
		{
			if (i * 2 + 1 >= N)
			{
				if (less(i * 2, i * 2 + 1))
				{
					max = i * 2 + 1;
				}
				else
				{
					max = i * 2;
				}
			}
			else
			{
				max = i * 2;
			}

			if (less(max, i))
			{
				return;
			}

			exch(max, i);

			i = max;
		}
	}

从最末端的子节点下沉没有必要,它们没有子节点可以交换,于是从倒数第二层的父节点开始下沉,让其于它的子节点交换,最外层的交换不会干扰的整个数组的顺序,而里层父节点交换可能会干扰到,比如倒数第三层的父节点与倒数第二层的子节点交换,可能子节点的新元素比其子节点小,因此要追踪其交换的位置,让其再与子节点判断交换,直到末端。

可能你还有些顾虑,这里是二叉树的样子,仅仅正确交换一次就可以使当前子树有序,有元素更改,就去操作更改元素(它为根)所在的子树有序。

剩下就是不那么重要的,弹出最大值,并赋值给原数组:

delmax():

int delMax()
	{
		if (N == 0)
		{
			return -1;
		}
		int max = heap[1];
		exch(1, N);
		N--;
		sink(1);
		return max;
	}

sink():

void sink(int k)
	{
		while (2 * k <= N)
		{
			int max;
			if (2 * k + 1 <= N)
			{
				if (less(2 * k, 2 * k + 1))
				{
					max = 2 * k + 1;
				}
				else
				{
					max = 2 * k;
				}
			}
			else
			{
				max = 2 * k;
			}
			if (!less(k, max))
			{
				return;
			}

			exch(k, max);

			k = max;
		}
	}

让根节点处元素与末端元素交换,重新在根的位置下沉调整数组有序化。

验证结果:

int main()
{
	int source[10] = {10,9,5,7,6,5,4,3,2,1};

	cout << "初始遍历:" << endl;
	for (int i = 0; i < 10; i++)
	{
		cout << source[i] << endl;
	}

	HeapSort heapsort;

	heapsort.sort(source,10);

	cout << "重新遍历:" << endl;
	for (int i = 0; i < 10; i++)
	{
		cout << source[i] << endl;
	}
}

结果:
初始遍历:
10
9
5
7
6
5
4
3
2
1
len=10
重新遍历:
1
2
3
4
5
5
6
7
9
10

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值