排序:
简单排序(冒泡,插入):
冒泡:
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
冒泡排序算法的原理如下:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
这个就不给例题了,emmm,因为过于简单了。
#include<stdio.h>
int main()
{
int i,j,n,t;
int a[1000];
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n-1;i++)
for(j=0;j<n-1-i;j++)
{
if(a[j]>a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
return 0;
}
插入排序:
插入排序(Insertion sort)是一种简单直观且稳定的排序算法。如果有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,算法适用于少量数据的排序,时间复杂度O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。
插入排序的基本思想是:每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
emmm,这个也不给例题,因为也容易。
for(i=0;i<n;i++)
{
t=a[i];
for(j=n-1;j>=0&&a[j-1]>t;j--)
{
a[j]=a[j-1];
}
a[j]=t;
}
希尔排序:
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
for(m=n/2;n>0;m/=2)
{
for(i=0;i<m;i++)
{
for(j=i+m;j<n;j+=m)
{
if(a[j]<a[j-m]
{
int t=a[j];
int k=j-m;
while(k>0&&a[k]>t)
{
a[k+m]=a[k];
k-=m;
}
a[k+m]=t;
}
}
}
}
堆排序:
堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:
最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
创建最大堆(Build Max Heap):将堆中的所有数据重新排序
堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算
void HeapAdjust(int a[],int s,int m)//一次筛选的过程
{
int rc,j;
rc=a[s];
for(j=2*s;j<=m;j=j*2)//通过循环沿较大的孩子结点向下筛选
{
if(j<m&&a[j]<a[j+1]) j++;//j为较大的记录的下标
if(rc>a[j]) break;
a[s]=a[j];s=j;
}
a[s]=rc;//插入
}
void HeapSort(int a[],int n)
{
int temp,i,j;
for(i=n/2;i>0;i--)//通过循环初始化顶堆
{
HeapAdjust(a,i,n);
}
for(i=n;i>0;i--)
{
temp=a[1];
a[1]=a[i];
a[i]=temp;//将堆顶记录与未排序的最后一个记录交换
HeapAdjust(a,1,i-1);//重新调整为顶堆
}
}
归并排序:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
void cishu(int left,int mid,int right)
{
int i,j,k;
i=left;
j=mid+1;
k=left;
while(i<=mid&&j<=right)
{
if(a[i]<=a[j])
b[k++]=a[i++];
else
{
b[k++]=a[j++];
}
}
while(i<=mid)
b[k++]=a[i++];
while(j<=right)
b[k++]=a[j++];
for(i=left; i<=right; i++)
{
a[i]=b[i];
}
}
void dg(int left,int right)
{
int mid;
if(left<right)
{
mid=(left+right)/2;
dg(left,mid);
dg(mid+1,right);
cishu(left,mid,right);
}
}
int main()
{
int n;
int i;
scanf("%d",&n);
for(i=0; i<n; i++)
scanf("%lld",&a[i]);
dg(0,n-1);
printf("%lld\n",z);
return 0;
}
放个例题:
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
现在,给你一个N个元素的序列,请你判断出它的逆序数是多少。
比如 1 3 2 的逆序数就是1。
格式
输入格式
第一行输入一个整数T表示测试数据的组数(1<=T<=5)
每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=100000)
随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所有元素。
数据保证在多组测试数据中,多于10万个数的测试数据最多只有一组。
输出格式
输出该数列的逆序数
样例
样例输入 Copy
2
2
1 1
3
1 3 2
样例输出 Copy
0
1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
long long int a[800000]= {0};
long long int b[800000]= {0};
long long int z=0;
void cishu(int left,int mid,int right)
{
int i,j,k;
i=left;
j=mid+1;
k=left;
while(i<=mid&&j<=right)
{
if(a[i]<=a[j])
b[k++]=a[i++];
else
{
b[k++]=a[j++];
z+=mid-i+1;
(这就唯一的不同)
}
}
while(i<=mid)
b[k++]=a[i++];
while(j<=right)
b[k++]=a[j++];
for(i=left; i<=right; i++)
{
a[i]=b[i];
}
}
void dg(int left,int right)
{
int mid;
if(left<right)
{
mid=(left+right)/2;
dg(left,mid);
dg(mid+1,right);
cishu(left,mid,right);
}
}
int main()
{
int n;
int i;
scanf("%d",&n);
for(i=0; i<n; i++)
scanf("%lld",&a[i]);
dg(0,n-1);
printf("%lld\n",z);
return 0;
}