数组专题讲义之简单排序算法

来源:互联网 发布:网络层的4个功能 编辑:程序博客网 时间:2024/06/06 18:09
专题二 简单排序算法阅读代码,回答下列问题:#include <iostream>using namespace std;const int M = 100;const int N = 10;int T[N+1];//桶排序专用数组(元素值为0-N的整数)void PrintArray(const int A[], int low, int high); //输出数组A中区域[low,high]的元素void BubbleSort (int A[], int n); //用冒泡排序法对数组A进行排序(非递减序列)void SelectionSort(int A[], int n); //用选择排序法对数组A进行排序(非递减序列) void InsertSort(int A[], int n); //用插入排序法对数组A进行排序(非递减序列) void BucketSort(int A[], int n);//用桶排序法对数组A进行排序(非递减序列)int main(){int A[M] = {2,8,2,1,2,6,5,6};int B[M] = {2,8,2,1,2,6,5,6};int C[M] = {2,8,2,1,2,6,5,6};int D[M] = {2,8,2,1,2,6,5,6};int n = 8;BubbleSort(A, n);//冒泡排序算法 PrintArray(A, 0, n-1);SelectionSort(B, n);//选择排序算法 PrintArray(B, 0, n-1);InsertSort(C, n);//插入排序算法 PrintArray(C, 0, n-1);    BucketSort(D, n);//桶排序算法 PrintArray(D, 0, n-1);return 0;}void PrintArray(const int A[], int low, int high) //输出数组A中区域[low,high]的元素{while (low <= high)cout << A[low++] << " ";cout << endl;}算法1:用冒泡排序法对数组A进行排序(非递减序列) void BubbleSort(int A[], int n){int temp; for (int i=n-1; i>0; i--)     {    for (int j=0; j<i; j++) //通过交换相邻位置元素,进行冒泡操作        {            if (A[j] > A[j+1])            {            temp = A[j];                A[j] = A[j+1];                A[j+1] = temp;            }        }}}问题1:写出每轮冒泡后的数组序列。问题2:算法1是每次对A[0..i]部分进行冒泡排序,并将最大值存储到最右侧A[i]中,能否转换一下思路:每次将最小值冒泡到最左侧?试写出修改后的代码。问题3:通过问题1,我们注意到在第3轮的时候就已经排好序了,第4-7轮没有做任何交换操作,实际是没有必要执行的。能否对算法1进行改进,一旦排序完成则结束循环,无需再进行下一轮冒泡?试写出改进后的代码。答案:问题1:第1轮:2 2 1 2 6 5 6 8; 第2轮:2 1 2 2 5 6 6 8; 第3轮:1 2 2 2 5 6 6 8;第4轮:1 2 2 2 5 6 6 8; 第5轮:1 2 2 2 5 6 6 8; 第6轮:1 2 2 2 5 6 6 8;第7轮:1 2 2 2 5 6 6 8; 问题2:代码如下:void BubbleSort_0(int A[], int n)//冒泡排序算法0:逆序扫描,将最小值放到下方 {int temp;    for (int i=1; i<n; i++)     {    for (int j=n-1; j>=i; j--)         {            if (A[j] < A[j-1])            {            temp = A[j];  A[j] = A[j-1];  A[j-1] = temp;            }        }}}问题3:一种思路:设置交换操作标志。void BubbleSort_1(int A[], int n)//冒泡排序改进算法1:设置交换操作标志  {bool swapFlag = 1; //交换标志用来判断内层循环中是否有交换操作int temp;     for (int i=n-1; swapFlag && i>0; i--)     {swapFlag = 0; //先假设未做交换操作     for (int j=0; j<i; j++)         {            if (A[j] > A[j+1])            {            temp = A[j];  A[j] = A[j+1];  A[j+1] = temp;                swapFlag = 1;//设置交互操作标志             }        }}}另一种思路:将待排序列的上界缩小到最后一次发生交换的位置处。void BubbleSort_2(int A[], int n) //修改待排序数组的上界为最后一次发生交换操作的位置{int swapPos;//记录最后一次发生交换操作的位置int temp;     for (int i=n-1; i>0; i=swapPos)//待排序部分数组的上边界,即lib[0..i]为待排序部分    {swapPos = 0; //先假设最后一次发生交换操作的位置为0     for (int j=0; j<i; j++)         {            if (A[j] > A[j+1])            {            temp = A[j];  A[j] = A[j+1];  A[j+1] = temp;                swapPos = j;             }        }}}算法2:用选择排序法对数组A进行排序(非递减序列) void SelectionSort(int A[], int n){int p; int temp; for (int i=0; i<n-1; i++)     {p = i;    for (int j=i+1; j<n; j++)         {            if (A[j] < A[p])            p = j;        }        if (p != i) {//语句块1} }}问题4:写出每轮选择后的数组序列。问题5:将语句块1填写完整(注意是语句块,可能不止一条语句)。答案:问题4:第1轮:1 8 2 2 2 6 5 6; 第2轮:1 2 8 2 2 6 5 6; 第3轮:1 2 2 8 2 6 5 6;第4轮:1 2 2 2 8 6 5 6; 第5轮:1 2 2 2 5 6 8 6; 第6轮:1 2 2 2 5 6 8 6;第7轮:1 2 2 2 5 6 6 8;问题5:{temp = A[p];A[p] = A[i];A[i] = temp;}算法3:用插入排序法对数组A进行排序(非递减序列) void InsertSort(int A[], int n){int p; int temp; for (int i=1; i<n; i++)     {temp = A[i];    for (p=i-1; p>=0; p--) //语句1        {            if (A[p] > temp)            A[p+1] = A[p];        else        break;        }        A[p+1] = temp;}}问题6:写出每轮插入后的数组序列。问题7:算法3中语句1及其所在循环体的作用是逆序扫描A[0..i],把比temp大的元素右移1位,直到A[p] <= temp为止。注意到A[0..i-1]部分是有序排列的,能否设计更高效的算法实现插入排序?答案:问题6:第1轮:2 8 2 1 2 6 5 6; 第2轮:2 2 8 1 2 6 5 6; 第3轮:1 2 2 8 2 6 5 6;第4轮:1 2 2 2 8 6 5 6; 第5轮:1 2 2 2 6 8 5 6; 第6轮:1 2 2 2 5 6 8 6;第7轮:1 2 2 2 5 6 6 8;问题7:有2种改进思路:void InsertSort_1(int A[], int n)//插入排序改进算法1:二分插入 {int low, high, mid;int temp; //用来存储待插入元素的临时变量 for (int i=1; i<n; i++) //A[0..i-1]为已排序部分,将A[i]插入到A[0..i-1]中     {temp = A[i];low = 0;high = i-1;while(low <= high) //二分查找插入位置{mid = (low + high)/2;if (A[mid] > temp)high = mid - 1;elselow = mid + 1;}    for (int j=i; j>low; j--)//移动元素以腾出插入位置         A[j] = A[j-1];        A[low] = temp;}}void InsertSort_2(int A[], int n)//插入排序改进算法2:希尔排序 {int p; //用来存储插入位置的临时变量 int temp; //用来交换数组元素值的临时变量       for (int gap=n/2; gap>0; gap/=2)//元素跳跃的步长不断减少,步长为1时即为直接插入排序{for(int i=gap; i<n; i++)//将A[i]插入到A[0..i-1]中 {temp = A[i];for (p=i; p>=gap; p-=gap)//向后跳跃移动元素以腾出插入位置,跳跃距离为gap        {            if (A[p-gap] > temp)            A[p] = A[p-gap];        else        break;        }        A[p] = temp;}}}算法4:用桶排序法对数组A进行排序(非递减序列)void BucketSort(int A[], int n) {for (int i=0; i<n; i++)  {T[A[i]]++;}for (int i=0,t=0; i<=N; i++)//语句1 {for (int j=T[i]; j>0; j--)A[t++] = i;}}问题8:语句1中有一个全局常量N,请问其含义是什么?问题9:桶排序能否对元素值大小范围为[-100,100]的整数数组排序?如果元素值是负数呢?答案:问题8:N代表元素值的最大值,桶排序只能对元素值大小为[0,N]内的整型数组排序。问题9:将桶的大小做些修改,就能存储负整数,对范围为[-100,100]的整数数组,可设置桶的大小N=200,将数组元素值加上100后再装入桶中,取出元素时再减去100即可。如果元素值是小数,可先将其转化为整数,再装入桶中。课后练习:练习1:02_奇数单增序列 描述:给定一个长度为N(不大于500)的正整数序列,请将其中的所有奇数取出,并按升序输出。输入共2行:第1行为 N;第2行为 N 个正整数,其间用空格间隔。输出增序输出的奇数序列,数据之间以逗号间隔。数据保证至少有一个奇数。样例输入101 3 2 6 5 4 9 8 7 10样例输出1,3,5,7,9练习2:08_病人排队描述:病人登记看病,编写一个程序,将登记的病人按照以下原则排出看病的先后顺序: 1. 老年人(年龄 >= 60岁)比非老年人优先看病。 2. 老年人按年龄从大到小的顺序看病,年龄相同的按登记的先后顺序排序。 3. 非老年人按登记的先后顺序看病。输入第1行,输入一个小于100的正整数,表示病人的个数;后面按照病人登记的先后顺序,每行输入一个病人的信息,包括:一个长度小于10的字符串表示病人的ID(每个病人的ID各不相同且只含数字和字母),一个整数表示病人的年龄,中间用单个空格隔开。输出按排好的看病顺序输出病人的ID,每行一个。样例输入5021075 40004003 15010158 67021033 75102012 30样例输出021033010158021075004003102012练习3:06_整数奇偶排序描述:给定10个整数的序列,要求对其重新排序。排序要求:1.奇数在前,偶数在后;2.奇数按从大到小排序;3.偶数按从小到大排序。输入输入一行,包含10个整数,彼此以一个空格分开,每个整数的范围是大于等于0,小于等于100。输出按照要求排序后输出一行,包含排序后的10个整数,数与数之间以一个空格分开。样例输入4 7 3 13 11 12 0 47 34 98样例输出47 13 11 7 3 0 4 12 34 98练习4:09_明明的随机数描述:明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。输入有2行,第1行为1个正整数,表示所生成的随机数的个数:N;第2行有N个用空格隔开的正整数,为所产生的随机数。输出也是2行,第1行为1个正整数M,表示不相同的随机数的个数。第2行为M个用空格隔开的正整数,为从小到大排好序的不相同的随机数。样例输入1020 40 32 67 40 20 89 300 400 15样例输出815 20 32 40 67 89 300 400练习5:09_直方图描述:给定一个非负整数数组,统计里面每一个数的出现次数。我们只统计到数组里最大的数。假设 Fmax (Fmax < 10000)是数组里最大的数,那么我们只统计 {0,1,2.....Fmax} 里每个数出现的次数。输入第一行n是数组的大小。1 <= n <= 10000。紧接着一行是数组的n个元素。输出按顺序输出每个数的出现次数,一行一个数。如果没有出现过,则输出0。对于例子中的数组,最大的数是3,因此我们只统计{0,1,2,3}的出现频数。样例输入51 1 2 3 1样例输出031 1练习6:29_统计字符数描述:给定一个由a-z这26个字符组成的字符串,统计其中哪个字符出现的次数最多。输入输入包含一行,一个字符串,长度不超过1000。输出输出一行,包括出现次数最多的字符和该字符出现的次数,中间以一个空格分开。如果有多个字符出现的次数相同且最多,那么输出ascii码最小的那一个字符。样例输入abbccc样例输出c 3练习7:06_校门外的树 描述:某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。输入第一行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。对于20%的数据,区域之间没有重合的部分;对于其它的数据,区域之间有重合的情况。输出包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。样例输入500 3150 300100 200470 471样例输出298练习8:07_合影效果描述:小云和朋友们去爬香山,为美丽的景色所陶醉,想合影留念。如果他们站成一排,男生全部在左(从拍照者的角度),并按照从矮到高的顺序从左到右排,女生全部在右,并按照从高到矮的顺序从左到右排,请问他们合影的效果是什么样的(所有人的身高都不同)?输入第一行是人数n(2 <= n <= 40,且至少有1个男生和1个女生)。后面紧跟n行,每行输入一个人的性别(男male或女female)和身高(浮点数,单位米),两个数据之间以空格分隔。输出n个浮点数,模拟站好队后,拍照者眼中从左到右每个人的身高。每个浮点数需保留到小数点后2位,相邻两个数之间用单个空格隔开。样例输入6male 1.72male 1.78female 1.61male 1.65female 1.70female 1.56样例输出1.65 1.72 1.78 1.70 1.61 1.56练习9:07_有趣的跳跃 描述:一个长度为n(n>0)的序列中存在“有趣的跳跃”当前仅当相邻元素的差的绝对值经过排序后正好是从1到(n-1)。例如,1 4 2 3存在“有趣的跳跃”,因为差的绝对值分别为3,2,1。当然,任何只包含单个元素的序列一定存在“有趣的跳跃”。你需要写一个程序判定给定序列是否存在“有趣的跳跃”。输入一行,第一个数是n(0 < n < 3000),为序列长度,接下来有n个整数,依次为序列中各元素,各元素的绝对值均不超过1,000,000,000。输出一行,若该序列存在“有趣的跳跃”,输出"Jolly",否则输出"Not jolly"。样例输入4 1 4 2 3样例输出Jolly

原创粉丝点击