第十六篇--算法导论排序篇总结-开发实用quicksort算法

Vectorless dynamic动态功耗分析——Voltus power 计算工具会根据设计信息和用户提供的activity和switching约束来生成虚拟的worst-case的power vector,难点在于哪些instances视为switching,在没有仿真的前提下如何确定开关的时间,使用timing文件(TWF) 阅读详情

行百里者半九十,此言得之。

当看完快速排序之后,我了解了它的思想,我也会实现它的代码,可是,这就是我所需要的quicksort算法吗?显然不是。

习题7-1-2问道:如果数组中元素都相同,该怎么办?

 如果采用伪代码直接实现的程序,时间复杂度为n的平方;作者提供了思路,当A[p..r]中的元素相同时,返回的q为(p+r)/2,这样就能保持最好的性能。


习题7-4-5问道:难道一路quicksort递归到底,性能最好吗?能不能改进?

作者又提供了思路:当输入数组已经几乎有序时,插入排序的速度非常快;在实际应用中,我们对一个长度为k的子数组调用快速排序时,让它直接返回;最后对整个数组运行插入排序;


习题7-2问道:我们可不可以实现对于A[p..r]调用划分时,获得A[p..q-1]小于主元;A[q...t]等于主元;A[t+1..r]大于主元?


习题7-4说:其实消除尾递归是能提高程序性能的。。。


习题7-5问:怎么选择主元?如果随机选择实现的太慢,且效果不一定很好;而直接选最后一个元素又太容易出现最坏情况。

作者说:最常用的改进RANDOM-QUICKSORT的方法是:从子数组中更细致的选择主元而非随机选择。常用做法是三数取中法:

从子数组中随机选择三个元素,取其中位数作为主元;


习题7-6问:其实区间模糊排序也可以采用向quicksort一样的排序手法,如何写扩展性好的quicksort算法?


一个算法背后隐藏着这么多的细节或者说是技巧,虽然我们做题目的时候写的都是简单的,不考虑这么多问题的,但是实际应用中自然是要考虑这些细节的,所以本篇的目的是-------如何实现一个实用的排序算法?


程序说明:取材于STL。命名的规则是:只在函数中调用而非面向用户的接口的函数均为  _xxxx(除sort外都是。。)

//----------------------------------------------------------------------------------------------------
//这里的插入排序跟《算法导论》的伪代码一致
 //对迭代器[first,last)范围内的元素按递增排序
template<typename RandomIterator>
void _insertion_sort(RandomIterator first,RandomIterator last)
{
	typedef  typename iterator_traits<RandomIterator>::value_type  value_type;
	if(first==last) return;
	for(RandomIterator i=first+1;i!=last;++i){
		RandomIterator j=i-1;
		value_type  key=*i;
		while(j>=first && key<*j){
				*(j+1)=*j;
				--j;
		}
		*(j+1)=key;
	}
}

//对迭代器[first,last)范围内的元素按函数对象进行排序
template<typename RandomIterator,typename Compare>
void _insertion_sort(RandomIterator first,RandomIterator last,Compare comp)
{
	typedef  typename iterator_traits<RandomIterator>::value_type  value_type;
	if(first==last) return;
	for(RandomIterator i=first+1;i!=last;++i){
		RandomIterator j=i-1;
		value_type  key=*i;
		while(j>=first && comp(key,*j)){
				*(j+1)=*j;
				--j;
		}
		*(j+1)=key;
	}
}
//-------------------------------------------------------------------------------------------------

quicksort在平均情况下复杂度为O(nlgn),不过我们这儿采用的改进版的时间复杂度最坏情况下为O(nlgn)

//策略一:三点中值做主元
//三点取中值
template<typename T>
inline const T& _median(const T& a,const T& b,const T& c)
{
	if(a<b){
		if(b<c)//a<b<c
			return b;
		else if(a<c) //a<b,a<c,b>=c
			return c;
		else //a<b,b>=c,a>=c
			return a;
	}
	else if(a<c)//a>b,a<c
		return a;
	else if(b<c)//a>b,a>c,b<c
		return c;
	else         //a>b,a>c,b>c
		return b;
}
//------------------------------------------------------------------------

然后是quicksort的划分代码,这里的划分实现选择了《算法导论》书中的伪代码,而非习题7-1的实现方式(STL中采用的是习题7-1的实现方式)

//------------------------------------------------------------------------
//两个辅助性工具函数,用于交换两迭代器所指元素的值
template<typename RandomIterator>
inline void iter_swap(RandomIterator& i,RandomIterator& j)
{
  swap(*i,*j);
}
template<typename T>
inline void  swap(T&  L,T& R)
{
	T tmp=R;
	R=L;
	L=tmp;
}
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
//partition函数,划分成两段[first,i)小于等于pivot[i+1,last)大于等于pivot
template<typename RandomIterator,typename T>
RandomIterator _partition(RandomIterator first,RandomIterator last,T pivot)
{
	for(RandomIterator i=first;i!=last;++i){
		if(*i==pivot){RandomIterator tmp=last-1;iter_swap(i,tmp);break;}
	}
	RandomIterator i=first-1;
	RandomIterator r=last-1;
	for(RandomIterator j=first;j!=r;++j){
		if(*j<=pivot){
			++i;
			iter_swap(i,j);
		}
	}
	++i;
	iter_swap(i,r);
	return i;
}
//这里按照传入的函数对象进行划分,
//如果传入的是大于号的话,那么左边子数组大于pivot,右边小于等于pivot
template<typename RandomIterator,typename T,typename Compare>
RandomIterator _partition(RandomIterator first,RandomIterator last,T pivot,Compare comp)
{
	for(RandomIterator i=first;i!=last;++i){
		if(*i==pivot){RandomIterator tmp=last-1;iter_swap(i,tmp);break;}
	}
	RandomIterator i=first-1;
	RandomIterator r=last-1;
	for(RandomIterator j=first;j!=r;++j){
		if(comp(*j,pivot)){
			++i;
			iter_swap(i,j);
		}
	}
	++i;
	iter_swap(i,r);
	return i;
}

总的程序来了:

//-----------------------------------------------------------------------------------------
//策略二:与插入排序结合使用,如习题7-4-5
//策略三:消除尾递归
//策略四:混合式排序:内省式排序;当分割行为有恶化为N^2次行为的倾向时,能够自我侦测,转而
//使用堆排序,使效率维持在NlgN
const int threshold=16;//当子数组元素数小于此值时,调用快速排序则直接返回
//默认情况下按升序排序
template<typename RandomIterator>
inline void sort(RandomIterator first,RandomIterator last)
{
	if(first!=last){
        //控制递归调用的层数最多为__lg(last-first)*2层
                _intro_sort(first,last,value_type(first),__lg(last-first)*2);
		_insertion_sort(first,last);
	}
}
//按照传入的函数对象进行排序
template<typename RandomIterator,typename Compare>
inline void sort(RandomIterator first,RandomIterator last,Compare comp)
{
	if(first!=last){
		_intro_sort(first,last,value_type(first),__lg(last-first)*2,comp);
		_insertion_sort(first,last,comp);
	}
}	
//---------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------
//__lg是为了控制分割恶化
//找到2^k<=n的最大k值
//在sort程序中我们传入__lg(last-first)*2,意为如果元素为40的话,那么k=5;层数最多为10层
template<typename Size>
inline Size __lg(Size n)
{
	Size k;
	for(k=0;n>1;n>>=1)++k;
	return k;
}
//--------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------
//按升序排序
template<typename RandomIterator,typename T,typename Size>
void _intro_sort(RandomIterator first,RandomIterator last,T*,Size depth_limit)
{
	while(last-first>threshold){
		if(depth_limit==0){//分割恶化
			_heap_sort(first,last);
			return;
		}
		--depth_limit;
		//主元采用三点中值选择
		RandomIterator cut=_partition(first,last,T(_median(*first,
			                                                             *(first+(last-first)/2),*(last-1))));
		//消除尾递归
		_intro_sort(cut+1,last,value_type(first),depth_limit);
		last=cut;
	}
}
//按函数对象排序
template<typename RandomIterator,typename T,typename Size,typename Compare>
void _intro_sort(RandomIterator first,RandomIterator last,T*,Size depth_limit,Compare comp)
{
	while(last-first>threshold){
		if(depth_limit==0){//分割恶化
			_heap_sort(first,last,comp);
			return;
		}
		--depth_limit;
		//主元采用三点中值选择
		RandomIterator cut=_partition(first,last,T(_median(*first,
			                                                             *(first+(last-first)/2),*(last-1))),comp);
		//消除尾递归
		_intro_sort(cut+1,last,value_type(first),depth_limit,comp);
		last=cut;
	}
}
//--------------------------------------------------------------------------------------------

现在的主要程序大纲都基本实现了,但是堆排序又是一个大头,这里仍然是采用《算法导论》伪码:

//------------------------------------------------------------------------------------
//辅助程序
template<typename Size>
inline Size _parent(Size i){return (i-1)>>1;}
template<typename Size>
inline Size _left(Size i){return (i<<1)+1;}
template<typename Size>
inline Size _right(Size i){return (i<<1)+2;}

以下函数都在《算法导论》第六章实现过,可以看看我以前写的代码;

//----------------------------------------------------------------------------------------
//保持堆性质,默认最大堆,
template<typename RandomIterator,typename Distance>
void _heapify(RandomIterator first,RandomIterator i,Distance len)
{
	Distance i_index=i-first;
	
	Distance largest=i_index;
	Distance current_index=i_index;
	while(current_index<len){
		Distance i_left_child=_left(current_index);
	    Distance i_right_child=_right(current_index);
		if(i_left_child<len&&(*(first+i_left_child)>*(first+current_index))){
			largest=i_left_child;
		}
		if(i_right_child<len &&(*(first+i_right_child)>*(first+largest))){
			largest=i_right_child;
		}
		if(largest!=current_index){
			RandomIterator tmp1=first+current_index,tmp2=first+largest;
			iter_swap(tmp1,tmp2);
			current_index=largest;
		}else{
			break;
		}
	}
}
//保持堆性质,按函数对象,如:传入小于号,那么就是建立最小堆
template<typename RandomIterator,typename Distance,typename Compare>
void _heapify(RandomIterator first,RandomIterator i,Distance len,Compare comp)
{
	Distance i_index=i-first;
	
	Distance compest=i_index;
	Distance current_index=i_index;
	while(current_index<len){
		Distance i_left_child=_left(current_index);
	    Distance i_right_child=_right(current_index);
		if(i_left_child<len&&comp(*(first+i_left_child),*(first+current_index))){
			compest=i_left_child;
		}
		if(i_right_child<len &&comp(*(first+i_right_child),*(first+compest))){
			compest=i_right_child;
		}
		if(compest!=current_index){
			RandomIterator tmp1=first+current_index,tmp2=first+compest;
			iter_swap(tmp1,tmp2);
			current_index=compest;
		}else{
			break;
		}
	}
}
//------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------
//对[first,last)建堆,默认为最大堆
template<typename RandomIterator>
inline void build_heap(RandomIterator first,RandomIterator last)
{
	typedef iterator_traits<RandomIterator>::difference_type  difference_type;
	typedef iterator_traits<RandomIterator>::value_type     value_type;
	if(last-first<2) return;//如果长度为0或1,不必重新排列
	difference_type len=last-first;
	for(RandomIterator it=first+(len/2)-1;it!=first-1;--it){
		_heapify(first,it,len);
	}
}
//建堆,按函数对象来建
template<typename RandomIterator,typename Compare>
inline void build_heap(RandomIterator first,RandomIterator last,Compare comp)
{
	typedef iterator_traits<RandomIterator>::difference_type  difference_type;
	typedef iterator_traits<RandomIterator>::value_type     value_type;
	if(last-first<2) return;//如果长度为0或1,不必重新排列
	difference_type len=last-first;
	for(RandomIterator it=first+(len/2)-1;it!=first-1;--it){
		_heapify(first,it,len,comp);
	}
}
//----------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------
//堆排序,默认建立最大堆,按升序排序
template<typename RandomIterator>
void _heap_sort(RandomIterator first,RandomIterator last)
{
	typedef iterator_traits<RandomIterator>::difference_type difference_type;
	difference_type len=last-first;
	build_heap(first,last);
	for(difference_type i=len-1;i>=1;--i){
		RandomIterator tmp=(first+len-1);
		iter_swap(first,tmp);
		--len;
		_heapify(first,first,len);
	}
}

下面是按函数对象版本堆排序的,但是这儿有一些细节,首先对于升序排序,我们传入小于号,但是我们需要建立最大堆,所以在建堆过程中我们却需要大于号,这里需要一个函数对象的取反功能,要对一个函数对象取反(配接器),我们建立配接器需要建立在大家都得遵守的约定上,即定义二元函数对象时,应该继承基本的binary_function:

//辅助程序
template<typename Arg1,typename Arg2,typename Result>
struct binary_function
{
	typedef Arg1 first_argument_type;
	typedef Arg2 second_argument_type;
	typedef Result result_type;
};
template<typename Predicate>
class binary_negate   :public  binary_function<typename Predicate::first_argument_type,
                                                      typename Predicate::second_argument_type,bool>
{
protected:
	Predicate _pred;
public:
	explicit binary_negate(const Predicate& x):_pred(x){ }
	bool operator()(const typename Predicate::first_argument_type& x,
		                    const typename Predicate::second_argument_type& y) const
	{return !_pred(x,y);}
};
这样我们使用时,就可以binary_negate<Compare>(comp)对函数对象取反啦

//按函数对象进行堆排序
template<typename RandomIterator,typename Compare>
void _heap_sort(RandomIterator first,RandomIterator last,Compare comp)
{
	typedef iterator_traits<RandomIterator>::difference_type difference_type;
	difference_type len=last-first;
	build_heap(first,last,binary_negate<Compare>(comp));
	for(difference_type i=len-1;i>=1;--i){
		RandomIterator tmp=(first+len-1);
		iter_swap(first,tmp);
		--len;
		_heapify(first,first,len,binary_negate<Compare>(comp));
	}
}

好,如此我们的程序就完成了,这就是使用的快速排序算法!

下面是一些测试:

需要包含的头文件:

#include<iostream>
#include<cstdlib>

//升序排列
int main()
{
	int  A[10];
	for(int i=0;i<10;++i){
		A[i]=rand()%100;
	}
    sort(A,A+10);

   for(int* it=A;it!=A+10;++it){
	   std::cout<<*it<<" ";
	}
	char c=getchar();
}

结果:

首先定义一个大于号的函数对象:

template<typename T>
struct greater :public binary_function<T,T,bool>
{
	bool operator()(const T& x,const T& y)const{return x>y;}
};
然后降序排列:


//降序排列
int main()
{
	int  A[10];
	for(int i=0;i<10;++i){
		A[i]=rand()%69;
	}
	sort(A,A+10,greater<int>());

   for(int* it=A;it!=A+10;++it){
	   std::cout<<*it<<" ";
	}
	char c=getchar();
}

由于我写的代码不是很好,所以对于一个可以排序的类至少要定义四种关系操作符:

struct student
{
	int id;
	char name;
	student(int a=0,char b=0):id(a),name(b){ }
	bool operator<(const student& r)const{return id<r.id;}
	bool operator<=(const student& r)const {return id<=r.id;}
	bool operator==(const student& r)const {return id==r.id;}
	bool operator>(const student& r)const {return id>r.id;}
	
};

这里只是为了测试,所以student类地设计非常粗糙,只是为了证明正确性,测试程序也写得很糟糕。。。。请谅解大笑:


int main()
{
	student A[10];
	for(int i=0;i<10;++i){
		int x=rand()%120;
		A[i].id=x;
		A[i].name=x+'a';
	}
	sort(A,A+10);
	 for(student* it=A;it!=A+10;++it){
	   std::cout<<(*it).id<<" ";
	}
	 char c=getchar();
}

最后一个,就是我在第六章的一个问题,对于非常大的卫星数据,对于优先队列来说,我们更多的是使用句柄(指针)而非直接用数据,所以对于指向某一类型数据的句柄或指针,我们也要让他能够在优先队列中工作,借此契机,我用heap_sort来说明,我对于这个问题的解法。。我觉得应该把这个问题转移到句柄的设计而非是优先队列的设计。

如果student是非常大的数据类型,那么我在优先队列中处理的是指向student的句柄,如何让这个句柄工作,这个问题的解答和如何让student句柄在堆排序算法中工作是一样的。

我定义了指向student的句柄---迭代器,再次声明,迭代器设计的非常糟糕,只是为了测试正确性。。。。

struct student_iter
{
	student* p;
	student_iter():p(0){}

	student_iter(student* x):p(x){ }
	student_iter(const student_iter& x):p(x.p){ }
	student_iter& operator=(student_iter& x){p=(x.p);return *this;}
	bool operator<(const student_iter& r)const{return p->id<(r.p)->id;}
	bool operator<=(const student_iter& r)const {return p->id<=(r.p)->id;}
	bool operator==(const student_iter& r)const {return p->id==(r.p)->id;}
	bool operator>(const student_iter& r)const {return p->id>(r.p)->id;}
	int& operator*() const {return (*p).id;}

};

定义好这些,就可以工作了:

int main()
{
	student A[10];
	for(int i=0;i<10;++i){
		int x=rand()%124;
		A[i].id=x;
		A[i].name=x+'a';
	}
	student_iter B[10];
	for(int i=0;i<10;++i){
		B[i]=student_iter(&A[i]);
	}
	 for(student* it=A;it!=A+10;++it){
	   std::cout<<(*it).id<<" ";
	}
	 std::cout<<'\n';
    _heap_sort(B,B+10);
   for(student_iter* it=B;it!=B+10;++it){
	   std::cout<<*(*it)<<" ";
	}
	char c=getchar();
}


对于这个程序的扩展,例如如果排序有大量重复元素的序列,这样我们就可以按《算法导论》7-2设计算法了:

//当后面多一个bool型参数时,可以选择分三段式

template<typename RandomIterator,typename T>
iter_pair<RandomIterator> _partition(RandomIterator first,RandomIterator last,T pivot,bool)
{
	typedef iterator_traits<RandomIterator>::difference_type size_type;
	for(RandomIterator i=first;i!=last;++i){
		if(*i==pivot){RandomIterator tmp=last-1;iter_swap(i,tmp);break;}
	}
	RandomIterator i=first-1;
	RandomIterator r=last-1;
	size_type count=1;//等于pivot元素的个数,初始时为1  
	RandomIterator tmp=r;
	//[tmp,last)中的元素的值等于pivot
	for(RandomIterator j=first;j!=tmp;++j){
		if(*j<pivot){
			++i;
			iter_swap(i,j);
		}else if(*j==pivot){//如果两者相等,交换(r-count)和j,此时j的值未知,需要重新判断
			//是故--j,主元数目增加一
		    tmp=r-count;
			iter_swap(j,tmp);
			++count;
			--j;
		}
	}
	size_type count_=count;
	//此时[i+1,i+count+1)中的元素的值大于pivot,[i+count+1,last)中元素的值等于pivot
	if(ptrdiff_t(r-(i-count))<count){//此时等于pivot的元素多于大于pivot的元素
		count_=ptrdiff_t(r-(i-count));
	}
	//交换
	for(int j=0;j<count_;++j){ 
		RandomIterator L=i+1+j,R=r-j;
		iter_swap(L,R);
	}
	//此时[first,i]小于pivot,[i+1,i+count]等于pivot,[i+count+1,r]大于pivot
	return iter_pair<RandomIterator>(i+1,i+count);
}

然后再设计多一个bool类型参数的对应的sort函数进行宽展,这里就不写了。。。


2024.6.10丨基于DIAMOND与VFDB数据库的致病菌毒力因子高效注释指南 本文详细介绍了基于DIAMOND与VFDB数据库的致病菌毒力因子高效注释方法,涵盖工具安装、参数优化、数据库选择及实战案例解析。通过DIAMOND的快速比对和VFDB的全面毒力因子数据,显著提升微生物基因组研究效率,适用于临床检测、食品安全监测等多个场景。 阅读详情

相关推荐

高通9008模式隐藏技巧:不拆机用ADB命令+Diag协议进入EDL

本文深入解析高通EDL模式(紧急下载模式)的技术原理与实战应用,详细介绍了通过ADB命令和Diag协议无需拆机进入EDL的方法。涵盖硬件/软件触发方案、跨平台工具配置、Firehose协议解析及设备救砖流程,为开发者提供从基础到进阶的完整指南。

weixin_29191761的博客 1126

STL源码:算法sort

sort算法适用范围        sort算法接受两个RandomAccessIterators(随机存取迭代器),然后对区间内元素以渐增方式由小到大排序;另一个版本允许用户指定排序方式。        STL的所有关联容器都拥有自动排序功能(以为底层的RB-tree是自动排序的)因此,不需要使用sort算法。顺序容器中stack、queue、priority-queue都有特定的入口和

Sunshine的专栏 1503

汇川伺服Modbus-RTU通讯实战:从帧结构解析到西门子PLC配置

本文详细解析了汇川伺服与西门子PLC通过Modbus-RTU协议进行通讯的实战步骤,包括帧结构解析、硬件连接、参数设置及PLC程序配置。通过具体案例和常见问题排查指南,帮助工程师快速掌握工业自动化中的通讯技术,提升设备调试效率。

weixin_33670713的博客 453

算法分析-快速排序QUICK-SORT

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

weixin_33851177的博客 297

Matlab实战:用DQN算法让机器人学会自主避障(附完整代码)

本文详细介绍了如何使用Matlab实现DQN(深度Q网络)算法,使机器人在复杂环境中学会自主避障。通过环境建模、网络架构设计、奖励函数优化及实战调试,提供了完整的代码实现和训练策略,帮助开发者快速应用于机器人路径规划项目。

t8u9v0w1x的博客 232

PCB激光直接成像(LDI)设备技术解析与优化方案

激光直接成像(LDI)是PCB制造中的关键数字化工艺,通过激光束直接在基板上形成电路图案。其核心技术在于高精度光学系统与智能控制算法的结合,工作精度可达微米级。在HDI板、柔性电路等高端PCB制造中,LDI技术能显著提升线宽精度和层间对位准确性。当前行业面临材料适配性、热变形控制等挑战,动态能量补偿、多波长曝光等创新方案正在突破这些瓶颈。随着模块化设计、预测性维护等工程实践的普及,LDI设备综合效率持续提升,为5G、汽车电子等领域的精密电路生产提供关键技术支撑。

weixin_29168393的博客 392

快速排序(QuickSort)

最保姆级的快速排序讲解,文章用步步图解的方法去讲解快排三种单趟排序的实现,分析了快排的实际复杂度和稳定性,并提出了优化方法,分别实现了快速排序的递归版本和非递归版本。

Ye_Ming_OUC的博客 1641

【机器学习-09】特征工程

特征工程是机器学习模型构建的初步工作,但它的重要性却贯穿整个模型生命周期。在进行特征工程时,我们需要充分利用数据科学的知识和技巧,结合具体的应用场景和业务需求,来制定出最合适的特征提取和转换策略。只有这样,我们才能为机器学习模型提供最有价值的输入,从而使其发挥出最大的潜力。总之,特征工程是机器学习中的一项关键任务,它需要我们用心去探索、去实践、去创新。只有不断地优化和完善特征工程的过程,我们才能构建出更加准确、更加可靠的机器学习模型,为实际应用带来更大的价值。

qq_38614074的博客 2万+

算法导论第七章课后答案

7.1-1 参照图7-1的方法,说明PARTITION在数组A={13,9,9,5,12,8,7,4,21,2,6,11}上的操作过程。 A={13,19,9,5,12,8,7,4,21,2,6,11}   ={13,19,9,5,12,8,7,4,21,2,6,11}   ={13,19,9,5,12,8,7,4,21,2,6,11}   ={9,19,13,5,12,8,7,4,2

z84616995z的专栏 1万+

c#【保姆级教程】基于System.Text.Json 支持多态类型序列化! 手把手教你实现一个通用的 PolymorphicJsonConverter!

我们需要自己实现一个继承自的转换器,在序列化时记录具体类型,在反序列化时根据类型标识还原成正确的子类对象。public abstract class WorkStepBase { /* 抽象方法等 */ }public class Person : WorkStepBase { /* 实现 */ }public class Product : WorkStepBase { /* 实现 */ }特性说明✅ 自动发现子类无需手动维护类型列表,自动扫描程序集✅ 类名映射。

一个编程的同学 425

Codex 100个真实案例 - 用AI绘制CAD机械图纸(工程师看了直呼内行)

本案例将展示如何用 Codex 生成 Python 脚本,通过 `ezdxf` 库绘制标准 DXF 格式的 CAD 机械图纸。我们会从零开始,逐步实现直线、圆、圆弧、标注等基本图形元素,最终绘制出一张包含主视图、俯视图、尺寸标注、标题栏和技术要求的完整法兰盘零件图。还会演示参数化批量生成不同规格零件图和自动 BOM 物料清单,生成的 DXF 文件可直接在 AutoCAD、FreeCAD 中打开。全程用自然语言驱动 Codex,工程师看完直接上手!

yueyeguzhuo的专栏 2075

快速排序算法学习笔记

快速排序是一种比较实用的排序算法,平均时间复杂度为O(nlogn),最坏情况为O(n*n),最好情况也是O(nlogn)。该算法基于分治处理思想,在数列中选取一个主元,根据这个主元把整个数列分为两部分:一部分比这个主元小,一部分比这个主元大。然后对这两部分分别再选取主元划分,以此递归下去。 针对一个A[p....r]的数组,其执行步骤可以描述为: 1、分组:A[p..r]被划...

aqns80581的博客 144

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

算法导论 第十六章 贪心算法

def:贪心算法是一种以局部最优最优选择以期求得全局最优解得算法。 16.1活动选择问题 求一个活动选择问题的域中求最大兼容活动子集。 活动选择问题具有最优子结构:解中若包含活动ak,s.t. S[...k]和S[k+1...]都为最大兼容活动子集 若用c[i,j]来表示S[i...j]的大小则有递归公式:

pokeyode的专栏 2826

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

第十六周项目2-大数据集上排序算法性能的体验

问题及代码: 设计一个函数,产生一个至少5万条记录的数据集合。在同一数据集上,用直接插入排序、冒泡排序、快速排序、直接选择排序、堆排序、归并排序、基数排序等算法进行排序,记录所需要的时间,经过对比,得到对复杂度不同的各种算法在运行时间方面的感性认识。 主函数main.cpp代码: #include #include #include #include #include "so

wx6226的博客 580

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

第十六周 项目一 验证快速排序算法

#ifndef BTREE_H_INCLUDED #define BTREE_H_INCLUDED /* *烟台大学计控学院 *作 者:林颖 *完成日期:2016年12月16日 *问题描述:用序列{57, 40, 38, 11, 13, 34, 48, 75, 6, 19, 9, 7}作为测试数据,验证快速排序 */ #endif // BTREE_

linying3121的博客 800

第十六周项目二~~大数据集上排序算法性能的体验

#include #include #include #include #include "sort.h" void GetLargeData(RecType *&R, int n) { srand(time(0)); R=(RecType*)malloc(sizeof(RecType)*n); for(int i=0; i<n; i++) R[i

lihao66886的博客 667

第十六周上机实践项目2 - 大数据集上排序算法性能的体验

问题及代码: 设计一个函数,产生一个至少5万条记录的数据集合。在同一数据集上,用直接插入排序、冒泡排序、快速排序、直接选择排序、堆排序、归并排序、基数排序等算法进行排序,记录所需要的时间,经过对比,得到对复杂度不同的各种算法在运行时间方面的感性认识。 提示1:这一项目需要整合多种排序算法,可以考虑先建设排序算法库,作为我们这门课算法库的收官之作; 提示2:本项目旨在获得对于复杂度不同算

yxxhilda的博客 497

第十六周项目5—— 大数据集上排序算法性能的体验

/*    * Copyright (c)2016,烟台大学计算机与控制工程学院    * All rights reserved.    * 文件名称:wu.cpp    * 作    者:武昊    * 完成日期:2016年12月15日    * 版 本 号:v1.0     *问题描述:采用归并排序、快速排序等高效算法进行排序,当数据元素较少时(如n≤64),经常直接使用直接插

最好你搬过来 477

第十六周 项目1 验证算法 快速排序

快速排序: 1).以第一个元素为基准 #include #define MaxSize 20 typedef int KeyType; //定义关键字类型 typedef char InfoType[10]; typedef struct //记录类型 { KeyType key; //关键字项 InfoType data;

balabala0322的博客 442

第十六周项目一验证算法(2)快速排序

问题及代码 /* 02.* Copyright (c)2016,烟台大学计算机与控制工程学院 03.* All rights reserved. 04.* 文件名称:项目1cbp 05.* 作 者:陈迪 06.* 完成日期:2016年12月11日 07.* 版 本 号:v1.0 08. 09.* 问题描述:验证快速排序 10. 11

chendi19的博客 413

第十六周项目1-验证算法(4)快速排序

/* * Copyright (c) 2016, 烟台大学计算机与控制工程学院 * All rights reserved。 * 文件名称 :1.cpp * 作 者 :孟令群 * 完成日期 :2016年 12月15日 * 版 本 号 :v1.0 * 问题描述 : * 输出描述 : */ //1.以第1个元素作为基准 #include #defi

mlq9527的博客 425

第十六周项目1-(2)快速排序

问题及代码: /*    * Copyright (c)2016,烟台大学计算机与控制工程学院    * All rights reserved.    * 文件名称:项目1.cpp    * 作    者:董雪   * 完成日期:2016年12月14日    * 版 本 号:v1.0     *问题描述:验证快速排序,完成测试。  *输入描述:无    *程序输出

vip____的博客 395

网易校招机器学习算法笔试题全解析:从KMP到模型评估与特征工程

机器学习算法岗笔试中,经典数据结构与统计学习理论始终是考察核心。KMP算法作为字符串匹配的经典方法,其next数组推导考验候选人对算法本质的理解;排序算法与并查集则检验基础编码功底。模型评估指标如AUC、F1在类别不平衡场景下的选择,常成为区分原理型选手的关键。特征工程与过拟合控制方法,则直接反映工程落地能力。无论是准备校招笔试,还是系统梳理机器学习知识体系,理解这些高频考点的原理与实际应用都至关重要。网易历年笔试卷正是这些核心知识的典型样本,值得深入拆解。

weixin_34295316的博客 352

数据结构与算法——快速排序

每次看大牛的博客都有一种感想:啥时候我也能成为大牛。。。。。插入一个:上两篇文章分别介绍了选择排序和冒泡排序,其思想都差不多,只是选择排序是比较完所有数据后确定最小的数再交换,而冒泡排序是比较相邻的两个数如果顺序不对就要交换:两者的时间复杂度都是o(n2) 下面是我在数组里面存在相同数据的结果:选择排序和冒泡排序的结果 选择排序的结果: 第1次排序结果:1 33 12 45 23 68 33

623

算法导论 — 思考题7-5 三数取中划分

(三数取中划分)一种改进RANDOMIZED-QUICKSORT的方法是在划分时,要从子数组中更细致地选择作为主元的元素(而不是简单地随机选择)。常用的做法是三数取中法:从子数组中随机选出三个元素,取其中位数作为主元(见练习7.4-6)。对于这个问题的分析,我们不妨假设数组A[1..n]A[1..n]A[1..n]的元素是互异的且有n≥3n ≥ 3n≥3。我们用A’[1..n]A’[1..n]A’...

yangtzhou的专栏 1683

QuickSort快速排序,详细说明过程及展示

#include #include using namespace std; void show(int*a) //交换数据 { for(int i=0;i<8;i++) cout<<setw(3)<<a[i]; cout<<endl; } void swap(int* a,int start,int second) { int temp=*(a+start); *(a+star

白话魔法师 1295
上一篇: 数据结构篇deque
下一篇: 算法导论第13章-红黑树
wangyanphp
博客等级 码龄14年 90粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值