目录
一、堆
1、堆结构就是用数组实现的完全二叉树结构
2、完全二叉树中如果每棵子树的最大值都在顶部就是大根堆
3、完全二叉树中如果每棵子树的最小值都在顶部就是小根堆
4、堆结构的heapInsert与heapify操作
5、堆结构的增大和减少
6、优先级队列结构,就是堆结构
heapInsert操作代码:
void heapInsert(int arr[],int index)
{
while(arr[index]>arr[(index-1)/2])
{
swap(arr,index,(index-1)/2);
index=(index-1)/2;
}
}
healpInsert操作是寻找根节点是否比当前节点小,若比当前节点小则交换,index继续指向当前节点,直到根节点大于当前节点
heapify操作代码:
void heapify(int arr[],int index)
{
int left=index*2+1;
while(left<heapsize)
{
int lagster=left+1<heapsize&&arr[left+1]>arr[left]?left+1:left;//若右子节点大于左子节点则返回右子节点,反之,返回左子节点
lagster=arr[lagster]>arr[index]?lagster:index;
if(lagster==index) return;
swap(arr[lagster],arr[index]);
index=lagster;
left=index*2+1;
}
}
二、堆排序
堆排序1,先让整个数组都变成大根堆结构,建立堆的过程:
1、从上到下的方法,时间复杂度为O(N*logN)2)从下到上的方法,时间复杂度为O(N)
2、把堆的最大值和堆末尾的值交换,然后减少堆的大小之后,再去调整堆,一直周而复始,时间复杂度为O(N*logN)
3、堆的大小减小成0之后,排序完成
题目链接:排序
class Solution {
public:
int healpsize;
vector<int> sortArray(vector<int>& nums) {
healpsize=nums.size();
int n=nums.size();
for(int i=nums.size()-1;i>=0;i--)
{
heap(nums,i);
}
swapp(nums,0,--healpsize);
while(healpsize>1)
{
heap(nums,0);
swapp(nums,0,--healpsize);
}
return nums;
}
void heap(vector<int>&arr,int index)
{
int l=index*2+1;
while(l<healpsize)
{
int lagster=l+1<healpsize&&arr[l]<arr[l+1]?l+1:l;
lagster=arr[lagster]<arr[index]?index:lagster;
if(index==lagster)
{
return;
}
swapp(arr,index,lagster);
index=lagster;
l=index*2+1;
}
}
void swapp(vector<int>& arr,int l,int r)
{
arr[l]=arr[l]^arr[r];
arr[r]=arr[l]^arr[r];
arr[l]=arr[l]^arr[r];
return;
}
void heapInsert(vector<int>& arr,int index)
{
while(arr[index]>arr[(index-1)/2])
{
swapp(arr,index,(index-1)/2);
index=(index-1)/2;
}
}
};
简短版:
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
priority_queue<int,vector<int>,greater<int>>big;
for(int i=0;i<nums.size();i++)
{
big.push(nums[i]);
}
for(int i=0;i<nums.size();i++)
{
nums[i]=big.top();
big.pop();
}
return nums;
}
};
问题一:
已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
分析:准备一个小根堆,遍历数组,假设k=6,则先遍历前7个数,0~6放入小根堆,那么小根堆的最小值一定放在0位置上,因为由题意,每个元素移动的距离一定不超过k,所以小根堆的最小值弹出的数字放在0位置上,然后将7位置上的数放入小根堆,小根堆弹出的数字放到1位置,以此类推
int main()
{
priority_queue<int,vector<int>,greater<int>>small_heap;
int n,k;
cin>>n>>k;
int index=0;int x;
int arr[100];
for(int i=0;i<n;i++)
{
cin>>arr[i];
}
for(;index<=min(n,k);index++)
{
small_heap.push(arr[index]);
}
int i=0;
for(;index<n;i++,index++)
{
small_heap.push(arr[index]);
arr[i]=small_heap.top();
small_heap.pop();
}
while(!small_heap.empty())
{
arr[i++]=small_heap.top();
small_heap.pop();
}
for(int i=0;i<n;i++)
{
cout<<arr[i]<<' ';
}
return 0;
}
用c++的优先队列
手写的堆可以改变其中的数字,但是黑盒的堆不支持
有些情境下手写堆更高效
三、比较器的使用
1)比较器的实质就是重载比较运算符
2)比较器可以很好的应用在特殊标准的排序上
3)比较器可以很好的应用在根据特殊标准排序的结构上
在c++中就是重载运算符
四、桶排序
桶排序思想下的排序
1)计数排序
2)基数排序分析:
1)桶排序思想下的排序都是不基于比较的排序
2)时间复杂度为O(N),额外空间负载度O(M)
3)应用范围有限,需要样本的数据状况满足桶的划分
假设有0~9号桶,从左往右根据个位数字依次将数组元素放入桶中,然后把桶中的数字从左往右依次倒出,然后再根据十位数字从左往右放入桶中
代码为:
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
radixSort(nums);
return nums;
}
void radixSort(vector<int>& nums){
if(nums.size()<2)return;
radixSort(nums,0,nums.size()-1,maxbits(nums));
}
int maxbits(vector<int>& nums){
int maxx=nums[0];
for(int i=0;i<nums.size();i++)
{
maxx=max(maxx,nums[i]);
}
int res=0;
while(maxx!=0)
{
res++;
maxx/=10;
}
return res;
}
void radixSort(vector<int>& nums,int l,int r,int digit){
int radix=10;
int cout[radix];
memset(cout,0,radix);
int i=0,j=0;
int n=r-l+1;
int bucket[n];
memset(bucket,0,n);
for(int d=1;d<=digit;d++)
{
for(i=l;i<=r;i++)
{
j=getDigit(nums[i],d);
cout[j]++;
}
for(i=1;i<radix;i++)
{
cout[i]=cout[i]+cout[i-1];
}
for(i=r;i>=l;i--)
{
j=getDigit(nums[i],d);
bucket[cout[j]-1]=nums[i];
cout[j]--;
}
for(i=l,j=0;i<=r;i++,j++){
nums[i]=bucket[j];
}
}
}
int getDigit(int c,int d)
{
return((c/((int)pow(10,d-1)))%10);
}
};