数据结构与算法-排序算法
往期内容
1-链表
2-栈与队列
3-树与图
4-哈希表
5-查找
6-排序
7-贪心
8-递归与分治
9-动态规划
排序算法
常见的排序算法
不稳定的算法:快速排序,希尔排序,选择排序,堆排序
1.冒泡排序
1.1 低配版本的冒泡排序(交换)
void BubbleSort(int *arr,int length)
{
for(int i=0;i<length;i++)
{
for(int j=i+1;j<length;j++)
{
if(arr[i]>arr[j])
{
int temp=arr[j];
arr[j]=arr[i];
arr[i]=temp;
}
}
}
}
1.2 冒泡排序
- 注意:第二个for循环j=length-i-1;一定要注意还有一个-1,因为对于n个数据其实只要比较n-1次,故需要-1
void BubbleSort1(int arr[],int length)
{
for(int i=0;i<length;i++)
{
for(int j=0;j<length-i-1;j++)
{
if(arr[j]>arr[j+1])
{
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
1.3 冒泡排序优化1
- 设置一个标志位flag,但某一次没有发生交换则表示排序已经完成
void BubbleSort2(int arr[],int length)
{
bool flag=true;//是否需要继续排序,只要有交换继续排序
for(int i=0;i<length && flag;i++)
{
flag=false;
for(int j=0;j<length-1-i;j++)
{
if(arr[j]>arr[j+1])
{
flag=true;
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
1.4 冒泡排序优化2-鸡尾酒排序
- 也叫双向冒泡
鸡尾酒排序:从低到高后从高到低
冒泡排序:从低到高
//4.鸡尾酒排序:从低到高后又从高到低
void BubbleSort3(int arr[],int length)
{
int i,temp;
int left,right;
left=0;
right=length-1;
while(left<right)
{
//从后往前
for(i=right;i>left;i--)
{
if(arr[i-1]>arr[i])
{
temp=arr[i];
arr[i]=arr[i-1];
arr[i-1]=temp;
}
}
left++;
//从前往后
for(i=left;i<right;i++)
{
if(arr[i]>arr[i+1])
{
temp=arr[i];
arr[i+1]=arr[i];
arr[i]=temp;
}
}
right--;
}
}
2.选择排序
每次只找对应的位置,第二层循环的时候 交换数据
void SelectSort(int *arr,int length)
{
int idcard;//实质是先找到位置,在交换
for(int i=0;i<length;i++)
{
idcard=i;
for(int j=i+1;j<length;j++)
{
if(arr[idcard]>arr[j])
idcard=j;
}
if(idcard!=i)
{
int temp=arr[idcard];
arr[idcard]=arr[i];
arr[i]=temp;
}
}
}
-类比 普通的交换排序,节省了 每次交换
void SelectSort0(int arr[],int length)
{
for(int i=0;i<length;i++)
{
for(int j=i+1;j<length;j++)
{
if(arr[i]>arr[j])
{
int temp=arr[j];
arr[j]=arr[i];
arr[i]=temp;
}
}
}
}
3.插入排序
对于任意的低i个位置,认为前i-1个位置是有序的,将当第i个位置的小于前面的元素,依次比较,并依次移动位置,知道空出的位置为0或者,满足条件为止。切记 要用临时变量保存插入元素的值。
void InsertSort(int *arr,int length)
{
int target;
for(int i=1;i<length;i++)
{
target=arr[i];
int pos=i;//应该插入的位置
while(pos>0 && target<arr[pos-1])
{
arr[pos]=arr[pos-1];
pos--;
}
arr[pos]=target;
}
}
- 改进 二分插入排序
//7. 二分插入排序
void InsertSort1(int arr[],int length)
{
for(int i=1;i<length;i++)
{
if(arr[i]<arr[i-1])
{
int target=arr[i];
int left=0;
int right=i-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(target>arr[mid])
{
left=mid+1;
}
else
{
right=mid-1;
}
}
for(int j=i;j>left;j--)
{
arr[j]=arr[j-1];
}
arr[left]=target;
}
}
}
4.希尔排序
希尔排序实在插入排序的基础上进行变化的,希尔排序首先对数据进行分组,即每间隔gas的数据进行排序,然后依次改变gas的大小,最后一次一定要取到gas=1,最后一次得到完成的插入排序。
希尔排序参考视频
//8.希尔排序
void shellSort(int *arr,int length)
{
int gas=length;//每次插入的间隔
int target;//临时存续插入排序待排数据
while(gas>0)
{
//插入排序部分
for(int i=gas;i<length;i++)
{
target=arr[i];
int pos=i;
while(pos>0&& target<arr[pos-gas])//后移动数据
//while(pos>=gas&& target<arr[pos-gas])//后移动数据
{
arr[pos]=arr[pos-gas];
pos-=gas;
}
arr[pos]=target;
}
gas=gas/2;//改变间隔,在进行插入排序,一定要取到1
//进行完整的插入排序
}
}
- 对比插入排序与希尔排序
void InsertSort(int *arr,int length)
{
//int gas=length;
int target;
//while(gas>0)
//{
int gas=1;
for(int i=gas;i<length;i++)
{
target=arr[i];
int pos=i;
while(pos>0 && target<arr[pos-gas])//后移动数据
{
arr[pos]=arr[pos-gas];
pos-=gas;
}
arr[pos]=target;
//}
//gas=gas/2;
}
}
5.堆排序
堆排序是一种选择排序
a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
参考堆排序
参考视频
void HeapAdjust(int *arr,int begin,int length)
{
int temp=arr[begin];//将首元素保持起来
for(int i=2*begin+1;i<length;i=i*2+1)//从i结点的左子结点开始,也就是2i+1处开始
{
if(i+1<length && arr[i]<arr[i+1])//取出左右孩子中较大的元素,该结点的标号为i
i++;
if(temp>=arr[i])//temp是最大值,不用调整
break;
else
{
arr[begin]=arr[i];//根取最大值
begin=i;//对最大值位置在经行操作
}
}
arr[begin]=temp;
}
void HeapSort(int *arr,int length)
{
for(int i=length/2-1;i>=0;i--)//构建一个大顶堆,[(length-1)/2是从有孩子结点的最后一个结点开始]
{
HeapAdjust(arr,i,length); //将[0,1,2...length]的元素构建大顶堆
}
for(int i=length-1;i>0;i--)//逐步将每个根值与末尾元素交换
{
//交换数据
int temp=arr[0];
arr[0]=arr[i];
arr[i]=temp;
HeapAdjust(arr,0,i);//将[0,1,2,3...length]的元素经行重新堆排序
}
}
6.归并排序
依次调用
void MergeSort(int arr[],int length);
void MSort(int arr[],int begin,int end);
void Merge(int arr[], int begin,int mid,int end);
MergeSort归并排序–>MSort排序–>Merge归并
//=============================归并排序记忆版本===========================================
/*
归并排序主要由如下的三个函数组成
void MergeSort(int arr[],int length);
void MSort(int arr[],int begin,int end);
void Merge(int arr[], int low,int mid,int high);
*/
void Merge3(int arr[],int begin,int mid,int end)
{
int* tempArr=(int *)malloc((end-begin+1)*sizeof(int));
// int length=end-begin+1;
// int tempArr[length];
int i=begin;//前半部分
int j=mid+1;//后半部分
int k=0;//前半数据和后半数据,合并到新的数组的下标
while(i<=mid && j<=end)
{
if(arr[i]<=arr[j])
{
tempArr[k++]=arr[i++];
}
else
{
tempArr[k++]=arr[j++];
}
}
while(i<=mid)
{
tempArr[k++]=arr[i++];
}
while(j<=end)
{
tempArr[k++]=arr[j++];
}
//将tempArr中排序完成的数据,从新拷贝到
//begin到end的区间上去
for(i=begin,k=0;i<=end;i++,k++)
{
arr[i]=tempArr[k];
}
delete[] tempArr;
}
void MSort3(int arr[],int begin,int end)
{
if(begin>=end)
return ;
int mid=(begin+end)/2;
MSort3(arr,begin,mid);
MSort3(arr,mid+1,end);
Merge3(arr,begin,mid,end);
}
void Mergesort3(int arr[],int length)
{
MSort3(arr,0,length-1);
}
7.快速排序
通过一趟排序将待排序记录分割成独立的两部分,其中一部分的关键字大于另一部分的关键字,然后对这两部分在继续进行排序,最终达到整个序列有序的目的
和归并排序类似,快速排序算法也分为三部分,依次调用
void QuickSort(int arr[],int length);
void QSort(int arr[],int begin,int end);
void Partition(int arr[], int begin,int end);
QuickSort快速排序–>QSort排序–>Partition位置
int Partition0(int arr[], int begin,int end)
{
int pivotkey=arr[begin];//其实位置作为枢轴
while(begin<end)
{
while(begin<end && arr[end]>=pivotkey)
end--;
//交换数据
int temp=arr[begin];
arr[begin]=arr[end];
arr[end]=temp;
while(begin<end && arr[begin]<=pivotkey)
begin++;
//交换数据
temp=arr[begin];
arr[begin]=arr[end];
arr[end]=temp;
}
return begin;
}
//优化
int Partition(int arr[], int begin,int end)
{
int pivotkey=arr[begin];//其实位置作为枢轴
while(begin<end)
{
while(begin<end && arr[end]>=pivotkey)
end--;
//交换数据
arr[begin]=arr[end];
while(begin<end && arr[begin]<=pivotkey)
begin++;
//交换数据
arr[end]=arr[begin];
}
arr[begin]=pivotkey;
return begin;
}
void QSort(int arr[],int begin,int end)
{
int pivot;
if(begin>=end)
return;
pivot=Partition(arr,begin,end);
QSort(arr,begin,pivot-1);
QSort(arr,pivot+1,end);
}
void QuickSort(int arr[],int length)
{
QSort(arr,0,length-1);
}