数据结构——排序(C语言)

目录

插入排序

一.直接插入排序

1.如何构建初始的有序序列

2.如何查找待插入记录的插入位置?

3.r[0]有两个作用:

直接插入排序代码:

二.希尔排序

1.应如何分割待排序记录?

2.子序列内如何进行直接插入排序?

希尔排序代码:

交换排序

一.起泡排序

1.如何记载一趟排序过程中交换的多个记录?

2.如何确定起泡排序的范围?

3.如何判别起泡排序的结束?

起泡排序代码:

二.快速排序

1.如何选择轴值?

2.如何实现一次划分

算法描述:

3.如何处理分割得到的两个待排序子序列?

4.如何判别快速排序的结束?

快速排序代码如下:

选择排序

一.简单选择排序

1.如何在无序区中选出关键字最小的记录?

2.如何确定最小记录的最终位置?

 简单选择排序代码:

堆排序

1.堆的定义

 归并排序

二路归并排序


插入排序

一.直接插入排序

1.如何构建初始的有序序列

将第1个记录看成是初始有序表,然后从第2个记录起依次插入到这个有序表中,直到将第n个记录插入。

2.如何查找待插入记录的插入位置?

在i-1个记录的有序区r[1] ~ r[i-1]中插入记录r[i],首先顺序查找r[i]的正确插入位置,然后将r[i]插入到相应位置。

3.r[0]有两个作用:

1. 进入循环之前暂存了r[i]的值,使得不致于因记录的后移而丢失r[i]的内容;
2. 在查找插入位置的循环中充当哨兵。

直接插入排序代码:

void insert(int r[],int n)//直接插入排序
{
	int i,j;
	for(i=2;i<n;i++)
	{
		r[0]=r[i];j=i-1;
		while(r[i]<r[j])
		{
			r[j+1]=r[i];
			j--;
		}
		r[j+1]=r[0];
	}
} 

二.希尔排序

1.应如何分割待排序记录?

将相隔某个“增量”的记录组成一个子序列。
增量应如何取?
希尔最早提出的方法是d1=n/2,di+1=di/2。

2.子序列内如何进行直接插入排序?

在插入记录r[i]时,自r[i-d]起往前跳跃式(跳跃幅度为d)搜索待插入位置,并且r[0]只是暂存单元,不是哨兵。当搜索位置<0,表示插入位置已找到。
在搜索过程中,记录后移也是跳跃d个位置。
在整个序列中,前d个记录分别是d个子序列中的第一个记录,所以从第d+1个记录开始进行插入。

希尔排序代码:

void shellsort(int r[],int n)
{
	int d=0;
	for(d=n/2;d>=1;d=d/2)
	{
		for(i=d+1;i<=n;i++)
		{
			r[0]=r[i];
			j=i-d;
			while(j>0&&r[0]<r[j])
			{
				r[j+d]=r[j];
				j=j-d;
			}
			r[j+d]=r[0];
		}
	}
}

交换排序

一.起泡排序

1.如何记载一趟排序过程中交换的多个记录?

设变量exchange记载记录交换的位置,则一趟排序后,exchange记载的一定是这一趟排序中记录的最后一次交换的位置,且从此位置以后的所有记录均已经有序。

2.如何确定起泡排序的范围?

设bound位置的记录是无序区的最后一个记录,则每趟起泡排序的范围是r[1] ~ r[bound]。
在一趟排序后,从exchange位置之后的记录一定是有序的,所以bound=exchange。

3.如何判别起泡排序的结束?

在每一趟起泡排序之前,令exchange的初值为0,在以后的排序过程中,只要有记录交换,exchange的值就会大于0。这样,在一趟比较完毕,就可以通过exchange的值是否为0来判别是否有记录交换,从而判别整个起泡排序的结束。

起泡排序代码:

void BubbleSort(int r[ ], int n)
{	
    exchange=n; 	
    while (exchange) 
    {
        bound=exchange; 
        exchange=0;  
        for (j=1; j<bound; j++)
            if (r[j]>r[j+1]) {
                r[j]←→r[j+1];
	      exchange=j; 
            }
     }
 }

二.快速排序

1.如何选择轴值?

选择轴值的方法:
1.使用第一个记录的关键字;
2.选取序列中间记录的关键字;
3.比较序列中第一个记录、最后一个记录和中间记录的关键字,取关键字居中的作为轴值并调换到第一个记录的位置;
4.随机选取轴值。

选取不同轴值的后果:
决定两个子序列的长度,子序列的长度最好相等。

2.如何实现一次划分

设待划分的序列是r[s] ~ r[t],设参数i,j分别指向子序列左、右两端的下标s和t,令r[s]为轴值,
(1)j从后向前扫描,直到r[j]<r[i],将r[j]移动到r[i]的位置,使关键字小(同轴值相比)的记录移动到前面去;
(2)i从前向后扫描,直到r[i]>r[j],将r[i]移动到r[j]的位置,使关键字大(同轴值比较)的记录移动到后面去;
(3)重复上述过程,直到i=j。

算法描述:

int Partition(int r[ ], int first, int end)
{	
    i=first; j=end;         //初始化
    while (i<j)	
    {  
       while (i<j && r[i]<= r[j]) j--;  //右侧扫描
       if (i<j) { 
          r[i]←→r[j];   i++;  //将较小记录交换到前面
       }
       while (i<j && r[i]<= r[j]) i++;  //左侧扫描
       if (i<j) {
          r[j]←→r[i];   j--;  //将较大记录交换到后面
       }
    }
    retutn i;    //i为轴值记录的最终位置
}

3.如何处理分割得到的两个待排序子序列?

解决方法:
对分割得到的两个子序列递归地执行快速排序。

4.如何判别快速排序的结束?

若待排序列中只有一个记录,显然已有序,否则进行一次划分后,再分别对分割所得的两个子序列进行快速排序(即递归处理)。

快速排序代码如下:

void QuickSort (int  r[ ], int first, int end )
{//在序列 first~end中递归地进行快速排序
    if (first < end) {					
          pivotpos = Partition (r, first, end );    
          QuickSort (r, first, pivotpos-1);
          QuickSort (r, pivotpos+1, end );
   }
}

选择排序

一.简单选择排序

1.如何在无序区中选出关键字最小的记录?

设置一个整型变量index,用于记录在一趟比较的过程中关键字最小的记录位置。

2.如何确定最小记录的最终位置?

第i趟简单选择排序的待排序区间是r[i] ~ r[n],则r[i]是无序区第一个记录,所以,将index所记载的关键字最小的记录与r[i]交换。

 简单选择排序代码:

void  selectSort ( int  r[ ], int n)
{   
    for ( i=1; i<n; i++) 
    {  
        index=i; 		
        for (j=i+1; j<=n; j++) 
           if  (r[j]<r[index])  index=j;
        if (index!=i)   r[i]<==>r[index]; 	 
    }
} 

堆排序

1.堆的定义

堆是具有下列性质的完全二叉树:每个结点的值都小于或等于其左右孩子结点的值(称为小根堆),或每个结点的值都大于或等于其左右孩子结点的值(称为大根堆)。

void  HeapSort ( int  r[], int n)
{
    for (i=n/2; i>=1; i--)      //初建堆
       sift(r, i, n) ;     
    for (i=1; i<n; i++ )
    {
       r[1]←→r[n-i+1];        //移走堆顶
       sift(r, 1, n-i);               //重建堆
    }
}

 归并排序

二路归并排序

将一个具有n个待排序记录的序列看成是n个长度为1的有序序列,然后进行两两归并,得到n/2个长度为2的有序序列,再进行两两归并,得到n/4个长度为4的有序序列,……,直至得到一个长度为n的有序序列为止。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值