数据结构知识复习1——排序

一些函数准备:数组元素交换函数、数组打印函数、获取数组长度函数。

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


void exchange(int *list,int i,int j)
{
	int temp=0;
	temp=list[i];
	list[i]=list[j];
	list[j]=temp;
}

template <class T>
int length(T& list)
{
	int len=(int)sizeof(list)/sizeof(list[0]);//使用sizeof,不能传递指针
	return len;
}

void print(int *list,int len)
{
	for(int i=0;i<=len-1;i++)
	{
		cout<<list[i]<<" ";
	}
	cout<<endl;
}

交换类排序(冒泡、快排)

冒泡(经典):两两比较相邻记录,如果反序则交换,直到整个序列没有反序;

void bubble_sort(int *list,int len)
{
	int i,j;
	for(i=1;i<=len-1;i++)
		for(j=0;j<len-i;j++)
		{
			if(list[j]>list[j+1])
			{
				exchange(list,j,j+1);
			}
		}
}

第i轮,倒数第i个位置上得到正确的元素。

冒泡(改进):立一个flag,监控是否有元素交换,若有,则继续循环,否则退出循环;

//改进的冒泡排序
void bubble_sort2(int *list,int len)
{
	int flag=true;
	int i=1,j=0;
	while((i<=len-1) && flag)
	{
		flag=false;
		for(j=0;j<len-i;j++)
		{
			if(list[j]>list[j+1])
			{
				exchange(list,j,j+1);
				flag=true;
			}
		}
		i++;
	}
}

快排(重要):首先确定一个枢纽值,通过一趟快排将元素分割为两个部分,左边部分的元素都比枢纽值小,右边部分的值都比枢纽值大。实现的关键就是用两个指针low,high;low从左往右寻找比枢纽大的值,交换到枢纽右边;high从右往左寻找比枢纽小的值,交换到枢纽左边。当low==high时,说明找到了枢纽值的正确位置,将枢纽值与low位置处的值交换。然后再将分割的两个部分分别递归调用该方法,直到整个序列有序。参考:https://blog.csdn.net/adusts/article/details/80882649

void quick_sort(int *list, int left, int right)
{
	int i,j,temp;
	temp=list[left];
	i=left; j=right;
	if(left>right)
		return;
	while(i!=j)
	{
		while(list[j]>=temp && j>i)
			j--;
		while(list[i]<=temp && i<j)
			i++;
		if(i<j)
		{
			exchange(list,i,j);
		}
	}
	list[left]=list[i];
	list[i]=temp;
	print(list,right+1);
	quick_sort(list,left,i-1);
	quick_sort(list,i+1,right);
}

选择类排序(简单选择排序、堆排序)

简单选择排序:对于当前的位置i,经过n-i次比较,从n-i+1个数据中选出最小关键字,并与i位置的值进行交换;选择排序能够保证位置i前面的数据是顺序排列的。

void select_sort(int *list,int len)
{
	int i,j,min;
	for(i=0;i<len-1;i++)
	{	min=i;
		for(j=i+1;j<len;j++)
			if(list[j]<list[min])
			{
				min=j;
			}
		exchange(list,i,min);
	}
}

堆排序:堆是一种完全二叉树,有大顶堆和小顶堆。大顶堆的所有节点元素都比其左右孩子节点元素值大,小顶堆反之。将序列构成一个大顶堆,然后将堆顶元素与叶子节点元素交换,此时将剩余的n-1个元素重新构造成一个堆,反复执行就可以得到一个有序序列;参考:https://www.cnblogs.com/wanglei5205/p/8733524.html

//大顶堆调整
void heap_adjust(int *list,int len,int index)
{
	int left = 2*index+1;
	int right = 2*index+2;

	int maxIdx = index;
	if(left<len && list[left]>list[maxIdx]) maxIdx = left;
    if(right<len && list[right]>list[maxIdx]) maxIdx = right;

	if(maxIdx != index)
	{
		exchange(list,maxIdx,index);
		print(list,len);
		cout<<maxIdx<<"  "<<index<<endl;
		heap_adjust(list,len,maxIdx);

	}	
	
}

//交换元素并进行堆调整
void heap_sort(int *list,int len)
{
	for(int i=len/2-1;i>=0;i--)   //最后一个非叶子节点的下标为len/2-1
	{
		heap_adjust(list,len,i);
	}

	for(i=len-1;i>=1;i--)
	{
		exchange(list,0,i);
		heap_adjust(list,i,0);
	}

}

插入类排序(直接插入排序、shell排序)

直接插入排序:将一个待排元素插入到它前面已经排好的序列当中,依次比较它与前面的元素,若比待排元素大,就将这个元素后移,直到找到一个合适的位置将待排元素插入序列。(类似于扑克牌)

void insert_sort(int *list,int len)
{
	int i,j,temp;
	for(i=1;i<=len-1;i++)
	{
		temp=list[i];
		for(j=i-1;j>=0;j--)
		{
			if(list[j]>temp)
				list[j+1]=list[j];
			else
			{
			 break;
			}
		}
		list[j+1]=temp;
	}
}

shell排序:也叫增量减小排序,在直接插入排序基础上增加了“增量”。设置一个增量,根据增量将整个待排序列分割成为若干子序列,对每一个子序列分别进行直接插入排序。当增量减小为1时,对全体记录进行一次直接插入排序。时间节省在:对子序列排序,因为子序列元素少,所以排序快;最后一轮对所有数据排序,但此时大部分数据已经有序,所以可以节省很多时间。

void shell_sort(int *list,int len)
{
	int inc=len;
	int temp=0;
	int j;
	do{
		inc = inc/3+1;
		for (int i=inc;i<len;i++)
		{
			temp=list[i];
			for(j=i-inc;j>=0;j-=inc)
			{
				if(list[j]>list[i])
					list[j+inc]=list[j];
				else
					break;
			}
			list[j+inc]=temp;
		}
	}while(inc>1);
}

归并排序

归并排序:分治法排序。先将n个记录看成是n个有序子序列,每个序列中只有1个元素,然后两两归并,得到n/2个有序子序列,然后再两两归并,直到得到一个长度为n的子序列。归并排序每次都是将有序子序列合并在一起。

参考:https://www.cnblogs.com/WuNaiHuaLuo/p/5446449.html  

https://www.cnblogs.com/eudiwffe/p/6254394.html

//归并排序
void merge_core(int *list,int begin, int mid, int end)
{
	int i=begin,j=mid,k=0;
	int *tmp = (int*)malloc(sizeof(int)*(end-begin));
	for(;i<mid && j<end; )
		tmp[k++]=(list[i]<list[j]?list[i++]:list[j++]);
	for(;i<mid;)
		tmp[k++]=list[i++];
	for(;j<end;)
		tmp[k++]=list[j++];
	for(i=begin,k=0;i<end;)
		list[i++]=tmp[k++];
	free(tmp);
}

void merge_sort(int *list,int begin,int end)
{
	if(end-begin < 2) return;
	int mid = (begin+end)>>1;
	
	merge_sort(list,begin,mid);
	merge_sort(list,mid,end);
	merge_core(list,begin, mid, end);

}

main函数:

int main()
{
	time_t c_start,c_end;
	int arr[] = {7,33,5,22,8,9};
	//int arr[] = {0,1,2,3,4,5,6,7};
	int len=length(arr);
	int choose;
	cout<<"************original arr******************"<<endl;
	print(arr,len);
	cout<<"input the operation"<<endl;
	cin>>choose;
	switch(choose)
	{
	
	case 1:
		c_start=clock();
		bubble_sort(arr,len);
		c_end=clock();
		cout<<"************bubble_sort******************"<<endl;
		print(arr,len);
		cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
		break;
	case 2:
		c_start=clock();
		bubble_sort2(arr,len);
		c_end=clock();
		cout<<"************bubble_sort2******************"<<endl;
		print(arr,len);
		cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
		break;
	case 3:
		c_start=clock();
		select_sort(arr,len);
		c_end=clock();
		cout<<"************select_sort******************"<<endl;
		print(arr,len);
		cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
		break;
	case 4:
		c_start=clock();
		insert_sort(arr,len);
		c_end=clock();
		cout<<"************insert_sort******************"<<endl;
		print(arr,len);
		cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
		break;
	case 5:
		c_start=clock();
		shell_sort(arr,len);
		c_end=clock();
		cout<<"************shell_sort******************"<<endl;
		print(arr,len);
		cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
		break;
	case 6:
		heap_sort(arr,len); 
		cout<<"************heap_sort******************"<<endl;
		print(arr,len);
	case 7:
		quick_sort(arr,0,len-1);
		cout<<"************quick_sort******************"<<endl;
		print(arr,len);
	case 8:
		merge_sort(arr,0,len);
		cout<<"************merge_sort******************"<<endl;
		print(arr,len);
	}
	return 0;
}

各种排序时间/空间复杂度分析:

 

参考:https://www.cnblogs.com/daimingming/p/3219744.html

图解:https://blog.csdn.net/opooc/article/details/80994353

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值