一个数组中只有0,1,2三种元素,要求对这样的数组进行排序
2013-11-06 17:24
489 查看
题目:一个数组中只有0,1,2三种元素,要求对这样的数组进行排序。
1.思路:
1.1思路1:
第一眼看到这样的题目,会举得非常简单,只需要两次遍历数组就可以完成了。第一次遍历,扫描数组中的元素,每次遇到0则count0++,遇到1则count1++,遇到2则count2++,这样一趟下来就能够统计出数组中0,1,2的个数了。然后第二次遍历的时候,只需要对数组进行重新赋值就可以了,从头开始赋值count0个0,count1个1,count2个2。最终完成对数组的排序。(计数排序做法)
1.2思路2:
既然是面试题,那么肯定不会让你这么简单就解决出来了的。面试官说,加入只能进行一次遍历怎么办,然后你就不知道了。这道题目如果只能进行一次遍历,我们肯定会想到使用多指针。这种题目之前碰到过很多。类似折半查找需要设置两个指针,不过这道题目却需要三个指针,分别指向数组中0,1,2三个元素末尾。加入有排好序的数组{0,0,1,1,2,2},那么p0指向下标为1的那个0,p1指向下标为3的那个1,而p2则指向下标为5的那个2。
p0和p1从前往后扫描,p2从后往前扫描,
初始化时:
p0指向第一个非0元素,那么arry[p0]=1||2
p1指向第一个非1元素,那么arry[p1]=0||2
p2指向第一个非2元素,那么arry[p2]=0||1
假如:
arry[p0]==2,arry[p2]==0,交换两个元素
arry[p1]==2,arry[p2]==1,交换两个元素
arry[p0]==1,arry[p1]==0,交换两个元素
否则的话只可能是p0,p1,p2指向的三个数各不相同,那么进行如下赋值
arry[p0]==0,arry[p1]==1,arry[p2]==2。
假如经过上述swap以后出现i>k的情况,将k=i。(PS:2012-10-5)
#include<iostream> #include<stdlib.h> using namespace std; void PrintArry(int arry[],int len) { for(int i=0;i<len;i++) cout<<arry[i]<<" "; cout<<endl; } void swap(int arry[],int i,int j) { int temp=arry[i]; arry[i]=arry[j]; arry[j]=temp; } void sort(int arry[],int len) { int i= 0;//头指针指向0 int j = len - 1;//尾指针指向2 int k = 0;//中间指针指向1 while(i <= j && k <= j && i <= k) { //i指向第一个非0值 while(arry[i] == 0){ i++; } //k指向第一个非1值 while(arry[k] == 1){ k++; } //j指向第一个非2值 while(arry[j] == 2){ j--; } if(i <= j && arry[j] == 0 && arry[i] == 2){ swap(arry,i,j); i++; j--; } else if(k <= j && arry[k] == 2 && arry[j] == 1){ swap(arry,k,j); k++; j--; } else if(i <= k && arry[k] == 0 && arry[i] == 1){ swap(arry,k,i); i++; k++; } else if(i < k && k < j){ arry[i] = 0; arry[k] = 1; arry[j] = 2; i++; k++; j--; } if(i>k) { k=i; } } } void main() { int arry[]={1,0,2,2,0,1,0,1}; int len=sizeof(arry)/sizeof(int); PrintArry(arry,len); sort(arry,len); PrintArry(arry,len); system("pause"); }
转自:/article/4631392.html
原题
排序只有1,2,3三个元素的数组,不能统计1,2,3的个数。分析
这个题目,尽管也是排序,但却不能使用快速排序的方法。只有三个元素,如果时间复杂度仍旧是O(nlogn),显然不是最好的。那就可以使用线性的排序算法,例如计数排序,可是题目中要求,不能够对1,2,3进行统计个数。那该如何处理呢?请大家看下面的方法,我们首先通过例子来说明:2 | 1 | 1 | 3 | 3 | 2 |
p1 | p2 | p3 |
如果遇到1,则和p1进行交换,然后p1向右,指向第一个非1的数字
如果遇到3,则和p3进行交换,然后p3向左,指向第一个非3的数字
1 | 2 | 1 | 3 | 3 | 2 |
p1,p2 | p3 |
1 | 1 | 2 | 3 | 3 | 2 |
p1,p2 | p3 |
1 | 1 | 2 | 2 | 3 | 3 |
p1 | p3 | p2 |
总结一下上面的算法:
p1从左侧开始,指向第一个非1的数字;p3从右侧开始,指向第一个非3的数字。
p2从p1开始遍历,如果是2,p2继续遍历,直到p2遇到1或者3
如果遇到1,则和p1进行交换,然后p1向右,指向第一个非1的数字
如果遇到3,则和p3进行交换,然后p3向左,指向第一个非3的数字
重复上面的步骤,直到p2在p3的右侧结束。
void sort(int arr[],int len) { int i = 0;//头指针指向0 int j = len - 1;//尾指针指向2 int k = 0; while (arr[i] == 0) i++; k = i + 1; while (arr[j] == 2) j--; while (k < j) { if (arr[k] == 1) k++; else if (arr[k] == 0) { swap(arr[i], arr[k]); while (arr[i] == 0) i++; } else if (arr[k] == 2) { swap(arr[k], arr[j]); while (arr[j] == 2) j--; } } }
基于快排划分的思路
上面的思路,是针对三个数的,如果有更多的数,怎么处理呢?比如,4个,5个等等。下面根据快速的排序的启发,介绍一种算法,尽管在处理三个数的时候,比较次数会多些,但,具有很好的通用性。思路来自快排的划分部分,快排的划分部分:给定pivot,然后将数据划分为<=pivot和>pivot两部分。这样,三个数字时,需要两次划分:
第一次,用1作为pivot,划分1到最左边;
第二次,用2作为pivot,划分2到左边,则得到整体的排序。
最巧妙的思路
我们将1,2,3,替换为互质的2,3,5,得到如下:2 | 1 | 1 | 3 | 3 | 2 |
3 | 2 | 2 | 5 | 5 | 3 |
如下:(分解质因数)
被除数 | 除数 | 商 | 余数 | 排序结果 |
900 | 2 | 450 | 0 | 1 |
450 | 2 | 225 | 0 | 1 |
225 | 2 | 112 | 1 | 2尝试结束,尝试3 |
225 | 3 | 75 | 0 | 2 |
75 | 3 | 25 | 0 | 2 |
25 | 3 | 8 | 1 | 3尝试结束,尝试5 |
25 | 5 | 5 | 0 | 3 |
5 | 5 | 1 | 0 | 3 |
1 | 5 | 1 | 1 | 全部结束 |
【分析完毕】
相关文章推荐
- 一个数组中只有0,1,2三个元素,进行排序,要求时间复杂度为O(n)
- 那些年我们刷过的算法题(排序)---有一个只由0,1,2三种元素构成的整数数组,请使用交换、原地排序而不是使用计数进行排序
- 把一个二维实型数组a按照第0列的元素进行排序(由小到大排序,用气泡法)
- 已有一个已排好的9个元素的数组,今输入一个数要求按原来排序的规律将它插入数组中。
- 编写一个使用数组类模板Array对数组进行排序、求最大值和求元素和的程序,并采用相关数据进行测试。
- 用了接近一天的程序看懂了堆排序,堆排序的“筛选”的前提条件是一个大(小)顶堆,只有堆顶的元素不是有序的。这样从堆顶开始的排序才是筛选。而堆排序就是反复筛选的程序。
- 定义一个一维数组,其元素个数从键盘中输入,元素的值为[100,200]的随机整数。 (1)输出数组的每个数 (2)对数组的数进行升序排序,输出排序后的数组元素 (3)从键盘上输入一个整数,查找该整数是
- 一个数组只含0,1,2三种数,对这个数组排序,要求只能扫描一遍数组
- 求一个很大的数组(乱序)排序后从第i大到第j大之间的所有元素,并且这些元素之间要求有序
- 已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。 给定一个int数组A,同时给定
- 问题:利用输入输出流重载实现一个整数数组的输入和输出。 要求:输入一个数组大小 及 所有元素的值,排序后输出该数组的所有元素。
- 输入一个数组,对数组进行排序,并输出该数组中重复元素出现的次数
- 1.给出一个Person类里面包含姓名、年龄、成绩,声明5个Person对象数组,要求对数组中的内容进行排序,排序规则如下:按成绩由高到低排序,如果成绩一样,按年龄由高到低排序。
- 已有一个已排好的9个元素的数组,今输入一个数要求按原来排序的规律将它插入数组中。
- 要求从用户输入的多行文本中提取学生的姓名、学号及登录日期,并封装到 Student 类中作为类的私有属性。创建一个 Student 类型的对象数组,对学号进行 升序排序并输出
- 对一个数组按给定的下标排序,仅使用两两交换的方式,要求不能对数组进行扩容尽可能使用额外少的空间。原数组为:A,B,C,D,E, 现给定新的位置为3, 0, 1, 4, 2那么排序为D,A,B,E,C
- C++中用冒泡排序算法对一个数组中的元素进行排序
- 要求从用户输入的多行文本中提取学生的姓名、学号及登录日期,并封装到 Student 类中作为类的私有属性。创建一个Student类型的对象数组,对学号进行 升序排序并输出。
- 一个字符数组,里面的字符可能是a-z、A-Z、0-9.现在要求对数组进行排序,要求所有小写字符放在最前面,所有大写字符放在中间,所有数字放在最后,而且各部分内部分别有序(创新工场)
- 这是一个我面试某公司的算法题目:对一个字符数组进行排序,根据给定的字符,大于它的,放在数组的左边,小于它的,放在数组的右边,且数组中的元素之间的相对位置要保持不变。