1.归并排序
备注:归并排序虽然高效且稳定,但是它在处理的过程当中,除了用于保存输入数据的数组之外,还需要临时占用一部分内存空间。
2.分割:
题目:将指定的数组按标记值M分割成为小于M的部分和大于M的部分
注意点:分割会交换不相邻的元素,用于排序时要注意
代码:
3.快速排序:
a.题目:将指定的扑克在考虑花色和点数的情况下按升序排列,另外判断这些输入的数字和输出的顺序是否一致
b.步骤:
1)以数组的最末尾的值为标准值“分割”数组
2)将分割好的数组执行快速排序
3)合并,然后递归执行这三步
c.注意点:要提高效率,可以在每次分割时以需要分割的数组的“中间值”为标准值
d.代码:
4.计数排序:
a.简介:它能在线性时间(O(n+k))内对包含n个元素的数组进行排序,其中数组无素均大于等于0且小于k
b.详述:对于输入数组A的各元素A(j)进行排序时,将小于等于A(j)的元素数记录在计数数组C中,然后根据C中的数值计算A(j)在输出数组B中的位置。考虑到存在多个相等元素的情况,我们还需要在输出元素A(j)【加入B】之后修正计数用的C(A(j))
c.注意:其运行所需要的时间及内存空间也与A(j)的最大值成正比
d.代码:
5.使用标准库排序:
a.定义:使用标准库里的sort
a.步骤提要:将原有数组分割平分成两个数组,然后分别排序。将排好序的局部数组整合成一个数组,然后递归执行此过程
b.过程:
//
// Created by 叶子 on 2018/1/27.
// 归并排序
//
#include "iostream"
using namespace std;
#define MAX 500000
#define SENTINEL 20000000;
int L[MAX/2+2],R[MAX/2+2];
int cnt;
void merge(int A[],int n,int left,int mid,int right) {
int n1 = mid - left;
int n2 = right - mid;
for (int i = 0; i < n1; i++) L[i] = A[left + i];
for (int i = 0; i < n2; i++) R[i] = A[mid + i];
L[n1] = R[n2] = SENTINEL;
int i = 0, j = 0;
for (int k = left; k < right; k++) {
cnt++;
if (L[i] <= R[j]) {
A[k] = L[i++];
} else {
A[k] = R[j++];
}
}
}
void mergeSort(int a[], int n, int left, int right) {
if (left + 1 < right) {
int mid = (left + right) / 2;
mergeSort(a, n, left, mid);
mergeSort(a, n, mid, right);
merge(a, n, left, mid, right);
}
}
int main(){
int A[MAX],n,i;
cnt = 0;
cin >> n;
for ( i = 0 ; i < n ; i ++) cin >> A[i];
mergeSort(A,n,0,n);
for ( i = 0 ; i < n ; i ++){
if ( i ) cout << " ";
cout << A[i];
}
cout << endl;
cout << cnt <<endl;
}
备注:归并排序虽然高效且稳定,但是它在处理的过程当中,除了用于保存输入数据的数组之外,还需要临时占用一部分内存空间。
2.分割:
题目:将指定的数组按标记值M分割成为小于M的部分和大于M的部分
注意点:分割会交换不相邻的元素,用于排序时要注意
代码:
//
// Created by 叶子 on 2018/1/27.
// 分割
//
#include <stdio.h>
#define MAX 100000
int A[MAX],n;
int partition(int p,int r){
int x,i,j,t;
x = A[r];
i = p - 1;
for ( j = p ; j < r ; j ++){
if ( A[j] <= x){
i ++;
t = A[i];A[i] = A[j];A[j] = t;
}
}
t = A[i+1];A[i+1]= A[r];A[r] = t;
return i+1;
}
int main(){
int i,q;
scanf("%d",&n);
for ( i = 0 ; i < n ; i ++) scanf("%d",&A[i]);
q = partition(0,n-1);
for ( i = 0 ; i < n ; i ++){
if ( i ) printf(" ");
if ( i == q) printf("[");
printf("%d",A[i]);
if ( i == q) printf("]");
}
printf("\n");
return 0;
}
3.快速排序:
a.题目:将指定的扑克在考虑花色和点数的情况下按升序排列,另外判断这些输入的数字和输出的顺序是否一致
b.步骤:
1)以数组的最末尾的值为标准值“分割”数组
2)将分割好的数组执行快速排序
3)合并,然后递归执行这三步
c.注意点:要提高效率,可以在每次分割时以需要分割的数组的“中间值”为标准值
d.代码:
//
// Created by 叶子 on 2018/1/27.
// 快速排序与归并排序的比较
//
#include <stdio.h>
#define MAX 100000
#define SENTINEL 2000000000
struct Card {
char suit;
int value;
};
struct Card L[MAX / 2 + 2],R[MAX / 2 + 2];
void merge(struct Card A[],int n ,int left,int mid,int right){
int i,j,k;
int n1 = mid - left;
int n2 = right - mid;
for ( i = 0 ; i < n1 ; i ++) L[i] = A[left+i];
for ( i = 0 ; i < n2 ; i ++) R[i] = A[mid + i];
L[n1].value = R[n2].value = SENTINEL;
i = j = 0;
for ( k = left; k < right ; k ++){
if ( L[i].value <= R[j].value){
A[k] = L[i++];
}else{
A[k] = R[j++];
}
}
}
void mergeSort(struct Card A[],int n ,int left,int right){
int mid;
if ( left + 1 < right){
mid = (left + right) /2 ;
mergeSort(A,n,left,mid);
mergeSort(A,n,mid,right);
merge(A,n,left,mid,right);
}
}
int partition(struct Card A[],int n ,int p ,int r){
int i,j;
struct Card t,x;
x = A[r];
i = p -1;
for ( j = p;j < r ; j ++){
if ( A[j].value <= x.value){
i ++;
t = A[i]; A[i] = A[j];A[j] = t;
}
}
t = A[i+1];A[i+1] = A[r];A[r] = t;
return i+1;
}
void quickSort(struct Card A[],int n,int p ,int r){
int q;
if ( p < r){
q = partition(A,n,p,r);
quickSort(A,n,p,q-1);
quickSort(A,n,q+1,r);
}
}
int main(){
int n,i,v;
struct Card A[MAX],B[MAX];
char S[10];
int stable = 1;
scanf("%d",&n);
for ( i = 0 ; i < n ; i ++){
scanf("%s %d",S,&v);
A[i].suit = B[i].suit = S[0];
A[i].value = B[i].value = v;
}
mergeSort(A,n,0,n);
quickSort(B,n,0,n-1);
for ( i = 0 ; i < n ; i ++){
if ( A[i].suit != B[i].suit ) stable = 0;
}
if ( stable == 1) printf("Stable\n");
else printf("Not stable\n");
for ( i = 0 ; i < n ; i ++){
printf("%c %d\n",B[i].suit,B[i].value);
}
return 0;
}
4.计数排序:
a.简介:它能在线性时间(O(n+k))内对包含n个元素的数组进行排序,其中数组无素均大于等于0且小于k
b.详述:对于输入数组A的各元素A(j)进行排序时,将小于等于A(j)的元素数记录在计数数组C中,然后根据C中的数值计算A(j)在输出数组B中的位置。考虑到存在多个相等元素的情况,我们还需要在输出元素A(j)【加入B】之后修正计数用的C(A(j))
c.注意:其运行所需要的时间及内存空间也与A(j)的最大值成正比
d.代码:
//
// Created by 叶子 on 2018/1/28.
// 计数排序
#include "stdio.h"
#include "stdlib.h"
#define MAX 200001
#define VMAX 10000
int main(){
int A[VMAX + 1],B[VMAX + 1],C[VMAX + 1], n,i,j;
scanf("%d",&n);
for ( i = 0 ; i <= VMAX ; i ++) C[i] = 0;
for ( i = 0 ; i < n ; i ++){
scanf("%hu",&A[i+1]);
C[A[i+1]] ++;
}
for ( i = 1 ; i <= VMAX ; i ++) C[i] = C[i] + C[i-1];
for ( j = 1 ; j <= n ; j ++){
B[C[A[j]]] = A[j];
C[A[j]] --;
}
for ( i = 1 ; i <=n ; i ++){
if ( i > 1) printf (" ");
printf ("%d",B[i]);
}
printf("\n");
return 0;
}
5.使用标准库排序:
a.定义:使用标准库里的sort
b.代码:
//
// Created by 叶子 on 2018/1/28.
// 用C++内置函数排序
//
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;
int main(){
int n;
vector<int> v;
cin >> n;
for ( int i = 0 ; i < n ; i ++){
int x; cin >> x;
v.push_back(x);
}
sort(v.begin(),v.end());
for ( int i = 0 ; i < v.size() ; i ++){
cout << v[i] << " ";
}
cout << endl;
return 0;
}
6.最小成本排序:
a.题目:求给指定的数组进行排序的最小交换次数
b.解析:需要考虑“借整体最小元素”与“不借整体最小元素”两种情况
c.代码:
//
// Created by 叶子 on 2018/1/28.
// 最小成本统计
//
#include "iostream"
#include "algorithm"
using namespace std;
static const int MAX = 1000;
static const int VMAX = 10000;
int n,A[MAX],s;
int B[MAX],T[VMAX + 1];
int solve(){
int ans = 0;
bool V[MAX];
int v;
for ( int i = 0 ; i < n ; i ++){
B[i] = A[i];
V[i] = false;
}
sort(B,B+n);
for ( int i = 0 ; i < n ; i ++) T[B[i]] = i ;
for ( int i = 0 ; i < n ; i ++){
if (V[i] ) continue;
int cur = i ;
int S = 0;
int m = VMAX;
int an = 0 ;
while ( 1 ) {
V[cur] = true;
an ++;
v = A[cur];
m = min (m,v);
S += v;
cur = T[v];
if ( V[cur] ) break;
}
ans += min(S+(an-2) * m,m+S+(an+1)*s);
}
return ans;
}
int main(){
cin >> n;
s = VMAX;
for ( int i = 0 ; i < n ; i ++){
cin >> A[i];
s = min(s,A[i]);
}
int ans = solve();
cout << ans << endl;
return 0;
}