**排序算法**
1.简单选择排序:
描述:选择排序的基本思想是:每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。基于此思想的算法主要有简单选择排序、树型选择排序和堆排序(这里只介绍一种简单的)。第1趟,在待排序记录r[1]~r[n]中选出最小的记录,将它与r[1]交换;第2趟,在待排序记录r[2]~r[n]中选出最小的记录,将它与r[2]交换;以此类推,第i趟在待排序记录r[i]~r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕。
代码实现:
void SelectSort(int r[], int length)
{
int temp;
for ( i=0 ; i< length-1 ; i++)
{
int index=i;
for (int j=i+1 ; j < length ; j++)
if (r[j] < r[index] )
index=j;
if ( index!=i)
{
temp = r[index];
r[index] = r[i];
r[i] = temp;
}
}
}
2.冒泡排序:
//时间复杂度:O(n^2).
描述:
每次比较两个相邻的元素,如果顺序错误则交换。
代码实现:
例题:
排序问题
Time Limit: 1000MS Memory Limit: 65536KB
Problem Description
输入10个整数,将它们从小到大排序后输出,并给出现在每个元素在原来序列中的位置。
Input
输入数据有一行,包含10个整数,用空格分开。
Output
输出数据有两行,第一行为排序后的序列,第二行为排序后各个元素在原来序列中的位置。
Example Input
1 2 3 5 4 6 8 9 10 7
Example Output
1 2 3 4 5 6 7 8 9 10
1 2 3 5 4 6 10 7 8 9
Hint
Author
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[10], b[10], i, j;
for(i=0;i<10;i++)
{
scanf("%d", &a[i]);
b[i] = i + 1;
}
for(i=0;i<10;i++)
{
for(j=0;j<9-i;j++)
{
int t1 = 0, t2 = 0;
if(a[j]>a[j+1])
{
t1 = a[j];
a[j] = a[j+1];
a[j+1] = t1;
t2 = b[j];
b[j] = b[j+1];
b[j+1] = t2;
}
}
}
for(i=0;i<10;i++)
{
printf("%d", a[i]);
if(i!=9)
printf(" ");
else
printf("\n");
}
for(i=0;i<10;i++)
{
printf("%d", b[i]);
if(i!=9)
printf(" ");
}
return 0;
}
3.桶排序:(基数排序)
//时间复杂度:O(n).
描述:
桶排序 (Bucket sort)或所谓的箱排序,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。
代码实现(简单):
例题:
数据结构实验之排序三:bucket sort
Time Limit: 150MS Memory Limit: 65536KB
Problem Description
根据人口普查结果,知道目前淄博市大约500万人口,你的任务是帮助人口普查办公室按年龄递增的顺序输出每个年龄有多少人,其中不满1周岁的按0岁计算,1到2周岁的按1岁计算,依次类推,大于等于100岁的老人全部按100岁计算。
Input
输入第一行给出一个正整数N(<=5000000),随后连续给出N个整数表示每个人的年龄,数字间以空格分隔。
Output
按年龄递增的顺序输出每个年龄的人口数,人口数为0的不输出,每个年龄占一行,数字间以一个空格分隔,行末不得有多余空格或空行。
Example Input
10
16 71 17 16 18 18 19 18 19 20
Example Output
16 2
17 1
18 3
19 2
20 1
71 1
Hint
Author
xam
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int a[200];
int main()
{
int n, m;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d", &m);
if(m>=100)
a[100]++;
else
a[m]++;
}
for(int i=0;i<104;i++)
{
if(a[i])
{
printf("%d %d\n", i, a[i]);
}
}
return 0;
}
4.快速排序:
//时间复杂度:O(nlogn)—O(n^2).
描述:分治处理。
先找到一个基准数,然后从左到右,从右到左分别探测,直到找到了比基准数大、比基准数小的数字,然后交换,如此循环。
代码实现:
void sort(int n[], int left, int right)
{
int i = left, j = right;
int key = n[left];
if(i>=j)
return ;
while(i<j)
{
while(i<j&&n[j]>=key)
j--;
n[i] = n[j];
while(i<j&&n[i]<=key)
i++;
n[j] = n[i];
}
n[i] = key;
sort(n, left, i-1);
sort(n, i+1, right);
}
5.直接插入排序:
//时间复杂度:O(n^2).
//空间复杂度:O(1).
描述:
⒈ 从第一个元素开始,该元素可以认为已经被排序
⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描
⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置
⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
⒌ 将新元素插入到下一位置中
⒍ 重复步骤2~5
void insertsort()
{
for(int j=1; j<n; j++)
{
if(a[j]<a[j-1])
{
int temp = a[j];
int index = j-1;
while(index>=0&&a[index]>temp)
{
a[index+1] = a[index];
index-=1;
}
a[index+1] = temp;
}
}
}
代码实现:
6*.希尔排序(缩小增量排序)(复杂一点的插入排序)*:
//时间复杂度:O(nlogn).
//空间复杂度:O(1).
void shellsort()
{
for(int gap=n/2;gap>=1;gap/=2)
{
for(int i=0;i<gap;i++)
{
//插入排序
for(int j=i+gap;j<n;j+=gap)
{
if(Array[j]<Array[j-gap])
{
int temp = Array[j];
int index = j-gap;
while(index>=0&&a[index]>temp)
{
a[index+gap] = a[index];
index -= gap;
}
a[index+gap] = temp;
}
}
}
}
}
7.鸡尾酒排序:
听起来很高端吧~其实,它也叫Shaker排序或双向冒泡排序,是冒泡排序的一种轻微改动,是一种稳定的排序算法。
与冒泡排序的不同点:
冒泡是每次从前向后按一个次序排列。
Shaker是先从前向后,再从后向前,在从前往后遍历时,记录最后发生交换的两个元素的位置,从后往前遍历时就从这个位置开始……
#include <bits/stdc++.h>
using namespace std;
int a[12121];
int b[12121];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
b[i] = a[i];
}
int left = 0, right = n-1, shift = 0, temp;
int count = 0;
while(left<right)//鸡尾酒排序
{
for(int i=left;i<right;i++)//向右进行冒泡排序
{
if(a[i]>a[i+1])
{
temp = a[i], a[i] = a[i+1], a[i+1] = temp;//change
count++;
shift = i;//记录最后一次所在状态
}
}
right = shift;
for(int i=right;i>left;i--)//向左进行冒泡排序
{
if(a[i]<a[i-1])
{
temp = a[i], a[i] = a[i-1], a[i-1] = temp;//change
count++;
shift = i;
}
}
left = shift;
}
int count2 = 0;
for(int i=0;i<n;i++)//冒泡排序
{
for(int j=0;j<n-i-1;j++)
{
if(b[j]>b[j+1])
{
temp = b[j], b[j] = b[j+1], b[j+1] = temp;
count2++;
}
}
}
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
cout<<endl<<count<<endl;//冒泡的交换次数
for(int i=0;i<n;i++)
cout<<b[i]<<" ";
cout<<endl<<count2<<endl;//鸡尾酒的交换次数
return 0;
}
8.堆排序:
堆排序(HeapSort)是一树形选择排序。堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系(参见二叉树的顺序存储结构),在当前无序区中选择关键字最大(或最小)的记录
void HeapAdjust(int H[],int s, int length)
{
int tmp = H[s];
int child = 2*s+1; //左孩子结点的位置。(i+1 为当前调整结点的右孩子结点的位置)
while (child < length)
{
if(child+1 <length && H[child]<H[child+1]) // 如果右孩子大于左孩子(找到比当前待调整结点大的孩子结点)
{
++child ;
}
if(H[s]<H[child]) // 如果较大的子结点大于父结点
{
H[s] = H[child]; // 那么把较大的子结点往上移动,替换它的父结点
s = child; // 重新设置s ,即待调整的下一个结点的位置
child = 2*s+1;
}
else // 如果当前待调整结点大于它的左右孩子,则不需要调整,直接退出
{
break;
}
H[s] = tmp; // 当前待调整的结点放到比其大的孩子结点位置上
}
print(H,length);
}
void BuildingHeap(int H[], int length)
{
//最后一个有孩子的节点的位置 i= (length -1) / 2
for (int i = (length -1) / 2 ; i >= 0; --i)
HeapAdjust(H,i,length);
}
void HeapSort(int H[],int length)
{
//初始堆
BuildingHeap(H, length);
//从最后一个元素开始对序列进行调整
for (int i = length - 1; i > 0; --i)
{
//交换堆顶元素H[0]和堆中最后一个元素
int temp = H[i];
H[i] = H[0];
H[0] = temp;
//每次交换堆顶元素和堆中最后一个元素之后,都要对堆进行调整
HeapAdjust(H,0,i);
}
}
9.归并排序:
void mergearray(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + 1;
int m = mid, n = last;
int k = 0;
while (i <= m && j <= n)
{
if (a[i] <= a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while (i <= m)
temp[k++] = a[i++];
while (j <= n)
temp[k++] = a[j++];
for (i = 0; i < k; i++)
a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
if (first < last)
{
int mid = (first + last) / 2;
mergesort(a, first, mid, temp); //左边有序
mergesort(a, mid + 1, last, temp); //右边有序
mergearray(a, first, mid, last, temp); //再将二个有序数列合并
}
}
//mergesort(a, 0, n - 1, p);