数据结构与算法中排序详解!

数据结构与算法中排序详解!!!

本文是总结中国大学mooc上的电子科技大学的数据结构和算法课程,未完待续!
排序的基本概念(稳定排序与不稳定排序)

**稳定的排序方法:**对于任意的数据元素序列,若排序前后所有相同关键字的相对位置都不变。

**不稳定的排序方法:**若存在一组数据序列,在排序前后,相同关键字的相对位置发生了变化。

举个栗子~

比如有一组序列:4,3,3,2

排序后变成了:2,3,3,4。这就是不稳定的排序。

我们先来看简单的排序方法:

插入排序:

简单插入排序:

思想:将无序子序列中的一个或几个记录“插入”到有序子序列中,从而增加有序子序列的长度。

就是先从无序子序列中顺次取一个数,放入有序子序列中并排序。

在这里插入图片描述
步骤:定位(查找要插入的数的位置)->挤空(所有记录向后移一位)->插入

由于定位方法的不同可以将插入排序分类:

1.直接插入排序(基于顺序查找定位)

2.折半插入排序(基于折半查找定位)

3.希尔排序(基于逐趟缩小增量)

下面我们分别介绍这三种排序方式:

直接插入排序:整个排序过程为n-1趟插入,先将序列中第一个记录看成是一个有序子序列,然后从第二个记录开始,逐个进行插入,直至整个序列有序。

这个比较简单,就不图示了,下面给出算法实现:

#include <stdio.h> 
#include <string.h>
typedef struct{
	int key;
	float info;
}JD;
//直接插入排序
//对长度为n的序列排序 
void straisort(JD r[],int n) 
{
	int i,j;
	for(i=2;i<=n;i++){
		r[0]=r[i];
		j=i-1;
		while(r[0].key<r[j].key)
		{
			r[j+1]=r[j];
			j--;
		}
		r[j+1]=r[0];
	}
} 

选择排序:

简单选择排序:

思想:从无序子序列中“选择”关键字最大或最小的记录,并将它加入到有序子序列中,以此方法增加记录中有序子序列的长度。

相比于简单插入排序,增加的步骤就是在无序序列中要进行选择一次。

排序过程:

首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将它与第一个记录交换。

再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换

重复上述操作,共进行n-1趟排序。

void smp_selesort(JD r[],int n){
	int i,j,k;
	JD x;
	for(i=1;i<n;i++){
		k=i;
		for(j=i+1;j<=n;j++)
		if (r[j].key<r[k].key)
			k=j;
		if(i!=k){
			x=r[i];
			r[i]=r[k];
			r[k]=x;
		}
	}
}

交换排序:

通过“交换”无序序列中的记录从而得到其中关键字最大/最小的记录,并将它加入到有序子序列中,以此方法增加有序子序列长度。

  • 冒泡排序
  • 快速排序

首先说冒泡排序:

排序过程:

1.将第一个记录的关键字与第二个记录的关键字进行比较,若为逆序r[1].key>r[2].key,则交换;然后比较第二个记录和第三个记录,依次类推。直至第n-1个记录和第n个记录比较为止,第一趟冒泡排序,结果关键字最大的记录被安置在最后一个记录上。

2.对前n-1个记录进行第二次冒泡排序,结果使关键字次大的记录被安置在第n-1个记录位置。

3.重复上述过程,直到“在一趟排序过程中没有进行过交换记录的操作”为止

//冒泡排序 
void bubble_sort(JD r[],int n)
{
	//flag表示本趟有无交换 
	int m,i,j,flag=1;
	JD X;
	m=n;
	while ((m>1)&&(flag==1))//趟数 
	{
		flag=0;
		for(j=1;j<m;j++)
		if (r[j].key>r[j+1].key)
		{
			flag=1;
			x=r[j];
			r[j]=r[j+1];
			r[j+1]=x;
		}
		m--;
	}  
}

一般情况下,每经过一趟“冒泡”,“m-1”,但并不是每趟如此。

所以对冒泡排序进行改进:

//改进冒泡排序,m
void BubbleSort(Elem R[],int n)
{
	int m;
	m=n;
	while(m>1){
		lastExchangeIndex=1;
		for(j=1;j<m;j++)
		if(R[j].key>R[j+1].key){
			swap(R[j],R[j+1]);
			lastExchangeIndex=j;//记下进行交换的记录位置 
		}
		m=lastExchangeIndex;//本趟最后一次交换位置 
	}
	
 } 

快速排序:

实际使用中已知的最快的排序方法

重点在于选择枢纽pivot,使得A1和A2子集合数据相当。

我们采用三种取中法,Pivot=median(left,center,right)

以选择第一个关键字为枢纽为例:

排序过程:

1.对r[s…t]中记录进行一趟快速排序,附设两个指针i和j,设划分元记录rp=r[s],x=rp.key

2.初始时令i=s,j=t

3.首先从j所指位置向前搜索第一个关键字小于x的记录,并和rp交换。

再从i所指的位置起向后搜索,找到第一个关键字大于x的记录,和rp交换。

4.重复上述两步,直到i==j为止。

5.再分别对两个子序列进行快速排序,直到每个子序列只含有一个记录为止。

void qksort(JD r[],int t,int w)
{
	//t=low,w=high
	int i,j,k;
	JD x;
	if (t>=w) return;
	i=t,j=w,x=r[i].key;
	while(i<j)
	{
		while((i<j)&&(r[j].key>=x.key))
			j--;//枢纽后面的值大于枢纽
		//当不满足的时候,与枢纽交换
		if(i<j){
			r[i]=r[j];
			i++;
		} 
		//枢纽前面的值小于枢纽
		while((i<j)&&(r[i].key<=x.key)) 
			i++;
		if(i<j){
			r[j]=r[i];
			j--;
		}
		r[i].key=x;
		qksort(r,t,j-1);
		qksort(r,j+1,w);
	}
}

猜你喜欢

转载自blog.csdn.net/nicezheng_1995/article/details/82886077