目录
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]开始的数组看成一颗二叉树。堆实际上是一种特殊的二叉树,分为大根堆和小根堆,大根堆的每个父节点里存的值都大于它的所有子节点的值,小根堆则相反。因此,堆也满足二叉树的一些性质:
堆结构中重要的方法有两个,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,所以结果不变。