原地排序:原地排序就是指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。
稳定排序:对于相等的元素,在排序后,原来靠前的元素依然靠前相等元素的相对位置没有改变。
插入排序
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。
c++代码实现
#include<bits/stdc++.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int arr[6] = {9,3,4,2,6,5}; //对arr数组进行插入排序
void InsertPX(int arr[],int n){
int i;
for(i = 1;i < n;i++)
{
int temp = arr[i]; //从待排数组中取出一个元素
int j = i - 1; //j此时为有序组的最后一个元素
while(j >= 0&&arr[j] > temp) //当待排入的数据大于已经排入的数据
{
arr[j+1] = arr[j]; //待排入数据的地址的值换为前面大的值
j--;
}
arr[j+1] = temp; //将待排入的数据插入
}
for(i = 0;i < n;i++)
printf("%d ",arr[i]);
}
归并排序
归并排序:建立三个索引,将两个已经排好序的元素数组,来比较当前的头部元素谁更小,就放入最终的位置中,之后索引继续进行移动来比较。
一种空间换时间的算法时间复杂度为O(n^2)。
c++代码实现
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
// 将arr[l...mid]和arr[mid+1...r]进行归并排序
void __merge(int arr[] ,int l ,int mid ,int r){
//声明一个临时数组
int temp[r-l+1],i,j,k;
for( i = l ; i <= r ; i++ )
temp [i-l] = arr[i]; //初始化temp数组
//设置两个索引分别指向了左侧子数组开头的位置
//和右侧子数组开头的位置
j = mid + 1,i = l;
for(k = l;k <= r;k++)
{
if( i > mid )
{
arr[k] = temp[j-l];
j++;
}
else if( j > r)
{
arr[k] = temp[i-l];
i++;
}
else if(temp[i-l] < temp[j-l])
{
arr[k] = temp[i-l];
i++;
}else{
arr[k] = temp[j-l];
j++;
}
}
}
// 分治使用 归并排序 对arr[l...r]的范围进行排序
void __mergeSort(int arr[],int l,int r)
{
if( l >= r )
return ; //处理结束
int mid = (l + r)/2; //找到区间中点在哪
__mergeSort( arr , l , mid); //对左边归并排序
__mergeSort( arr , mid+1 , r); //对右边归并排序
//将这两部分进行一次merge操作完成整个归并排序
__merge( arr , l , mid , r);
}
void mergeSort(int arr[],int n)
{
//代表子函数
__mergeSort( arr , 0 , n-1 );
}
int main()
{
int arr[] = {100,22,55,4,1,5,4,15,1,5,666,7,7,7,7,7,888};
mergeSort(arr,17);
for(int i = 0;i < 17;i++)
cout << arr[i] <<" ";
return 0;
}
快速排序
单路快排思想,数组分为两部分,arr[l+1...j] < v, arr[j+1..i-1]>v,当i指向的值e大于v的时候, i++, 当e小于v的时候, swap(arr[++j],arr[i]) 然后i++.时间复杂度为O(nlogn)。是不稳定的排序方法。
c++代码实现
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
//对arr[l..r]部分进行partition操作
//返回p,使得arr[l..p-1] < arr[p] ; arr[p+1..r] > arr[p]
int __partition(int arr[],int l,int r){
int sign = arr[l]; //取数组第一个元素为分割的标志
//arr[l+1..j] < v;arr[j+1..r] > v;
int j = l,i;
for( i = l+1;i <= r;i++ )
{
if(arr[i] < sign)
{
swap(arr[j+1],arr[i]); //找到第一个大于v的元素 放到arr[j+1]的位置
j++;
}
}
swap(arr[l],arr[j]); //把标志放到合适的位置
return j; //最终j的位置就是下一个递归使用到的p
}
//对arr[l...r]进行快速排序
void __quickSort( int arr[],int l ,int r ){
if(l >= r) //递归到底的时候不需要排序
return;
int p = __partition(arr,l,r);
__quickSort(arr,l,p-1);
__quickSort(arr,p+1,r);
}
void quickSort(int arr[],int n)
{
__quickSort(arr,0,n-1);
}
int main()
{
int arr[] = {100,22,55,4,1,5,4,15,1,5};
quickSort(arr,10);
for(int i = 0;i < 10;i++)
cout << arr[i] <<" ";
return 0;
}
堆排序
堆分为最大堆和最小堆,是完全二叉树。最大堆的要求是每个子节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。时间复杂度为O(nlogn)。是不稳定的排序方法。
以最大堆为例:
ShiftUp实现过程。插入一个元素为52时
ShiftDown实现过程。插入一个元素为52时
c++代码实现
#include <bits/stdc++.h>
using namespace std;
//最大堆骨架(堆是一个完全二叉树)
template <typename Item>
class MaxHeap{
private:
Item*data; //节点信息
int count; //节点个数
int capacity; //输入堆的最大容量
//ShiftUp的实现
void ShiftUp( int k ){
while( k > 1 && data[k/2] < data[k] )
{ //当父节点的值小于新添加的节点,交换父节点和新添加节点的值
//并且保证k的值是大于一的
swap(data[k/2],data[k]);
k /= 2; //更新此时新添加节点在堆中的位置
}
}
//ShiftDown的实现
void ShiftDown( int k ){
//当此时的节点有左孩子
while( 2*k <= count ){
int j = 2*k;
if( j+1 <= count && data[j+1] > data[j] )
//当此节点有右孩子,并且右孩子大于左孩子
j += 1;
if( data[k] >= data[j] ) break; //如果此时的节点大于左孩子也大于右孩子
swap( data[k],data[j] );
k = j;
}
}
public:
MaxHeap(int capacity){
data = new Item[capacity+1];
count = 0;
this -> capacity = capacity;
}
~MaxHeap(){
//释放节点信息空间
delete [] data;
}
int size(){
return count;
}
bool isEmpty(){
//如果节点数量为0 返回true
return count == 0;
}
// 通过Shift Up方法向堆内添加元素保证堆的定义
void insert(Item item){
assert( count+1 <= capacity ); //判断此时堆中是否能容纳新的元素
data[count+1] = item; //新的元素放到(count+1)的位置
count++; //节点信息加一(此时新添加的元素存在count的索引中)
//将count这个元素向上移动来维持堆的定义
ShiftUp( count );
}
// 通过extractMax方法取出最大堆的元素
Item extractMax(){
assert( count > 0 ); //保证堆不为空
Item ret = data[1];
swap( data[1],data[count] ); //把最后一个元素放到第一个位置
count --;
ShiftDown(1); //通过ShiftDown方法维持取出元素后最大堆的性质
return ret;
}
};
int main()
{
int arr[11],n=10,i;
MaxHeap <int> maxheap = MaxHeap<int>(100); //最大堆的储存空间为100
printf("请输入10个元素\n");
while(n--)
{
scanf("%d",&i);
maxheap.insert(i); //向堆中插入10各元素
}
printf("排序后的结果为\n");
for( i = 9; i >= 0; i-- )
{
arr[i] = maxheap.extractMax(); //完成从小到大排序
cout << arr[i] << " ";
}
return 0;
}