PTA 统计工龄 思路分析及代码解析

一、前导

1. 需要掌握的知识

需要熟悉各种排序算法 或者 直接使用sort()函数。本文使用快速排序完成排序

2. 题目信息

2.1 题目来源:PTA / 拼题A
2.2 题目地址: 统计工龄

二、解题思路分析

1. 题意理解

排序算法基础练习题

1. 1 输入数据

8	//员工人数
10 2 0 5 7 2 5 2  //每个员工的工龄

1.2 输出数据

0:1 //员工工龄:对应的人数
2:3
5:2
......

2. 思路分析

通过数组存储每个员工的工龄,然后使用快速排序对员工工龄进行排序,最后按要求输出即可

三、具体实现

1. 弯路和bug

快速排序实现难度比较大,容易出错。还是sort()省心省力鸭

2. 代码框架(重点)

2.1 采用的数据结构

使用数组存储员工工龄数据

typedef int ElementType;
#define max 100010
ElementType A[max];

2.2 程序主体框架

               程序伪码描述
int main()
{
	1.存储工龄数据	
	2.排序
	3.按要求打印
}

2.3 各分支函数

2.3.1 QuickSort() 提供统一调用接口,本质是调用Qsort()函数

void QuickSort(ElementType A[], int N)
{
    Qsort(A, 0, N - 1);
}

2.3.2 Qsort() 核心函数,AC的关键。快速排序的步骤如下:
(1)选择基准:示例中用的是从数组的头、中、尾中选取中间值作为基准(三数取中)

ElementType MedianThree(ElementType A[], int Left, int Right) //3数取中
{
    int Center = (Left + Right) / 2;

    if (A[Left] > A[Center])
        Swap(&A[Left], &A[Center]); //&A[Left]表示数组元素A[Left]的地址

    if (A[Left] > A[Right])
        Swap(&A[Left], &A[Right]);

    if (A[Center] > A[Right])
        Swap(&A[Center], &A[Right]);
   //经过上面的位置交换后,A[Left] < A[Center] < A[Right]
    Swap(&A[Center], &A[Right-1]); /* 将基准Pivot放到右边,这样只需关心 Left+1 到 Right-2的数据了*/
    
    return  A[Right - 1];  /* 返回基准Pivot */
}

(2)从小到大排序,比基准小的移到基准左边,大的移到右边,重复上述操作,直到Low > High,即:此时达成了这样的效果,标志位Low前的数值都比基准小,位置Low及之后的数值比基准大。将标准为Low的元素与基准交换位置,这个位置就是基准元素的最终排序位置。这样说有点难以理解,请参考下面的画图和代码(示例中,5是第一次快速排序的基准)
在这里插入图片描述

	Pivot = MedianThree(A, Left, Right); /* Pivot就是选定的基准 */      
	Low = Left;
	High = Right - 1;
	while (1) /*将序列中比基准小的移到基准左边,大的移到右边*/
	{
	     while (A[++Low] < Pivot) {}
	     
	     while (A[--High] > Pivot) {}
	
	     if (Low < High)  //Low=High时的情况? 想象下 2 2 2 2的快排过程      
	         Swap(&A[Low], &A[High]);
	     else break;
	 }
	 Swap(&A[Low], &A[Right - 1]); //交换之后,就找到了基准的最终排序位置了

(3)通过递归分别解决基准的左边 和 右边,由于用到了递归,当元素数量不多时,直接使用简单排序进行处理(比如快速排序)

void Qsort(ElementType A[], int Left, int Right)
{ 
    int Pivot, Low, High;

    if (Right - Left >= 100) //待排序数据不小于100时,使用快速排序
    {
        找到基准最终位置的代码见(2) //找到基准的最终位置后(Low就是最终位置),通过递归进行处理
        Qsort(A, Left, Low - 1);    /* 递归解决左边 */
        Qsort(A, Low + 1, Right);   /* 递归解决右边 */
    }
    else 
        Insert_Sort(A + Left, Right - Left + 1); /* 为提高效率,元素小于100时用插入排序 */
}

2.3.3 PrintResult() 按要求进行打印

void PrintResult(ElementType A[], int n)
{
    int count = 1;

    for (int i = 0; i < n; )
    {
        while (i <= n - 2 && A[i] == A[i + 1])
        {
            count++;
            i++;
        }
        cout << A[i] << ":" << count << endl;
        i++; count = 1;
    }
}

3. 完整AC编码

如有建议或问题,欢迎留言


#include <iostream>
#include <algorithm>
using namespace std;

typedef int ElementType;
#define max 100010
#define Cutoff 100

void Insert_Sort(ElementType A[], int n);

ElementType MedianThree(ElementType A[], int Left, int Right);
void Swap(ElementType* a, ElementType* b);
void Quick_Sort(ElementType A[], int N);
void Qsort(ElementType A[], int Left, int Right);

void PrintResult(ElementType A[], int n);


int main()
{
    int n; ElementType A[max];

    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> A[i];

    Quick_Sort(A, n);

    PrintResult(A, n);
    
}
void PrintResult(ElementType A[], int n)
{
    int count = 1;

    for (int i = 0; i < n; )
    {
        while (i <= n - 2 && A[i] == A[i + 1])
        {
            count++;
            i++;
        }
        cout << A[i] << ":" << count << endl;
        i++; count = 1;
    }
}

void Insert_Sort(ElementType A[], int n) // The similar as arrange the playing card
{
    int P, i, tmp;
    for (P = 1; P < n; P++)
    {
        tmp = A[P]; //draw a card

        for (i = P; i > 0 && A[i - 1] > tmp; i--)
            A[i] = A[i - 1]; //move the sorted card and find the position 

        A[i] = tmp; //insert the position
    }
    return;
}


ElementType MedianThree(ElementType A[], int Left, int Right) //3数取中
{
    int Center = (Left + Right) / 2;

    if (A[Left] > A[Center])
        Swap(&A[Left], &A[Center]); //&A[Left]表示数组元素A[Left]的地址

    if (A[Left] > A[Right])
        Swap(&A[Left], &A[Right]);

    if (A[Center] > A[Right])
        Swap(&A[Center], &A[Right]);
   
    Swap(&A[Center], &A[Right-1]); /* 将基准Pivot藏到右边,这样只需关心 Left+1 至 Right-2的数据了*/

    return  A[Right - 1];  /* 返回基准Pivot */
}

void Qsort(ElementType A[], int Left, int Right)
{ 
    int Pivot, Low, High;

    if (Right - Left >= Cutoff) //待排序数据不小于100时,使用快速排序
    {
        Pivot = MedianThree(A, Left, Right); /* 选基准 */      
        Low = Left;
        High = Right - 1;

        while (1) /*将序列中比基准小的移到基准左边,大的移到右边*/
        {
            while (A[++Low] < Pivot) {}

            while (A[--High] > Pivot) {}

            if (Low < High)  //Low=High时的情况?       
                Swap(&A[Low], &A[High]);
            else break;
        }
          
        Swap(&A[Low], &A[Right - 1]);   /* 将基准换到正确的位置 */

        Qsort(A, Left, Low - 1);    /* 递归解决左边 */
        Qsort(A, Low + 1, Right);   /* 递归解决右边 */
    }
    else 
        Insert_Sort(A + Left, Right - Left + 1); /* 为提高效率,元素小于100时用插入排序 */
}

void Quick_Sort(ElementType A[], int N)
{ 
    Qsort(A, 0, N - 1);
}

void Swap(ElementType* a, ElementType* b) //直接交换
{
    int tmp=*a; *a = *b; *b = tmp;
}

四、参考

浙江大学 陈越、何钦铭老师主讲的数据结构

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值