算法练习:两指针之三色排序

问题描述

输入一个整型数组,每个元素在0~2之间,其中0,1,2分别代表红、白、蓝。现要求对数组进行排序,相同颜色的在一起,而且按红白蓝顺序先后排列。要求时间复杂度为O(n)。

问题分析

最容易想到的是排序,比如快排,归并,堆排等,但它们的时间复杂度为O(nlogn),与题意不符。

第二种想到的是计数排序,扫描一遍过去,分别记录0,1,2的个数,然后再对数组进行赋值。时间复杂度为O(2n),即O(n),满足条件。

还有一种方法,只需扫描一遍数组即可,其充分利用了元素只有3种的特性:在扫描数组的时候,使用首尾俩个指针,分别指示0、1与1、2边界。比如源数组为{2, 2, 0, 0, 1, 1  }。

第一步:首指针p0,尾指针p1,i标识当前扫描位置,当前位置值为2,需要将其交换至尾指针p1位置,p1要向前移动一位,p0、i位置不变。

第二步:i位置值不为0、2,i要向后移动一位,p0、p1位置不变。

第三步:i位置值为2,需要将其交换至尾指针p1位置,并且p1往前移动一位,i与p0位置不变。

第四步:i位置不为0、2,i要向后移动一位,p0、p1位置不变。

第五步:i位置值为0,需要将其交换至首指针p0位置,并且p0往后移动一位,i与p1位置不变。

第六步:i位置不为0、2,i要向后移动一位,p0、p1位置不变。

第七步:i位置值为0,需要将其交换至首指针p0位置,并且p0往后移动一位,i与p1位置不变。

第八步:i位置不为0、2,i要向后移动一位,p0、p1位置不变。

第九步:i位置超过p1位置了,结束。

实现代码

#include <iostream>

using namespace std;

void ThreeColorSort( int nArray[], int nCount )
{
	int p0 = 0;			//首指针
	int p1 = nCount-1;	//尾指针

	int i = 1;
	while( i <= p1 )
	{
		//当前值为2,与尾指针p1指向的值相互交换,p1向前移动一位
		//i、p0位置不变
		if ( nArray[i] == 2 )
		{
			int nTemp = nArray[i];
			nArray[i] = nArray[p1];
			nArray[p1--] = nTemp;
		}
		//当前值为0,与首指针p0指向的值相互交换,p0向后移动一位
		//i、p0位置不变
		else if ( nArray[i] == 0 && i > p0 )
		{
			int nTemp = nArray[i];
			nArray[i] = nArray[p0];
			nArray[p0++] = nTemp;
		}
		//i位置不为0、2,i要向后移动一位,p0、p1位置不变。
		else
		{
			++i;
		}
	}
}

//书上的例子代码
void SortColors( int nArray[], int nCount )
{
	int p0 = 0;
	int p2 = nCount;
	for( int i = 0; i < p2; ++i )
	{
		if ( nArray[i] == 0 )
		{
			int tmp = nArray[p0];
			nArray[p0] = nArray[i];
			nArray[i] = tmp;
			++p0;
		}
		else if ( nArray[i] == 2 )
		{
			--p2;
			int tmp = nArray[p2];
			nArray[p2] = nArray[i];
			nArray[i] = tmp;
			--i;
		}
	}
}

int main()
{
	//int nArray[] = { 2, 1, 0, 2, 0 };
	//int nArray[] = { 0, 0, 1, 1, 2, 2 };
	//int nArray[] = { 0 };
	//int nArray[] = { 2, 0, 1 };
	int nArray[] = { 2, 2, 0, 0, 1, 1 };
	ThreeColorSort( nArray, _countof(nArray) );

	//SortColors( nArray, _countof(nArray) );
	for( int i = 0; i < _countof(nArray); ++i )
	{
		cout << nArray[i] << " ";
	}
	cout << endl;

	return 0;
}

系列文章说明:

1.本系列文章[算法练习],仅仅是本人学习过程的一个记录以及自我激励,没有什么说教的意思。如果能给读者带来些许知识及感悟,那是我的荣幸。

2.本系列文章是本人学习陈东锋老师《进军硅谷,程序员面试揭秘》一书而写的一些心得体会,文章大多数观点均来自此书,特此说明!

3.文章之中,难免有诸多的错误与不足,欢迎读者批评指正,谢谢.

作者:山丘儿

转载请标明出处,谢谢。原文地址:http://blog.csdn.net/s634772208/article/details/46740191

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 23:20:36

算法练习:两指针之三色排序的相关文章

算法练习:两指针之三数之和为0

问题描述 给出一个整型数组,找出所有三个元素的组合,其组合之和等于0.要求在结果集里不含有重复的组合. 举例: 输入{-2, 1, -1, 2, 1} 输出{-2, 1, 1 } 问题分析 最容易想到的是穷举法,挑选第一个元素,然后在其后挑选第二个元素,再从除已经挑选出的两个元素之外挑第三个元素,判断三者之和是否为0:第二种想到的是用回溯递归,这两种方法的时间复杂度均为O(n^3),可参阅代码部分关于这两种方法的实现. 那有没有复杂度低一些的呢,答案是有的,就是使用两指针的方法,从而使复杂度下降

两指针扫描算法举例

问题一:求sum值 描述:给定一有序序列ary和sum值,求序列中是否存在两元素e1和e2,其和刚好为sum. 算法思想:这是典型的两指针的用法.i指针从头部开始,j指针从尾部开始,相向移动,本质向讲,在移动过程中比较ary[i]+ary[j]与sum的大小,达到逐步排除元素的过程,缩短查找范围.最开始,i和j处于序列首部和尾部如果ary[i]+ary[j]=sum,直接返回结果.如果ary[i]+ary[j]<sum,需要增大ary[i]或者ary[j],但是j已经不能在增大,只能i++,因此

(转) 白话经典算法系列之三 希尔排序的实现(附源代码实现)

链接:http://blog.csdn.net/morewindows/article/details/6668714 希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率

算法—比较两种排序算法:选择排序和插入排序

现在我们已经实现了两种排序算法,我们很自然地想知道选择排序和插入排序哪种更快.这里我们第一次用实践说明我们解决这个问题的办法. 性质:对于随机排序的无重复主键的数组,插入排序和选择排序的运行时间是平方级别的,两者之比应该是一个较小的常数. 例证:这个结论在过去的半个世纪中已经在许多不同类型的计算机上经过了验证.在1980年本书第一版完成之时插入排序就比选择排序快一倍,现在仍然是这样,尽管那时这些算法将10万条数据排序需要几个小时而现在只需要几秒钟.在你的计算机上插入排序也比选择排序快一些吗?可以

算法--三色排序练习题

三色排序练习题 第17节 三色排序练习题 有一个只由0,1,2三种元素构成的整数数组,请使用交换.原地排序而不是使用计数进行排序. 给定一个只含0,1,2的整数数组A及它的大小,请返回排序后的数组.保证数组大小小于等于500. 测试样例: [0,1,1,0,2,2],6 返回:[0,0,1,1,2,2] Java (javac 1.7) 代码自动补全 1 import java.util.*; 2 3 public class ThreeColor { 4 public int[] sortTh

Java数据结构和算法(三):常用排序算法与经典题型

常用的八种排序算法 1.直接插入排序 我们经常会到这样一类排序问题:把新的数据插入到已经排好的数据列中.将第一个数和第二个数排序,然后构成一个有序序列将第三个数插入进去,构成一个新的有序序列.对第四个数.第五个数--直到最后一个数,重复第二步.如题所示: 直接插入排序(Straight Insertion Sorting)的基本思想:在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的.如此反复循环,直到全部排

快速排序算法的两个写法

快速排序作为应用比较广泛,而且时间复杂度比较优越的排序算法备受大家的喜爱.最近有点悠闲,就又把这个快速算法研究了一遍,目前掌握了两种排序算法的思路,为了以免忘记,故详细的记录下来,也供大家学习借鉴,不足之处望请指教. 快速排序的基本原理: 假设一个待排序的数组如上图所示,排序的目的就是将其从小到大排序.快速排序的主要步骤就是设定一个待排序的元素(称作主元,记作temp),经过一轮划分排序后在这个主元左边的元素值都小于它,在主元右边的元素值都大于它,一轮划分后的效果应该是这样的,如下图: 这样以t

两指针--减少数组循环

题目(lintcode): 1.二数之和 2.三数之和 3.最接近的三数之和 4.四数之和  取三数之和为例: (一) 普通算法,多重遍历数组,需要多重for嵌套,但严重超时. (二) 剪枝,在外层循环中考虑有没有“不可能符合要求”的情况. 例如,在三数之和中,若两个数之和大于0,直接break.但题目没说不会出现负数,所以不对. (三) 接(二),判断两个数之和大于0无效,是因为数组无序,所以先进行排序  sort(nums.begin(),nums.end()); 之后可以在保证大于0时,b

七大内部排序算法总结(插入排序、希尔排序、冒泡排序、简单选择排序、快速排序、归并排序、堆排序)

 写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列.因此排序掌握各种排序算法非常重要.对下面介绍的各个排序,我们假定所有排序的关键字都是整数.对传入函数的参数默认是已经检查好了的.只是简单的描述各个算法并给出了具体实现代码,并未做其他深究探讨. 基础知识: 由于待排序的记录数量不同,使得排序过程中设计的存储器不同,可将排序方法分为两大类:一类是内部排序,指的是待排序记录存放在计算机随机存储器中进行的排序过程.另一类是外部排序,