自学数据结构和算法(3)

目录

 

1、快速排序

2、堆排序


 

1、快速排序

#include<iostream>
using namespace std;
int arr[8]={2,5,10,3,0,100,5,2};

void swap(int a[],int x,int y)
{
	int temp=arr[x];
	arr[x]=arr[y];
	arr[y]=temp;
}

void Quicksort(int a[],int L,int R)
{
	if(L==R) return;
//终止条件,也是二分后的小序列最终有序的标志 
	int low=L,high=R;
//下面是partition过程
//以下进行三数取中优化
	int mid=low+((high-low)>>1);
	if(arr[low]>arr[high])
	swap(a,low,high);
	if(arr[mid]>arr[high])
	swap(a,mid,high);
	if(arr[low]<arr[mid])
	swap(a,low,mid);
	int pivot=arr[low];
	while(low<high)
	{
		while(low<high&&arr[high]>=pivot)
		high--;
		if(low<high)
		arr[low]=arr[high];
		while(low<high&&arr[low]<=pivot)
		low++;
		if(low<high)
		arr[high]=arr[low];
		if(low>=high)
		arr[low]=pivot;
	}
	Quicksort(a,L,low);
	Quicksort(a,low+1,R);
}

int main()
{
	Quicksort(arr,0,7);	
	for(int i=0;i<8;i++)
	cout<<arr[i]<<' ';
	return 0;
}

关于三数取中的说明:假设有A,B,C三个数,先用两次swap保证A,B<C,再判断A和B的大小,谁大谁就是中间数,就放在arr[low]的位置上方便下面partition。

另一点需要注意的是:while循环的过程中,循环条件变得不满足时,不会立刻break,而是直到这一轮结束后才会break

2、堆排序

二叉树是我们想象出来的一种数据结构,一般而言我们可以将一个从[0]开始的数组看成一颗二叉树。堆实际上是一种特殊的二叉树,分为大根堆和小根堆,大根堆的每个父节点里存的值都大于它的所有子节点的值,小根堆则相反。因此,堆也满足二叉树的一些性质:

d602adc9fcdf4c1aa9c474d8c6c4f568.jpeg

 堆结构中重要的方法有两个,heapInsert和heapify(堆化)

heapSize=堆中元素的个数

#include<iostream>
using namespace std;

int a[8]={2,5,10,3,0,100,5,2};

void swap(int a[],int x,int y)
{
	int temp=a[x];
	a[x]=a[y];
	a[y]=temp;
}

void heapify(int a[],int index,int heapSize)
//heapify的作用是将下标为index的数放到合适的位置,
//使结构仍是一个大根堆 
//heapSize用于判断子节点是否越界 
{
	int left=index*2+1;
	int right=left+1;
	while(left<heapSize)
	//说明有子节点 
	{
		int largest=((right<heapSize)&&(a[left]<a[right]))?right:left;
		//largest取左右子节点中最大的那个的下标 
		largest=a[index]<a[largest]?largest:index;
		//largest取父、子节点中最大的那个的下标
		if(index==largest)
		break;
		//如果父节点值最大则不用继续向下进行 
		swap(a,index,largest);
		index=largest;
		left=index*2+1;
		right=left+1;
	}
}

void heapInsert(int a[],int index)
//用户新给一个数,通过这个函数将这个数放到堆的合适位置 
{
	while(a[index]>a[(index-1)/2])
	//注意:这里不能右移1位,因为(-1)>>1结果为-1,(-1)/2结果为0 
	{
		swap(a,index,(index-1)/2);
		index=(index-1)/2;
	}
}

void heapSort(int a[],int n)
{
//	for(int i=0;i<n;i++)
//	heapInsert(a,i);
//	//将数组变成大根堆
//上面这一步也可以写得更快、更简单:
	for(int i=n-1;i>=0;i--)
	heapify(a,i,n);



	int heapSize=n;
	swap(a,0,n-1);
	//将最大的数放到数组的最后
	heapSize--;
	//将最大值放到数组最后之后,保证有序,故不算入大根堆里 
	while(heapSize>0)
	//此时说明仍保留部分堆结构,不能保证整个数组完全有序 
	{
		heapify(a,0,heapSize);
		//恢复大根堆结构
		heapSize--;
		swap(a,0,heapSize);
	}
}

int main()
{
	heapSort(a,8);
	for(int i=0;i<8;i++)
	{
		cout<<a[i]<<' ';
	}
	return 0;
}

需要注意并不是什么时候都能用右移一位来代替除二的操作,比如-1右移一位的结果仍是-1,因为在二进制中,-1的补码表示是1111 1111,右移一位后仍然是1111 1111,所以结果不变。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值