学习笔记
堆
需要注意的地方
1.传参进去是坐标还是数值
2.堆排序需要递归
代码
# include<iostream>
using namespace std;
void print(int *arr,int n)
{
for(int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
void swap(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
void heaptify(int *arr,int n,int now)
{
int largest=now;
int left=2*largest+1;
int right=2*largest+2;
if(arr[left]>arr[largest]&&left<n)
{
largest=left;
}
if(arr[right]>arr[largest]&&right<n)
{
largest=right;
}
if(largest!=now)
{
swap(arr[largest],arr[now]);
heaptify(arr,n,largest);
}
}
void heapSort(int *arr,int n)
{
for(int i=n/2-1;i>=0;i--)
{
heaptify(arr,n,i);//从最后一个非叶子节点开始构造大顶堆
}
for(int i=n-1;i>=0;i--)
{
swap(arr[i],arr[0]);//将最大的放到数组的最后
heaptify(arr,i,0) ;
}
}
int main()
{
int arr[] = {12, 11, 13, 5, 6, 7};
int n =sizeof(arr)/sizeof(arr[0]);
print(arr, n);
heapSort(arr,n);
print(arr, n);
}
快速排序
需要注意的地方
1.while循环和if 条件,都是取等号的
代码
void quickSort(int *arr,int n,int left,int right)
{
if(left<right)
{
int pivot=(left+right)/2; //基准坐标
int i =left;
int j=right;
while(i<=j) //取等号 ,不然不运行结果
{
while(arr[i]<arr[pivot])
{
i++;
}
while(arr[j]>arr[pivot])
{
j--;
}
if(i<=j) //取等号
{
swap(arr[i],arr[j]);
i++;//交换后要记得++,--
j--;
}
}//递归不能忘记
quickSort(arr,n,left,j); //只有在left<right 的大前提下才会继续进行quick,并且,i,j是if大条件下的变量
quickSort(arr,n,i,right);
}
}
归并排序
需要注意的地方
- L2是从mid+1开始的
代码
# include<iostream>
using namespace std;
void print(int *arr,int n)
{
for(int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
void swap(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
void merge(int left,int mid,int right,int*arr)
{
int n1=mid-left+1;
int n2=right-(mid+1)+1;
int L1[n1]={0};
int L2[n2]={0};
for(int i=0;i<=n1;i++)
{
L1[i]=arr[left+i];
}
//print(L1,n1);
for(int j=0;j<=n2;j++)
{
L2[j]=arr[mid+1+j]; //这里从mid+1开始
}
//print(L2,n2);
int i=0;
int j=0;
int p=left;
while(i<n1&&j<n2)
{
if(L1[i]<L2[j])
{
arr[p]=L1[i];
p++;
i++;
}
else
{
arr[p]=L2[j];
p++;
j++;
}
}
while(i<n1)
{
arr[p]=L1[i];
p++;
i++;
}
while(j<n2)
{
arr[p]=L2[j];
p++;
j++;
}
}
void mergeSort(int *arr ,int n,int left,int right)
{
if(left<right)
{
int mid=(left+right)/2;
mergeSort(arr,n,left,mid);
mergeSort(arr,n,mid+1,right);
merge(left,mid,right,arr);
}
}
int main()
{
int arr[] = {12, 11, 13, 5, 6, 7};
int n =sizeof(arr)/sizeof(arr[0]);
print(arr, n);
mergeSort(arr,n,0,n-1);
print(arr, n);
}
选择排序
选择排序是一种简单直观的排序算法,它的基本思想是每次从待排序的元素中选择最小(或最大)的元素,然后将其放到已排序序列的末尾。这个过程重复进行,直到所有元素都排序完成。
需要注意的地方
1.注意比较的是两个元素,但是交换的是下标
2. if(index_min!=i)
{
swap(arr[i],arr[index_min]);
}
这个if可以没有,但是必须有交换的过程
代码
# include<iostream>
# include<string>
using namespace std;
void swap(int &a ,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}
void selectionSort(int *arr,int n)
{
for(int i=0;i<n-1;i++) //每次放置的位置
{
int index_min=i;
for(int j=i+1;j<n;j++)
{
if(arr[j]<arr[index_min])
{
index_min=j;
}
}
if(index_min!=i)
{
swap(arr[i],arr[index_min]);
}
}
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Original array: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
selectionSort(arr, n);
cout << "Sorted array: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
插入排序
需要注意的地方
1.插入排序要用while 来进行计算,内层循环
代码
# include<iostream>
# include<string>
using namespace std;
void print(int *arr,int n)
{
for(int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
void insertion(int *arr,int n)
{
for(int i=0;i<n-1;i++) //i 代表要插入的起始位置
{
int key=arr[i+1];
int j=i;
while(j>=0&&arr[j]>key) //比要key大的元素都往后移动
{
arr[j+1]=arr[j];
j--;
}
arr[j+1]=key;
}
}
int main()
{
int arr[]={5, 2, 4, 6, 1, 3};
int n=sizeof(arr)/sizeof(arr[0]);
print(arr,n);
insertion(arr,n);
print(arr,n);
}
计数排序
需要注意的地方
- 注意循环的上限是n还是length ,这两个代表不同的意思,并且容易混淆
- int o_index =count[index]-1; o_index需要通过count来计算,而不是直接index ,很容易就写错了
- count[index]–;不能忘记
- 计数排序放置位置的时候需要逆序
为何要逆序
代码
# include<iostream>
using namespace std;
void print(int *arr,int n)
{
for(int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
void countSort(int *arr,int n)
{
int max=arr[0];
int min=arr[0];
for(int i=0;i<n;i++)
{
if(max<arr[i])
{
max=arr[i];
}
if(min>arr[i])
{
min=arr[i];
}
}
int length=max-min+1;
int count[length]={0};
//index作为下标,count数组作为每个数相对于最小值有几个
for(int i=0;i<n;i++)
{
int index=arr[i]-min;
count[index]++;
}
for(int i=0;i<length-1;i++)
{
count[i+1]=count[i]+count[i+1];
}
int output[n]={0};
//根据累加数组的结果,将原数排序好放到output数组中
//这里是正序放入的,相对位置会改变,其实不是严格意义上的计数排序,但是方便理解(后面基数排序会写基数排序的逆序版)
for(int i=0;i<n;i++)
{
int index=arr[i]-min;
int o_index=count[index]-1;//output数组下标从0开始
output[o_index]=arr[i];
count[index]--; //例子:同样的3 有2个,一个已经放好到排序数组中了,所以还有一个,count--;
}
for(int i=0;i<n;i++)
{
arr[i]=output[i];
}
}
int main()
{
int arr[] = {4, 2, 2, 8, 3, 3, 1};
int n = sizeof(arr) / sizeof(arr[0]);
print(arr, n);
countSort(arr,n);
print(arr, n);
}
希尔排序
需要注意的地方
1.arr[j+gap]=key; 这里是更新k
2. j从i-gap开始,i从gap开始循环(需要理解j和i代表的含义)
代码
# include<iostream>
using namespace std;
void shellSort(int *arr,int n)
{
for(int gap=n/2;gap>0;gap/=2)
{
for(int i=gap;i<n;i++)
{
int key=arr[i];//i 代表要插入元素的下标
int j=i-gap; //j代表要插入的前一个元素的下标
while(j>=0&&arr[j]>key)
{
arr[j+gap]=arr[j];
j-=gap;
}
arr[j+gap]=key;
}
}
}
void printArray(int arr[], int n) {
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
int arr[] = {12, 34, 54, 2, 3,9,8,20};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Original array: ";
printArray(arr, n);
shellSort(arr, n);
cout << "Sorted array: ";
printArray(arr, n);
return 0;
}
桶排序
需要注意的地方
- vector<vector > buckets(cnt); 括号,不是中括号
- 要把元素放到桶里再排序,容易漏掉
代码
# include<iostream>
#include <vector>
# include<algorithm>
using namespace std;
void print(vector<int> nums,int n)
{
for (vector<int>::iterator numIter = nums.begin(); numIter != nums.end(); ++numIter) {
cout << *numIter << " ";
}
cout<<endl;
}
void bucketSort(vector<int> &num,int n)
{
int max=num[0];
int min=num[0];
for(int i=0;i<n;i++)
{
if(max<num[i])
{
max=num[i];
}
if(min>num[i])
{
min=num[i];
}
}
int size=(max-min)/n+1;//保证每个桶至少有一个元素
int cnt= (max-min)/size+1;//保证至少有一个桶
vector<vector <int> > buckets(cnt);//这里是括号
//将元素放到桶里
for(int i=0;i<n;i++)
{
//(mn+size*i,mn+size*(i+1))
int idx=(num[i]-min)/size;
buckets[idx].push_back(num[i]); //向末尾添加元素
}
for(int i=0;i<cnt;i++)
{
sort(buckets[i].begin(),buckets[i].end()); //桶内排序
}
}
int main()
{
int arr[] = {19, 27, 35, 43, 31, 22, 54, 66, 78};
int n=sizeof(arr)/sizeof(arr[0]);
vector<int> nums(arr,arr+n);
bucketSort(nums,n);
print(nums, n);
return 0;
}
基数排序
需要注意的地方
- 如果直接对nums全部进行除和取余操作,后续无法将原本的nums放入output数组里面
- 必须逆序对计数排序进行计算,不然无法得到正确结果
- (nums[i]/exp)%10和nums[i]一定要分清
代码
# include<iostream>
# include <vector>
# include<algorithm>
using namespace std;
void print(vector<int> &nums,int n)
{
for(vector<int>::iterator numIter=nums.begin();numIter!=nums.end();numIter++)
{//vector<int>::iterator numIter
cout<<*numIter<<" ";
}
cout<<endl;
}
int getMax(vector<int> &nums,int n)
{
int max=nums[0];
for(int i=0;i<n;i++)
{
if(nums[i]>max)
{
max=nums[i];
}
}
return max;
}
void countSort(vector<int> &nums,int n,int exp)
{
cout<<"exp:"<<exp<<endl;
// for(int i=0;i<n;i++)
// {
// nums[i]/=exp;
// nums[i]%=10;
// }
// print(nums,n);
int max=(nums[0]/exp)%10;
int min=(nums[0]/exp)%10;
for(int i=0;i<n;i++)
{
if(max<(nums[i]/exp)%10)
{
max=(nums[i]/exp)%10;
}
if(min>(nums[i]/exp)%10)
{
min=(nums[i]/exp)%10;
}
}
cout<<"max"<<max<<"min"<<min<<endl;
int length=max-min+1;
vector<int> count(length, 0);
for(int i=0;i<n;i++)
{
//count的下标表示的是与最小值的插值,count 数组表示的是有几个
int index=(nums[i]/exp)%10-min;
count[index]++;
}
cout<<"计数数组"<<endl;
print(count,length);
for (int i = 1; i <length; i++)
{
count[i] += count[i - 1];
}
cout<<"统计数组"<<endl;
print(count,length);
int output[n];
for(int i=n-1;i>=0;i--)
{
int index=(nums[i]/exp)%10-min;
int o_index=count[index]-1;
output[o_index]=nums[i];
count[index]--;
}
for(int i=0;i<n;i++)
{
nums[i]=output[i];
}
cout<<"sorted"<<endl;
print(nums,n);
}
void radixSort(vector<int> &nums,int n)
{
int max=getMax(nums,n);
for(int exp=1;max/exp>0;exp*=10)
{
countSort(nums,n,exp);
}
}
int main()
{
int arr []={170, 45, 75, 90, 802, 24, 2, 66};
int n=sizeof(arr)/sizeof(arr[0]);
vector<int> nums(arr,arr+n);
cout << "原始数组:" << endl;
print(nums, n);
radixSort(nums,n);
cout << "排序后的数组:" << endl;
print(nums, n);
return 0;
}