本文主要是使用C++的操作符重载和模板的语法,完成一些结构性数据的排序,本文会实现冒泡、插入和选择三种简单排序,后续会更新希尔排序、快速排序、归并排序三种高级简单排序的方法。
1、C++操作符重载
操作符重载,也叫运算符重载,是C++的重要组成部分,它可以让程序更加的简单易懂,简单的运算符使用可以使复杂函数的理解更直观。
虽然运算符重载听起来好像是C++的外部能力,但是多数程序员都不知不觉地使用过重载的运算符。例如,加法
运算符“+”对整数、单精度数和双精度数的操作是大不相同的。这是因为C++语言本身已经重载了该运算符,所以它能够用于int、float、double和其它内部定义类型的变量。
操作符重载可对已有的运算符(C++中预定义的运算符)赋予多重的含义,使同一运算符作用于不同类型的数据时导致不同类型的行为。
其目的是:扩展C++中提供的运算符的适用范围,以用于类所表示的抽象数据类型。同一个运算符,对不同类型的操作数,所发生的行为不同。
操作符被重载的基本前提:
1.只能为自定义类型重载操作符;
2.不能对操作符的语法(优先级、结合性、操作数个数、语法结构) 、语义进行颠覆;
3.不能引入新的自定义操作符。
1.1、对于比较运算符的重载(本次会用到)
bool Student::operator>(const Student& stu)
{
if(this->age > stu.age)
return true;
return false;
}
bool Student::operator<(const Student& stu)
{
if(this->age < stu.age)
return true;
return false;
}
bool Student::operator==(const Student& stu)
{
if(this->age == stu.age)
return true;
return false;
}
1.2、对于自增自减运算符的重载(仅供参考)
Student& Student::operator++()
{
int temp = this->getAge();
this->setAge(temp+1);
return *this;
}
//Hou Zhi
Student Student::operator++(int)
{
Student tempObj = *this;
int temp = this->getAge();
this->setAge(temp+1);
return tempObj;
}
void Student::Display()
{
cout << this->getName() << "'s age is " << this->getAge() << endl;
}
//Qian Zhi
Student& Student::operator--()
{
int temp = this->getAge();
this->setAge(temp-1);
return *this;
}
//Hou Zhi
Student Student::operator--(int)
{
Student tempObj = *this;
int temp = this->getAge();
this->setAge(temp-1);
return tempObj;
}
//后置版本接受一个额外的参数(不被使用)int类型的参数(必须是int类型的)。
//当我们使用后置运算符时,编译器为这个形参提供一个值为0的实参。
//尽管从语法上说后置函数可以使用这个额外的形参,但在实际过程中通常不会这样做。
//这个形参的唯一作用就是区分前置和后置版本的函数,而不是真的要在实现后置版本是参与运算。
//因为前置和后置版本的递增或者递减函数原型必须加以一个特殊的区分,c++语言选择增加一个占位参数实现后置版本。
2、C++ 模板最初C++是没有标准库的,任何一门语言的发展都需要标准库的支持,为了让C++更强大,Bjarne Stroustrup觉得需要给C++提供一个标准库,但标准库设计需要一套统一机制来定义各种通用的容器(数据结构)和算法,并且能很好在一起配合,这就需要它们既要相对的独立,又要操作接口保持统一,而且能够很容易被别人使用(用到实际类中),同时又要保证开销尽量小(性能要好)。 Bjarne Stroustrup 提议C++需要一种机制来解决这个问题,所以就催生了模板的产生,最后经标准委员会各路专家讨论和发展,就发展成如今的模版, C++ 第一个正式的标准也加入了模板。
C++模版是一种解决方案,初心是提供参数化容器类和通用的算法(函数)。
模板类语法:
```C++
template<typename T>
class X{...};
```
3、几种简单的排序算法
3.1、冒泡排序
1. 比较相邻的元素。如果前一个元素比后一个元素大,就交换这两个元素的位置。
2. 对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大
值。
3.2、选择排序
1.每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处
的值大于其他某个索引处的值,则假定其他某个索引出的值为最小值,最后可以找到最小值所在的索引
2.交换第一个索引处和最小值所在的索引处的值
3.3 插入排序
1.把所有的元素分为两组,已经排序的和未排序的;
2.找到未排序的组中的第一个元素,向已经排序的组中进行插入;
3.倒叙遍历已经排序的元素,依次和待插入的元素进行比较,直到找到一个元素小于等于待插入元素,那么就把待
插入元素放到这个位置,其他的元素向后移动一位;
4、整体代码实现
main.cpp (这里对冒泡算法进行测试,其余两种排序方式亦同)
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include "common.h"
using namespace std;
int main()
{
vector<Student> Student_list;
srand((unsigned)time(NULL));
for(int i = 0;i < 100; i++)
{
string name = "LI_" + to_string(i);
Student stu(name,int(rand()%100));
Student_list.push_back(stu);
}
//cout << Student_list.size();
bubbleSort(Student_list);
for(auto st:Student_list)
st.Display();
}
common.h (对学生类进行定义,以及排序算法的实现,另外,如果使用模板的话,函数的声明和实现应该在一个文件内)
#ifndef COMMON_H
#define COMMON_H
#include <iostream>
#include <vector>
using namespace std;
class Student
{
private:
string name;
int age;
public:
void setName(string uname);
string getName();
void setAge(int uage);
int getAge();
Student()
{
}
Student(string uname,int uage);
// Operator >
bool operator>(const Student& stu);
bool operator<(const Student& stu);
bool operator==(const Student& stu);
//Qian Zhi
Student& operator++();
//Hou Zhi
Student operator++(int);
void Display();
//Qian Zhi
Student& operator--();
//Hou Zhi
Student operator--(int);
};
//应用模板写冒泡排序 实现各类数据的排序
template<typename T>
void bubbleSort(vector<T>& data)
{
int n = data.size();
if(n <= 1)
return;
for(int i = 0; i < n; i++)
{
for (int j = 0; j < n -1; j++)
{
if(data[j] > data[j+1])
{
swap(data[j],data[j+1]);
}
}
}
return;
}
//应用模板写选择排序 实现各类数据的排序
template<typename T>
void selectionSort(vector<T>& data)
{
int n = data.size();
if(n <= 1)
return;
for(int i = 0;i < n-1; i++)
{
int min_index = i;
for(int j = i+1; j < n; j++)
{
if(data[j] < data[min_index])
min_index = j;
}
if(i == min_index)
continue;
swap(data[i],data[min_index]);
}
return;
}
//应用模板写插入排序 实现各类数据的排序
template<typename T>
void insertionSort(vector<T>& data)
{
int n = data.size();
if(n <= 1)
return;
for(int i = 1; i < n; i++)
{
for(int j = i;j >= 1; j--)
{
if(data[j-1] > data[j])
swap(data[j-1],data[j]);
else {
break;
}
}
}
return;
}
common.cpp(对学生类的实现)
#include<iostream>
#include"common.h"
using namespace std;
void Student::setName(string uname)
{
this->name = uname;
}
string Student::getName()
{
if(name == "")
{
cout << "You have not set name" << endl;
return nullptr;
}
return this->name;
}
void Student::setAge(int uage)
{
this->age = uage;
}
int Student::getAge()
{
return this->age;
}
Student::Student(string uname,int uage)
{
this->age = uage;
this->name = uname;
}
bool Student::operator>(const Student& stu)
{
if(this->age > stu.age)
return true;
return false;
}
bool Student::operator<(const Student& stu)
{
if(this->age < stu.age)
return true;
return false;
}
bool Student::operator==(const Student& stu)
{
if(this->age == stu.age)
return true;
return false;
}
//Qian Zhi
Student& Student::operator++()
{
int temp = this->getAge();
this->setAge(temp+1);
return *this;
}
//Hou Zhi
Student Student::operator++(int)
{
Student tempObj = *this;
int temp = this->getAge();
this->setAge(temp+1);
return tempObj;
}
void Student::Display()
{
cout << this->getName() << "'s age is " << this->getAge() << endl;
}
//Qian Zhi
Student& Student::operator--()
{
int temp = this->getAge();
this->setAge(temp-1);
return *this;
}
//Hou Zhi
Student Student::operator--(int)
{
Student tempObj = *this;
int temp = this->getAge();
this->setAge(temp-1);
return tempObj;
}
//后置版本接受一个额外的参数(不被使用)int类型的参数(必须是int类型的)。
//当我们使用后置运算符时,编译器为这个形参提供一个值为0的实参。
//尽管从语法上说后置函数可以使用这个额外的形参,但在实际过程中通常不会这样做。
//这个形参的唯一作用就是区分前置和后置版本的函数,而不是真的要在实现后置版本是参与运算。
//因为前置和后置版本的递增或者递减函数原型必须加以一个特殊的区分,c++语言选择增加一个占位参数实现后置版本。
实现效果
至此,实现了通过操作符重载以及模板实现了对于一个类的排序算法,当然由于使用了模板,将上述main函数中的bubbleSort参数改为一个普通的vector容器,亦可以实现排序。