PPT:第五章 排序
三个基础排序
两数交换
void swap(int* x, int* y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
}
冒泡排序
//冒泡排序 每次遍历两两比较,将最大元素互换到最后一个位置
void bubble_sort(int arr[], int len) {
for (int i = 0; i < len-1; i++) {
for (int j = 0; j < len - 1 - i; j++) {//第一轮换由于是两两比较,一定会吧最大的元素换到最后面,则下一轮可不与最后一个元素比较
if (arr[j] > arr[j + 1])
swap(&arr[j], &arr[j + 1]);
}
}
}
插入排序
//直接插入排序 每次遍历将未排序数组第一个数插入到已排序数组中
void insertion_sort(int arr[], int len)
{
for (int i = 1; i < len; i++) {//从下标为1的元素开始选择合适的位置插入
int key = arr[i];//key为本轮要插入的数据
int j = i - 1;//比较区间为[0,i-1]的数据,即已排列好的递增序列
while (j >= 0 && key < arr[j]) {//从已经排序的序列最右边的开始比较,找到比其小的数(key应插入在第一个比key小的数的后面)。
//当key>=arr[j]或j<0时跳出,因为与key比较的是递增序列,我们只需找到比key小的第一个数
arr[j + 1] = arr[j];//将比key大的数(arr[j])逐次往后移,给key让空
j--;
}
arr[j + 1] = key;//将key插入到比key小的数的后一个位置。
}
}
选择排序
//选择排序 每次遍历找到最小元素,把他放到已排序数组的最后一个位置
void selection_sort(int arr[], int len) {
int i, j;
for (i = 0; i < len - 1; i++) {
int min = i;
for (j = i + 1; j < len; j++) {//找到最小的元素下标
if (arr[j] < arr[min])
min = j;
}
swap(&arr[min], &arr[i]);//把最小的元素与第i个位置互换
}
}
总。
#include<algorithm>
#include<iostream>
using namespace std;
void swap(int* x, int* y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
}
//直接插入排序 每次遍历将未排序数组第一个数插入到已排序数组中
void insertion_sort(int arr[], int len)
{
for (int i = 1; i < len; i++) {//从下标为1的元素开始选择合适的位置插入
int key = arr[i];//key为本轮要插入的数据
int j = i - 1;//比较区间为[0,i-1]的数据,即已排列好的递增序列
while (j >= 0 && key < arr[j]) {//从已经排序的序列最右边的开始比较,找到比其小的数(key应插入在第一个比key小的数的后面)。
//当key>=arr[j]或j<0时跳出,因为与key比较的是递增序列,我们只需找到比key小的第一个数
arr[j + 1] = arr[j];//将比key大的数(arr[j])逐次往后移,给key让空
j--;
}
arr[j + 1] = key;//将key插入到比key小的数的后一个位置。
}
}
//冒泡排序 每次遍历两两比较,将最大元素互换到最后一个位置
void bubble_sort(int arr[], int len) {
for (int i = 0; i < len-1; i++) {
for (int j = 0; j < len - 1 - i; j++) {//第一轮换由于是两两比较,一定会吧最大的元素换到最后面,则下一轮可不与最后一个元素比较
if (arr[j] > arr[j + 1])
swap(&arr[j], &arr[j + 1]);
}
}
}
//选择排序 每次遍历找到最小元素,把他放到已排序数组的最后一个位置
void selection_sort(int arr[], int len) {
int i, j;
for (i = 0; i < len - 1; i++) {
int min = i;
for (j = i + 1; j < len; j++) {//找到最小的元素下标
if (arr[j] < arr[min])
min = j;
}
swap(&arr[min], &arr[i]);//把最小的元素与第i个位置互换
}
}
int main() {
int n = 10;
int arr[10] = { 2,67,34,56,3,45,60,86,32,5 };
//insertion_sort(arr, n);
//bubble_sort(arr, n);
selection_sort(arr, n);
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
例题
4.G POJ 2388 Who’s in the Middle 排个序就行了
4.H UVA 299 Train Swapping 冒泡排序记一下交换次数
#include <iostream>
using namespace std;
#define N 10007
int sort(int arr[], int n) {
int num = 0;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
num++;
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return num;
}
int main() {
int arr[N];
int num = 0;
int n;
cin >> n;
while (n--) {
cin >> num;
for (int i = 0; i < num; i++)
cin >> arr[i];
cout << "Optimal train swapping takes " << sort(arr, num) << " swaps." << endl;
}
return 0;
}
4.I POJ 1007 DNA Sorting 冒泡找一下有多少逆序对,再根据逆序对数排一下序即可
##做题一定要细心!!!!!!!!!!m和n又搞混了。。。。。
#include <iostream>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define N 107
string s[N];
void insertion_sort(int arr[], int len){
for(int i=1;i<len;i++){
int key=arr[i];
string keys;
keys=s[i];
int j=i-1;
while(j>=0&&key<arr[j]){
arr[j+1]=arr[j];
s[j+1]=s[j];
j--;
}
arr[j+1]=key;
s[j+1]=keys;
}
}
int main(){
int n,m;
int nixu[N];
cin>>n>>m;
getchar();
for(int k=0;k<m;k++){
cin>>s[k];
int ans=0;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
if(s[k][i]>s[k][j])
ans++;
}
}
nixu[k]=ans;
}
insertion_sort(nixu,m);
for(int i=0;i<m;i++){
cout<<s[i]<<endl;
}
return 0;
}
更新
归并排序
参考代码
void Merge(int r[],int temp[],int s,int m,int t){
//将数组r的两个连续的有序序列:第s到第m个元素,第m+1到第t个元素,合并产生一个有序序列:第s到第t个元素的有序序列
int i=s;
int j=m+1;//i,j是两个连续的有序序列的开始位置
int k=i;//k 临时数组temp的下标
while(i<=m&&j<=t){
if(r[i]<=r[j])//谁小就先把谁放进去
temp[k++]=r[i++];
else
temp[k++]=r[j++];
}
while(i<=m)//剩余部分依次放入临时数组(俩while只会执行一个)
temp[k++]=r[i++];
while(j<=t)
temp[k++]=r[j++];
for(i=s;i<=t;i++)//将临时数组中的内容拷贝回原数组中
r[i]=temp[i];
}
void MergeSort(int r[],int temp[],int s,int t){//分解:把 n 个元素组成的序列r分解为n 个长度为1的有序子表;
if(s==t)//分解为长度为1的有序子表
return;
else
{
int m=(s+t)/2;
MergeSort(r,temp,s,m) ;//对左边序列进行递归
MergeSort(r,temp,m+1,t);//对右边序列进行递归
Merge(r,temp,s,m,t);//合并 即r[s]~r[m]合并成有序数列
}
}
例题例题
5.A POJ1084 Brainman
利用归并排序求出逆序对即可。
最近脑子不太好使,老是看错输入输出,自认为第二行前面的10是数组的第一个元素,还寻思了半天为啥 10 1 2 3 4 5 6 7 8 9逆序对是0。。。。。。
还有Dev函数没有返回值的话不会报错,,提交的时候一直显示语法错误,一直以为是头文件的事情,没看到代码里有个毫无关系的函数还没有返回值。。。。
题解题解
#include<iostream>
#include<cstdio>
using namespace std;
#define N 1007
int num = 0;
int arr[N];
int temp[N];
void Merge(int a[], int temp[], int l, int m, int r) {
int i = l;
int j = m + 1;
int k = l;
while (i <= m && j <= r) {
if (a[i] <= a[j]) {
temp[k++] = a[i++];
}
else {
temp[k++] = a[j++];
num += m - i + 1;
}
}
while (i <= m)
temp[k++] = a[i++];
while (j <= r)
temp[k++] = a[j++];
for (i = l; i <= r; i++)
a[i] = temp[i];
}
void MergeSort(int a[], int temp[], int l, int r) {
if (l == r)
return;
else {
int m = (l + r) / 2;
MergeSort(a, temp, l, m);
MergeSort(a, temp, m + 1, r);
Merge(a, temp, l, m, r);//合并
}
}
int main() {
int T;
cin >> T;
for (int t = 1; t <= T; t++) {
num = 0;
int len = 0;
cin>>len;
for(int i=0;i<len;i++)
cin>>arr[i];
MergeSort(arr, temp, 0, len - 1);
cout << "Scenario #" << t << ":" << endl;
cout << num << endl << endl;
}
return 0;
}
5.B POJ 2299,ZOJ 2386,UVA 10810 Ultra-QuickSort
同上题,求出逆序对即可
注意取值范围,结果要设为longlong
#include<iostream>
#include<cstdio>
using namespace std;
#define N 500007
//int num = 0;
long long num = 0;
int arr[N];
int temp[N];
void Merge(int a[], int temp[], int l, int m, int r) {
int i = l;
int j = m + 1;
int k = l;
while (i <= m && j <= r) {
if (a[i] <= a[j]) {
temp[k++] = a[i++];
}
else {
temp[k++] = a[j++];
num += m - i + 1;
}
}
while (i <= m)
temp[k++] = a[i++];
while (j <= r)
temp[k++] = a[j++];
for (i = l; i <= r; i++)
a[i] = temp[i];
}
void MergeSort(int a[], int temp[], int l, int r) {
if (l == r)
return;
else {
int m = (l + r) / 2;
MergeSort(a, temp, l, m);
MergeSort(a, temp, m + 1, r);
Merge(a, temp, l, m, r);//合并
}
}
int main() {
int len = 0;
while(scanf("%d",&len)!=EOF&&len!=0) {
num = 0;
for(int i=0;i<len;i++)
cin>>arr[i];
MergeSort(arr, temp, 0, len - 1);
cout << num << endl;
}
return 0;
}
快速排序
又对比初始数组和最终数组,我们可以看出初始将a[0]作为pivot,从右向左找第一个比pivot小的数,a[high],赋值给a[0],再从左向右找第一个比pivot大的数,a[low],赋值到a[high]的位置上,最后再将pivot,既原始a[0]处的值赋值到a[low]的位置上。最后返回新的low的下标作为下一次的基准值。
参考代码
Parition(int a[],int low,int high){
int pivot=a[low];//设下标low为“基准”
while(low<high){
while(low<high&&a[high]>=pivot){//从右向左找比pivot小的值
high--;
}
a[low]=a[high];
while(low<high&&a[low]<=pivot){//从左向右找比pivot大的第一个值
low++;
}
a[high]=a[low];
}
a[low]=pivot;//
return low;//返回新 low 的位置,作为分界
}
void QuickSort(int a[],int low,int high){
if(low<high){
int pivot=Parition(a,low,high);
QuickSort(a,low,pivot-1);
QuickSort(a,pivot+1,high);
}
}
俩O(nlog2n)的排序 总。
#include <iostream>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define N 10
void Merge(int r[],int temp[],int s,int m,int t){
//将数组r的两个连续的有序序列:第s到第m个元素,第m+1到第t个元素,合并产生一个有序序列:第s到第t个元素的有序序列
int i=s;
int j=m+1;//i,j是两个连续的有序序列的开始位置
int k=i;//k 临时数组temp的下标
while(i<=m&&j<=t){
if(r[i]<=r[j])//谁小就先把谁放进去
temp[k++]=r[i++];
else
temp[k++]=r[j++];
}
while(i<=m)//剩余部分依次放入临时数组(俩while只会执行一个)
temp[k++]=r[i++];
while(j<=t)
temp[k++]=r[j++];
for(i=s;i<=t;i++)//将临时数组中的内容拷贝回原数组中
r[i]=temp[i];
}
void MergeSort(int r[],int temp[],int s,int t){//分解:把 n 个元素组成的序列r分解为n 个长度为1的有序子表;
if(s==t)//分解为长度为1的有序子表
return;
else
{
int m=(s+t)/2;
MergeSort(r,temp,s,m) ;//对左边序列进行递归
MergeSort(r,temp,m+1,t);//对右边序列进行递归
Merge(r,temp,s,m,t);//合并 即r[s]~r[m]合并成有序数列
}
}
Parition(int a[],int low,int high){
int pivot=a[low];//设下标low为“基准”
while(low<high){
while(low<high&&a[high]>=pivot){//从右向左找比pivot小的值
high--;
}
a[low]=a[high];
while(low<high&&a[low]<=pivot){//从左向右找比pivot大的第一个值
low++;
}
a[high]=a[low];
}
a[low]=pivot;//
return low;//返回新 low 的位置,作为分界
}
void QuickSort(int a[],int low,int high){
if(low<high){
int pivot=Parition(a,low,high);
QuickSort(a,low,pivot-1);
QuickSort(a,pivot+1,high);
}
}
int main() {
int arr[N]={5,64,36,343,6,24,1,4,8,29};
int temp[N]={0};
//MergeSort(arr,temp,0,9);
QuickSort(arr,0,9);
for(int i=0;i<10;i++)
cout<<arr[i]<<" ";
return 0;
}
例题例题
5.C Who’s in the Middle
//这次要用快速排序做一下,输出中间数即可
#include<iostream>
#include<cstdio>
using namespace std;
#define N 500007
int a[N];
int partition(int l, int r) {
int pivot = a[l];
while (l < r) {
while (l < r && pivot <= a[r])
r--;
a[l] = a[r];
while (l < r && pivot >= a[l])
l++;
a[r] = a[l];
}
a[l] = pivot;
return l;
}
void quick_sort(int l, int r) {
if (l < r) {
int m = partition(l, r);
quick_sort(l, m);
quick_sort(m + 1, r);
}
}
int main() {
int n;
while (~scanf("%d", &n)) {
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
quick_sort(0, n - 1);
cout << a[n / 2] << endl;
}
return 0;
}
利用sort函数排序
例题
5.D sort 给你n个整数,请按从大到小的顺序输出其中前m大的数。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define N 1000007
int a[N];
bool cmp(int a,int b){
return a>b;
}
int main() {
int n,m;
while(cin>>n>>m){
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n,cmp);
for(int i=0;i<m-1;i++)
cout<<a[i]<<" ";
cout<<a[m-1]<<endl;
}
return 0;
}