排序 Swap(0, i) 最小次数

原创 2015年11月18日 00:00:13

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">	</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">最近在上数据结构和算法基础, 有一个附加题。要求如下:</span>

5-1 Sort with Swap(0, i)   (25分)

Given any permutation of the numbers {0, 1, 2,..., N1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive N (105) followed by a permutation sequence of {0, 1, ..., N1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:

10
3 5 7 2 6 4 9 0 8 1

Sample Output:

9

看到题目,思考一番不难得出:Swap(0, i) 即不断的将0 所在的下标对应的数进行交换,以保证每一次交换都能有一个数字被放到正确的位置。

然而,这里面存在一些特殊情况,即 0 已经回到了Array[0], 而数组中别的数还没排序完成。

没有办法,只能选择用0 与第一个排序错误的数进行Swap, 而这次Swap是没有完成排序一个数的任务的,但我们别无选择。

在这样的思路下,我自己先写了一个程序,然而OJ系统的结果是:在一些例子的情况下运行超时。

代码如下:

#include <stdio.h>
#include <stdlib.h>

int *Array, NumNotPos, NumSwap;
void Swap(int a, int b, int N);
void Sort(int N);
void Read(int N);


int main(int argc, char const *argv[])
{
	int N;
	scanf("%d", &N);
	Read(N);
	Sort(N);
	printf("%d\n", NumSwap);
	system("pause");
	return 0;
}

void Read(int N)
{
	Array = (int *)malloc(N * sizeof(int));
	int i = 0;
	while (i < N)
	{
		scanf("%d", &Array[i]);
		i++;
	}
	/*
	Array[0] = 3;
	Array[1] = 5;
	Array[2] = 7;
	Array[3] = 2;
	Array[4] = 6;
	Array[5] = 4;
	Array[6] = 9;
	Array[7] = 0;
	Array[8] = 8;
	Array[9] = 1;
	*/
}

void Sort(int N)
{
	int i = 0;
	while (i < N)
	{
		if (Array[i] != i)
			NumNotPos++;
		i++;
	}
	
	do
	{
		if (Array[0] == 0 && NumNotPos != 0)
		{
			int j = 1;
			while(Array[j] == j && j < N)
			{
				j++;
			}
			Swap(0, j, N);
			NumNotPos++;
		}

		if (NumNotPos != 0)
		{
			int j = 0;
			while (Array[j] != 0 && j < N)
				j++;
			Swap(0, j, N);
			NumNotPos--;
			if (Array[0] == 0)
				NumNotPos--;
		}
	} while (NumNotPos > 0);
}

void Swap(int a, int b, int N)
{
	NumSwap++;
	int i, temp, FirIndex, SecIndex;
	i = FirIndex = SecIndex = 0;
	while (i < N)
	{
		if (Array[i] == a)
			FirIndex = i;
		if (Array[i] == b)
			SecIndex = i;
		if (FirIndex && SecIndex)
			break;
		i++;
	}
	
 	temp = Array[FirIndex];
 	Array[FirIndex] = Array[SecIndex];
 	Array[SecIndex] = temp;
}

想了很久,自我感觉已经没法优化了,结果还是超时。。。

上google! 1s 出结果,找到了一个似乎和我一样在浙大上PTA的同学技术博客。

点击打开链接  http://blog.csdn.net/xyt8023y/article/details/47210245

搬运至此:

#include <stdio.h>  
  
int findNotOK(int* arr,int begin,int end)   //从begin开始往后寻找未到位的数  
{  
    for(int i=begin;i<end;i++)  
    {  
        if(arr[i]!=i)return i;  
    }  
    return 0;  
}  
  
int main()  
{  
    int n;  
    scanf("%d",&n);  
    int* arr = new int[n];  
    int i,t;  
  
    for(i=0;i<n;i++)  
    {  
        scanf("%d",&t);  
        arr[t]=i;  
    }  
    int tmp = 0;  
    int count=0;  
    int firstPos = 1;  
    firstPos = findNotOK(arr,firstPos,n);  
  
    while(firstPos)     //还有未到位的数字  
    {  
        if(arr[0]==0)       //如果0到位了,则与未到位的firstPos交换  
        {  
            arr[0] = arr[firstPos];  
            arr[firstPos] = 0;  
            count++;  
        }  
  
        while(arr[0]!=0)    //如果0不到位,则循环与自己所指向的值交换  
        {  
            tmp = arr[0];  
            arr[0] = arr[tmp];  
            arr[tmp] = tmp;  
            count++;  
        }  
        firstPos = findNotOK(arr,firstPos,n);       //此时0归位了,找到下一个未到位的数字  
    }  
    printf("%d\n",count);  
  
    return 0;  
}  
对比起来,思路上基本是一致的,但在确认排序完成和寻找Swap下标的实现上存在不同。但在浙大PTA中能够通过。

结论:自己的实现总存在着大量的循环确认未排序数的个数,并且循环寻找Swap下标。

对比第二份代码,我发现这样的循环存在太多的冗余信息。

而事实上确如第二份代码中的实现,第一个未排序完成数的下标,包含了两份信息:

1、排序是否完成

2、若没完成,Array[0] == 0 时0 的交换对象。

这确实值得我学习,在满足需求的情况下,精准的定位需要的信息量,而不是盲目的获取大量无用信息。

数组排序--计算最小交换次数

给定一个包含1-n的数列,我们通过交换任意两个元素给数列重新排序。求最少需要多少次交换,能把数组排成按1-n递增的顺序,其中,数组长度不超过100。 例如: 原数组是3,2,1, 我们只需要交换1...
  • lavorange
  • lavorange
  • 2013年11月26日 21:04
  • 3877

bzoj 3580: 冒泡排序

Description   下面是一段实现冒泡排序算法的C++代码:   for (int i=1;i   for (int j=1;j   if (a[j]>a[j+1])   swa...
  • lqybzx
  • lqybzx
  • 2015年04月03日 19:41
  • 516

关于一个求最小交换次数的算法的一个严格证明,是严格证明,不是想当然

问题描述: 有一个1~n的数列的排列,但是这个数列已经被打乱了排列顺序,如果我们只是通过“交换任意两个元素”,那么,要实现元素从1~n的有序排列,“最少的交换次数是多少?” 解答过程: 首先我们...
  • wangxugangzy05
  • wangxugangzy05
  • 2015年01月06日 10:33
  • 2703

通过交换相邻数来完成排序所需要的最少交换次数

对一个无序序列进行排序,要求一次只能交换相邻的两个数,那么最少需要交换多少次才可以完成排序呢? 本问题假设序列所有数各不相同。 概念介绍: 1、逆序。一般认为从左向右序列的数字增大认为是正序的,那...
  • luckyjoy521
  • luckyjoy521
  • 2013年12月02日 10:27
  • 3976

外部排序的方法

在实际应用中,由于外存设备的不同,通常又可分配磁盘文件排序和磁带文件排序两大类。磁带排序和磁盘排序的基本步骤相类似,主要的不同之处在于初始归并段在外存介质中的分布方式,磁盘是直接存储设备,磁带是顺序存...
  • jxq0816
  • jxq0816
  • 2016年09月09日 17:26
  • 1409

【留坑】UVA10810 求逆序对==求最少相邻元素交换次数 归并排序OR线段树OR树状数组

1 题意: 给出一个数列,允许相邻元素进行交换,求最少交换次数。 2分析: 求最少交换次数,等同于求该数列中的逆序对数。  证明:先将最大的数与后面的数交换直到停止,交换次数=该数的逆序数,...
  • a272846945
  • a272846945
  • 2016年11月28日 17:40
  • 560

排序算法(二)Sort with Swap(0,*)

对于一个由0到N-1的序列,如果只能交换0和另一个数的位置,求多少次能够将序列变为递增序列。 输入为 (N和序列之间有一个空格,序列元素之间均有一个空格)。 设序列存储在数组A里。 一个直接...
  • xyt8023y
  • xyt8023y
  • 2015年01月25日 17:09
  • 420

深入学习排序算法之稳定性、比较次数、交换次数探讨

在学习排序算法时,出于效率考虑,经常容易看到算法的稳定性、比较次数及交换次数研究。特别是考试或者公司笔试题,经常出现这样的题目。由于排序算法有很多种,平时提出大家才能说出个大概,但真要考查这些细节,估...
  • dreamer2020
  • dreamer2020
  • 2014年05月11日 17:27
  • 4823

C++面试题(七)

在C++中,排序也是一个很重要的东西,下面就对常见的排序算法进行一个总结 1.交换函数void swap(int *a, int i, int j) //交换两个数 { ...
  • zcl1804742527
  • zcl1804742527
  • 2017年02月18日 16:38
  • 162

java中实现swap函数的几种方式

java中实现swap解决方案由于java中“对基本类型的变量是不支持引用传递的”,所以根本不能像c/c++那样直接传地址,但是可以如下解决: 1.使用数组传值public class TestSw...
  • u014028392
  • u014028392
  • 2017年10月24日 10:32
  • 313
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:排序 Swap(0, i) 最小次数
举报原因:
原因补充:

(最多只允许输入30个字)