几种排序总结(一)

1.交换排序的基本思想是:两两比较待排序记录的关键字,若反序即进行交换,直到没有反序的记录为止。

static void swap(int *p,int *s )
{
	int tmp;
	tmp=*p;
	*p=*s;
	*s=tmp;
}

void exchange_sort(int *arr,int len)
{
	for (int i=0;i<len-1;i++)
	{
		for (int j=i+1;j<len;j++)
		{
			if (arr[i]>arr[j])
			{
				swap(&arr[i],&arr[j]);
			}
		}
	}
}

应用交换排序基本思想的主要排序方法有:冒泡排序(Bubble sort)和快速排序(Quick sort)。


</pre><pre name="code" class="cpp" style="color: rgb(85, 85, 85);">//冒泡排序
void bubble_sort(int *arr,int len)
{
	for (int i=0;i<len-1;i++)
	{
		for (int j=0;j<len-i-1;j++)
		{
			if (arr[j]>arr[j+1])
			{
				swap(&arr[j],&arr[j+1]);
			}
		}
	}
}
//改进版冒泡排序,当一趟比较后没有交换(flag=false)即已经有序,不再进行,直接跳出
void bubble_sort_ex(int *arr,int len)
{
	bool flag=true;
	for (int i=0;i<len-1 && flag;i++)
	{
		flag=false;
		for (int j=0;j<len-i-1;j++)
		{
			if (arr[j]>arr[j+1])
			{
				swap(&arr[j],&arr[j+1]);
				flag=true;
			}
		}
	}
}

快速排序是对冒泡排序的一种改进,基本思想:通过一趟排序将待排记录分割为独立的两部分,其中一部分记录关键字均比另一部分记录的关键字小,则可对这两部分记录继续进行排序,已达到整个有序。

//快速排序
static int partition(int *arr,int left,int right)
{
	int key=arr[left];
	while (left<right)
	{
		while (left<right && arr[right]>=key)
		{
			right--;
		}
		arr[left]=arr[right];

		while (left<right && arr[left]<=key)
		{
			left++;
		}
		arr[right]=arr[left];
	}

	arr[left]=key;
    return left;
}

static void quick(int *arr,int left,int right)
{
	if (left<right)
	{
		int pivo=partition(arr,left,right);
		quick(arr,left,pivo-1);
		quick(arr,pivo+1,right);
	}
}

void quick_sort(int *arr,int len)
{
	quick(arr,0,len-1);
}


2.选择排序的基本思想是:每一趟在n-i-1个记录中选取关键字最小的记录作为有序序列中第i个记录。

最简单的是简单选择排序,一趟简单的选择排序的操作为:通过n-i次关键字间的比较,从n-i-1个记录中选择出关键字最小的记录,并和第i个记录交换。

通俗地讲就是,对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置,接着第二次比较,前面"后一个元素"现变成了"前一个元素",继续跟他的"后一个元素"进行比较如果后面的元素比他要小则用变量k记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。

//选择排序
void select_sort(int *arr,int len)
{
	int min=arr[0];
	int min_index=0;
	int i;
	int j;
	for (i=0;i<len-1;i++)
	{
		min=arr[i];
		min_index=i;

		for (j=i+1;j<len;j++)
		{
			if (min>arr[j])
			{
				min=arr[j];
				min_index=j;
			}
		}

		if(i!=min_index)//下标并没有改变
		{
			swap(&arr[i],&arr[min_index]);
		}
	}
}
选择排序的主要操作是进行关键字间的比较,因此,改进简单选择排序应从减少“比较”出发。基于选择排序的思想,出现了堆排序

堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

为使记录序列按关键词非递减有序排列,则在堆排序的算法中先建一个“大根堆:,即先选得一个关键字为最大的记录并与序列最后一个记录交换,然后对序列中前n-1个记录进行筛选,重新调整为大根堆,如此反复直至排序结束。

//堆排序
static void heap_adjust(int *arr,int start,int len)
{
	int tmp=arr[start];
	int i;
	while ((i=2*start+1)<len)
	{
		if (i+1<len && arr[i]<arr[i+1])
		{
			i++;
		}

		if (tmp>=arr[i])
		{
			break;
		}
		arr[start]=arr[i];
		start=i;
	}

	arr[start]=tmp;
}

void heap_sort(int *arr,int len)
{
	for (int start=len/2-1;start>=0;start--)
	{
		heap_adjust(arr,start,len);
	}

	for (int i=len;i>1;i--)
	{
		swap(&arr[0],&arr[i-1]);
		heap_adjust(arr,0,i-1);
	}

}


3.插入排序的基本思想是:每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
//插入排序
//void insert_sort(int *arr,int len)
//{
//	int tmp;
//	int j;
//
//	for (int i=1;i<len;i++)
//	{
//		tmp=arr[i];
//		for (j=0;j<i;j++)
//		{
//			if (arr[j]>=tmp)
//			{
//				break;
//			}
//		}
//
//		for (int k=i-1;k>=j;k--)
//		{
//			arr[k+1]=arr[k];
//		}
//
//		arr[j]=tmp;
//	}
//}

void insert_sort(int *arr,int len)
{
	int tmp;
	int j;

	for (int i=1;i<len;i++)
	{
		tmp=arr[i];
		for (j=i-1;j>=0;j--)
		{
			if (arr[j]<=tmp)
			{
				break;
			}
			arr[j+1]=arr[j];
		}

		arr[j+1]=tmp;
	}
}
注释掉的代码符合人们的思维逻辑,但效率呢?从注释掉的代码到未注释的代码,想必你已经看出哪些地方进行了改进,未注释的代码才是真正的直接插入排序。当然还有其他的插入排序,这里再展示一种:

void half_insert_sort(int *arr,int len)
{
	int tmp;
	int j;
	int left;
	int right;
	int mid;

	for (int i=1;i<len;i++)
	{
		tmp=arr[i];
		left=0;
		right=i-1;

		while (left<=right)
		{
			//mid=(left+right)/2;
			mid=(right-left+1)/2+left;
			if (tmp<arr[mid])
			{
				right=mid-1;
			}
			else
			{
				left=mid+1;
			}
		}

		for (j=i-1;j>=right+1;j--)
		{
			arr[j+1]=arr[j];
		}

		arr[j+1]=tmp;
	}
}
希尔排序又称“缩小增量排序”,是基于插入排序的思想,但在时间效率上较前几种排序有较大改进。它的基本思想是:先将整个待排记录序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

//希尔排序
static void shell(int *arr,int len,int gap)
{
	int tmp;
	int i;
	int j;

	for (i=gap;i<len;i++)
	{
		tmp=arr[i];
		for (j=i-gap;j>=0;j-=gap)
		{
			if (arr[j]<tmp)
			{
				break;
			}
			arr[j+gap]=arr[j];
		}

		arr[j+gap]=tmp;
	}
}

void shell_sort(int *arr,int len)
{
	//for (int gap=len/2;gap>0;gap/=2)
	//{
	//	shell(arr,len,gap);
	//}

	int gap_index[]={701,301,132,57,23,10,4,1};//特殊序列
	int gap_len=sizeof(gap_index)/sizeof(gap_index[0]);

	int i;
	for (i=0;i<len;i++)
	{
		if (gap_index[i]<len)
		{
			break;
		}
		i++;	
	}

	for (i;i<gap_len;i++)
	{
		shell(arr,len,gap_index[i]);
	}
}
那么,分几组对希尔排序的效率有没有影响呢?答案是肯定的,关于如何选择增量,希尔排序效率更高,可以作为思考。可在维基百科上查看有关希尔排序怎样分组。


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

//归并排序

static void merge(int *arr,int len,int gap)
{
	int *buff=(int *)malloc(sizeof(int)*len);
	assert(buff!=NULL);
	int k=0;
	
	int low1=0;
	int high1=low1+gap-1;
	int low2=high1+1;
	int high2=low2+gap-1<len ? low2+gap-1:len-1;//如果越界,进行拉回

	while (low2<len)//归并段2只要有,就需要继续归并
	{
		while (low1<=high1 && low2<=high2)
		{
			if (arr[low1]<=arr[low2])
			{
				buff[k++]=arr[low1++];
			} 
			else
			{
				buff[k++]=arr[low2++];
			}
		}	
		while (low1<=high1)
		{
			buff[k++]=arr[low1++];
		}
		while (low2<=high2)
		{
			buff[k++]=arr[low2++];
		}

		low1=high2+1;
		high1=low1+gap-1;
		low2=high1+1;
		high2=low2+gap-1<len ? low2+gap-1:len-1;//如果越界,进行拉回
	}

	while (low1<len)//没有归并段2,但有归并段1  
	{
		buff[k++]=arr[low1++];
	}

	for (int i=0;i<len;i++)
	{
		arr[i]=buff[i];
	}

	free(buff);
}

static void merge_ex(int *arr,int len,int gap)
{
	int *buff=(int *)malloc(sizeof(int)*gap*2);
	assert(buff!=NULL);
	int *p=buff;
	int m=0;

	int low1=0;
	int high1=low1+gap-1;
	int low2=high1+1;
	int high2=low2+gap-1<len ? low2+gap-1:len-1;

	while (low1<len)
	{
		if (low2<len)
		{
			while (low1<=high1 && low2<=high2)
			{
				if (arr[low1]<=arr[low2])
				{
					*buff=arr[low1++];
					buff++;
				} 
				else
				{
					*buff=arr[low2++];
					buff++;
				}
			}	
		}
		while (low1<=high1)
		{
			*buff=arr[low1++];
			buff++;
		}
		while (low2<=high2)
		{
			*buff=arr[low2++];
			buff++;
		}

		buff=p;
		for (int i=0;i<2*gap && m<len;i++)
		{
			arr[m]=*buff;
			buff++;
			m++;
		}

		buff=p;
		low1=high2+1;
		high1=low1+gap-1<len ? low1+gap-1:len-1;
		low2=high1+1;
		high2=low2+gap-1<len ? low2+gap-1:len-1;
	}
	free(buff);
}


void merge_sort(int *arr,int len)
{
	for (int gap=1;gap<len;gap*=2)
	{
		//merge(arr,len,gap);
		merge_ex(arr,len,gap);
		//show(arr,len);
	}
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章