day5 – CAD2 CAD 类工厂

工厂方法模式

定义

厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

工厂方法模式:是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。

工厂方法模式对简单工厂模式进行了抽象:有一个抽象的Factory类(可以是抽象类和接口),这个类将不再负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。工厂方法模式(Factory Method pattern)是最典型的模板方法模式(Template Method pattern)应用。

工厂方法在面向对象系统设计中解决的两类问题

(1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现, 达到了多态的目的。 这里很容易出现的一个问题 n 多的子类继承自抽象基类,我们不得不在每次要用到子类的地方就编写诸如 new ×××;的代码。这里带来两个问题 a.客户程序员必须知道实际子类的名称(当系统复杂后, 命名将是一个很不好处理的问题, 为了处理可能的名字冲突, 有的命名可能并不是具有很好的可读性和可记忆性, 就姑且不论不同程序员千奇百怪的个人偏好了。) b.程序的扩展性和维护变得越来越困难。

(2)还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。这里的意思

为:假设我们在类 A 中要使用到类 B, B 是一个抽象父类,在 A 中并不知道具体要实例化那一个 B 的子类, 但是在类 A 的子类 D 中是可以知道的。 在 A 中我们没有办法直接使用类似于 new ×××的语句,因为根本就不知道×××是什么。

(3)以上两个问题也就引出了 Factory 模式的两个最重要的功能:

​ 1)定义创建对象的接口,封装了对象的创建;

​ 2)使得具体化类的工作延迟到了子类中

工厂方法的结构示意图

常用八大排序

(1)快排(递归&&非递归)

原理:

它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。步骤:

设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。

步骤:维基百科

一趟快速排序的算法是:

​ 1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;

2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];

3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]互换;

4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;

5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

(2)归并排序

原理:

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并过程为:比较a[i]和b[j]的大小,若a[i]≤b[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素b[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

步骤:

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置

第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置重复步骤3直到某一指针超出序列尾将另一序列剩下的所有元素直接复制到合并序列尾

(3)交换排序

原理:

​ 交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

(4)冒泡排序

原理:

1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。

2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

3) 针对所有的元素重复以上的步骤,除了最后一个。

4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

(5)选择排序

原理:

​ 选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。

(6)插入排序

原理:

输入一个元素,检查数组列表中的每个元素,将其插入到一个已经排好序的数列中的适当位置,使数列依然有序,当最后一个元素放入合适位置时,该数组排序完毕。

(7)希尔排序

原理:

在直接插入排序算法中,每次插入一个数,使有序序列只增加1个节点,并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。

(8)堆排序

原理:

(1)用大根堆排序的基本思想

① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区

② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key

③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。

……

直到无序区只有一个元素为止。

(2)大根堆排序算法的基本操作:

​ ①建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点,此处len是堆中元素的个数。建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程,相当于o(h1)+o(h2)…+o(hlen/2) 其中h表示节点的深度,len/2表示节点的个数,这是一个求和的过程,结果是线性的O(n)。

②调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,如果最大(小)值不是节点i而是它的一个孩子节点,那边交互节点i和该节点,然后再调用调整堆过程,这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,因为是沿着深度方向进行调整的。

③堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。堆排序过程的时间复杂度是O(nlgn)。因为建堆的时间复杂度是O(n)(调用一次);调整堆的时间复杂度是lgn,调用了n-1次,所以堆排序的时间复杂度是O(nlgn)[2]

注意:

①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。

​ ②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止

特点:

堆排序(HeapSort)是一树形选择排序。堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的 内在关系(参见二叉树的顺序存储结构),在当前无序区中选择关键字最大(或最小)的记录

c++实现源码:

//Factory.h
#ifndef _SORTFACTORY_H_
#define _SORTFACTORY_H_
class SortProduct;
class TreeProduct;
 
class Factory
{
public:
	virtual SortProduct* QuickSort(int *Arr,int Len,char s) = 0;
	virtual SortProduct* MergSort(int *Arr, int Len) = 0;
	virtual SortProduct* SwapSort(int *Arr, int Len) = 0;
	virtual SortProduct* BubbleSort(int *Arr, int Len) = 0;
	virtual SortProduct* SelectSort(int *Arr, int Len) = 0;
	virtual SortProduct* InsertSort(int *Arr, int Len) = 0;
	virtual SortProduct* ShellSort(int *Arr, int Len) = 0;  
	virtual SortProduct* HeapSort(int *Arr, int Len) = 0;
protected:
	Factory();
	virtual ~Factory() = 0;
private:
};
 
class ConcreteFactory:public Factory
{
public:
	~ConcreteFactory();
	ConcreteFactory(int *Arr, int Len);
	static void Print(int *Arr, int Len);
	SortProduct* QuickSort(int *Arr, int Len, char s);
	SortProduct* MergSort(int *Arr, int Len);
	SortProduct* SwapSort(int *Arr, int Len);
	SortProduct* BubbleSort(int *Arr, int Len);
	SortProduct* SelectSort(int *Arr, int Len);
	SortProduct* InsertSort(int *Arr, int Len);
	SortProduct* ShellSort(int *Arr, int Len);
	SortProduct* HeapSort(int *Arr, int Len);
private:
	int *P;
	int  N;
};
#endif
//SortProduct.h
       #ifndef _SORTPRODUCT_H_
       #define _SORTPRODUCT_H_
class SortProduct
{
public:
	virtual ~SortProduct() =0;
protected:
  SortProduct();
private:
};
 
 
/*
*快速排序
*/
class QuickSortN:public SortProduct
{
public:
	QuickSortN(int *Arr, int Len,char s);
	void RecusiveQuickSort(int *Arr, int Len);
	void NoRecusiveQuickSort(int *Arr, int Len);
protected:
	int Partation(int *Arr, int Low, int Hight);
	void RecusiveQuickSortN(int *Arr, int Low, int Hight);
	void NoRecusiveQuickSortN(int *Arr, int Low, int Hight);
private:
	int *P;
    int  N;
	char S;
};
 
 
class MergSortN :public SortProduct
{
public:
	MergSortN(int *arr, int start, int end);
	void Mymerge(int *arr, int start, int midd, int end);
private:
	int *P;
	int  N;
};
 
 
class SwapSortN : public SortProduct
{
public:
	void SwapSort(int *Arr, int Len);
	SwapSortN(int *Aarr,int Len);
private:
	int *P;
	int  N;
};
 
 
class BubbleSortN : public SortProduct
{
public:
	void BubbleSort(int *Arr, int Len);
	BubbleSortN(int *Aarr, int Len);
private:
	int *P;
	int  N;
};
 
class SelectSortN : public SortProduct
{
public:
	void SelectSort(int *Arr, int Len);
	SelectSortN(int *Aarr, int Len);
private:
	int *P;
	int  N;
};
 
class InsertSortN : public SortProduct
{
public:
	void InsertSort(int *Arr, int Len);
	InsertSortN(int *Aarr, int Len);
private:
	int *P;
	int  N;
};
 
class ShellSortN : public SortProduct
{
public:
	void ShellSort(int *Arr, int Len);
	ShellSortN(int *Aarr, int Len);
private:
	int *P;
	int  N;
};  
 
class HeapSortN : public SortProduct
{
public:
	static void HeapSort(int *Arr, int Len);
	HeapSortN(int *Aarr, int Len);
private:
	int *P;
	int  N;
};
#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值