修炼算法内功:选择排序(一)

内容:1、简单的选择排序;

           2、使用模板(泛型)使算法更加灵活;

           3、使用结构体完成学生的name和score属性的排序;

           4、随机生成算法测试用例。


写在前面:为什么学习O(n^2)的排序算法?

基础

  • 编码简单,易于实现,是一些简单场景的首选
  • 在一些特殊情况下,,简单的排序算法更有效
  • 简单的排序算法思想可衍生出复杂的排序算法
  • 作为子过程,改进更复杂的排序算法
  •  

1、Selection Sort 选择排序

基本思路

如:8 6 2 3 1 5 7 4

对一个序列A中的元素A[1]~A[n],令i从1到n的枚举,进行n趟操作,每趟从排序部分[i,n]中选择最小的元素,令其与待排序部分的第一个元素A[i]进行交换,直到排序完成。

示例:

[1,8]中1最小(1,8交换)——>1 6 2 3 8 5 7 4

[2,8]中2最小(2,6交换)——>1 2 6 3 8 5 7 4

[3,8]中3最小(3,6交换)——>1 2 3 6 8 5 7 4

[4,8]中4最小(4,6交换)——>1 2 3 4 8 5 7 6

[5,8]中5最小(5,8交换)——>1 2 3 4 5 8 7 6

[6,8]中6最小(6,8交换)——>1 2 3 4 5 6 7 8

[7,8]中7最小(7,8不换)——>1 2 3 4 5 6 7 8

排序完成

代码块1:

void selectionSort(int A[],int n)
{
    for(int i=0;i<n;i++)
        //寻找[i,n)区间里的最小值
        {
            int minIndex=i;
            for(int j=i+1;j<n;j++)
                if(A[j]<A[minIndex])
                minIndex=j;
            swap(A[i],A[minIndex]);//C++标准库内置函数,头文件为algorithm
        }
}

 2、使用模板(泛型)编写算法

添加模板template<typename T>,即可定义T类型数组。如:

void selectionSort(T A[],int n);//T代替了之前的int型

这样我们就可以使用更多类型的数组,使排序更加多样化。如:

代码块2:

int a[10]={2,3,5,7,6,1,4,9,8,10};
    selectionSort(a,10);
    for(int i=0;i<10;i++)
    cout<<a[i]<<" ";
    cout<<endl;

    float b[4]={2.1,3.2,1.8,4.9};
    selectionSort(b,4);
    for(int i=0;i<4;i++)
    cout<<b[i]<<" ";
    cout<<endl;
    
    string c[4]={"B","D","C","A"};
    selectionSort(c,4);
    for(int i=0;i<4;i++)
    cout<<c[i]<<" ";
    cout<<endl;

 

运行结果:

以上,我使用int、float和string三种类型完成对应类型的排序工作,但我只调用了一种函数。这就是模板(泛型)带来的好处,可以引用不同类型的数据类型,使自己的算法更加灵活多变。

3、使用头文件定义Student结构体,实现学生分数排序。(重要)

student.h

#pragma once
#ifndef SELECTIONSORT_STUDENT_H
#define SELECTIONSORT_STUDENT_H

#include<iostream>
#include<string>

using namespace std;

struct Student {//结构体的定义
	string name;//定义名字
	int score;//定义成绩

	bool operator<(const Student &otherStudent){//方法的重载
		return score < otherStudent.score;
	}
	friend ostream&  operator<<(ostream &os, const Student  &Student) {
		os << "Student:"<< Student.name << " "<<Student.score<< endl;
		return os;
	}
};

#endif // !SELECTIONSORT_STUDENT_H





注:引用头文件——>#include"student.h"  注意,自己声明的头文件使用"",而不是<>。

代码块4:

Student d[4] = { {"D",80},{"A",70},{ "C",60 },{ "B",80 } };
	selectionSort(d, 4);
	for (int i = 0; i<4; i++)
		cout << d[i];
	cout << endl;

运行结果:

思考:学生D和学生B成绩一样,是按照什么顺序排列的呢?怎么排列使它更加合理化呢?

     学生D和学生B是按照原先数组给定的顺序排列的;如果使排序更加合理化,我们可以将学生的姓名进行一次排序,类似于我们平时的 姓名首字母排序。

     如何实现name属性排序呢?

    我们在使用方法判断score大小时,可以利用条件运算符(三目运算符)实现name大小比较。即:

    return score != otherStudent.score ? score < otherStudent.score : name < otherStudent.name;

   是否相等——>不相等比较成绩

                 ——>相等则比较姓名

代码块5:

return score != otherStudent.score ? score < otherStudent.score : name < otherStudent.name;

  运行结果:

学生B的字母是排在学生D的字母前面的。

       由此可见,自定义比较的威力是非常强大的,要学会自己定义,深入思考算法精髓,使自己的编程更加个性化,而不是仅仅局限于现成的代码和算法,甘心做个代码打印机。

       如果想学习更多关于基础排序的算法知识点击——>继续阅读

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值