冒泡排序:每次选择一个与相邻的元素比较,并且判断是否两两交换。(稳定)因为是严格的大于或小于。
插入排序:每次选择一个元素开始,并且从最后一个开始比较选择合适位置插入。(稳定)
逆序对:如果i<j 且a[i]>a[j],则称i,j为一组逆序对。即一个序列的逆序对个数为该序列排序结束后需要交换元素的次数。
排序其实质是消除逆序对,交换相邻两个元素就可以消去一对逆序对,则在插入排序时,不仅与元素个数有关,还与逆序对个数有关。则如果序列基本有序时,此时逆序对个数较少,插入排序效率就比较高了。
#include<bits/stdc++.h>
#define maxsize 1005
#define inf 0x3f3f3f3f
using namespace std;
void bubble_sort(int a[],int n);///冒泡排序
void insert_sort(int a[],int n);///插入排序
int main()
{
int a[5] = {1,3,4,2,5};
insert_sort(a,5);
for(int i = 0; i < 5; i++)
cout<<a[i]<<" ";
return 0;
}
void bubble_sort(int a[],int n)
{
bool flag;///便于判断已经有序就不必再进行下去
for(int i = n;i > 0; i--)
{
flag = true;
for(int j = 0;j < i; j++)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
flag = false;
}
}
if(flag) break;
}
}
void insert_sort(int a[],int n)
{
int tmp,j;
for(int i = 1; i < n; i++)
{
tmp = a[i];///记录待插元素
for(j = i;j>=0 && a[j-1]>tmp;j--)
a[j]= a[j-1];///往后移动1个位置
a[j] = tmp;///插入该位置
}
}
希尔排序:通过设置d( 增量间距 )来增加每次消除的逆序对的数目,其实插入排序就是一种特殊的希尔排序,插入排序中d=1,一般的增量选取为d=n/2,反复取下去。但是构造巧妙的增量会降低一些时间复杂度。如Sedgewick增量。(不稳定)
第一趟
第二趟
int tmp[10]={41,19,5,1,0};///部分Sedgewick增量
void shell_sort(vector<int> &a,int n)///O(N^3/2)
{
int num,j,i;
for(int i=0;tmp[i]>=n;i++)//要求初始增量不能大于待排序列长度
;
for(int d = tmp[i];d>0;d=tmp[++i])//最外层的增量循环
{
for(int p = d;p<n;p++)//循环排子序列
{
num = a[p];
for(j = p;j>=d && a[j-d]>num;j-=d)
a[j] = a[j-d];
a[j] = num;
}
}
}
堆排序:利用最大堆或最小堆的特点,最坏情况下时间复杂度也是n*logn。(不稳定)
这是一个未改进的版本
void heap_sort(vector<int> &a,int n)
{
//额外需要了tmp_a的空间开销,和导回原数组的时间开销,所以效果不是最好的。
vector<int> tmp_a;
buildHeap(a);
for(int i = 0;i < n;i++)//每次弹出最小元素存入临时数组
tmp_a[i]=deleteMin(a);
for(int i = 0;i < n;i++)//因为是按增序排列,所以需要导回原数组
a[i] = tmp_a[i];
}
比如按增序排列,改进思路是每次将堆中最大的元素(即堆顶元素)与最后一个元素交换位置,然后重新调整剩下的堆序列,这样复杂度会比n*logn好一点点。
void heap(vector<int> &a,int index,int len)///以index为根节点,向下调整子堆。
{
int temp_num = a[index];///标记根节点
int parent,child;
///因为下标是从0开始,所以是parent*2+1
for(parent = index;(parent<<1)+1 < len;parent = child)
{
child = (parent<<1)+1;///左孩子
if((child != len-1) && a[child] < a[child+1])///判断右孩子存在,且选取左右孩子中最大的。
child++;
if(a[child] <= temp_num) break;
else
a[parent] = a[child];///说明父节点小于最大的孩子节点,父节点下去,孩子上来。
}
a[parent] = temp_num;///找到合适位置
}
void heap_sort(vector<int> &a ,int len)
{
for(int i = len>>1-1;i >= 0;i--)///从最后一个叶子节点的父节点开始调整每一个子堆。
heap(a,i,len);
for(int i = len-1;i >= 0;i--)///调整将最大元素放在最后
{
swap(a[0],a[i]);
heap(a,0,i);
}
}
归并排序(稳定的强n*lgn)
因为需要比较大的存储空间,因此一般用于外部排序,其利用的是分治的思想。
有递归和非递归版本,这里我记录的是非递归。
#include<bits/stdc++.h>
#define maxsize 100005
#define inf 0x3f3f3f3f
using namespace std;
void Print(int arr[]);
void merge_sort(int arr[]);
void merges_pass(int arr[],int tmp_arr[],int length);
void merges(int arr[],int tmp_arr[],int L,int R,int R_end);
int arr[maxsize];
int tmp_arr[maxsize];
int n;
int main()
{
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%d",&arr[i]);
merge_sort(arr);
Print(arr);
return 0;
}
void Print(int arr[])
{
for(int i = 0;i < n; i++)
{
printf("%d",arr[i]);
if(i != n-1)
printf(" ");
}
}
void merge_sort(int arr[])///归并有序子列,最终结果在arr中
{
int length = 1;///起始子列长度
while(length < n)
{
merges_pass(arr, tmp_arr, length);///arr一趟归并导入tmp中
length <<= 1;
merges_pass(tmp_arr, arr, length);
length <<= 1;
}
}
void merges_pass(int arr[],int tmp_arr[],int length)///一趟排序
{
int i;
for(i = 0;i <= n-(length<<1); i += (length<<1) )///先处理偶数对,或许会剩下
merges(arr, tmp_arr, i, i+length, i+(length<<1)-1);
if(i+length < n)///有剩下一个子列
merges(arr, tmp_arr, i, i+length, n-1);
else
for(int index = i; index < n;index++)///导回tmp中
tmp_arr[index] = arr[index];
}
///L:左边子列起始位置 R:右边子列起始 R_end:右边末尾
void merges(int arr[],int tmp_arr[],int L,int R,int R_end)
{
int L_end = R-1;
int index = L;///tmp起始下标
while(L <= L_end && R <= R_end)///归并过程
{
if(arr[L] <= arr[R])
tmp_arr[index++] = arr[L++];
else
tmp_arr[index++] = arr[R++];
}
///处理剩余元素
while(L <= L_end)
tmp_arr[index++] = arr[L++];
while(R <= R_end)
tmp_arr[index++] = arr[R++];
}
一组测试用例
***********************************************************************按键值对排序
以前写过对某键值对排序的问题,如下A.x != B.x 按升序排列,否则将 y 按降序排列并且输出将全部键值输出
struct node{
int x;
int y;
string z;
};
/*
//sample
mike 98 65
smith 64 88
jack 51 99
lucy 64 91
*/
就是结构体排序,然后写一个cmp函数就好。
bool cmp(node A,node B)
{
if(A.x!=B.x) return A.x < B.x;
return A.y > B.y;
}