排序算法的代码-插入排序

目录

没有考过代码。

写代码时出现的问题:

插入排序

直接插入排序·带哨兵

直接插入排序·不带哨兵

折半插入排序(二分插入排序)

希尔排序


没有考过代码。

写代码时出现的问题:

1、不知道各个排序算法的名词该如何命名。

建议都使用:Insortsert.  直接插入查找:Insortsert、折半查找(二分查找):Binarysearch(Binary:二进制)

2、不知道排序算法里的形参是?  直接插入排序是数组名和长度:

        函数名(ElemType a[],int n);

        折半插入排序是(Selist L,Elwmtype key );

3、直接插入排序不会,不知道要插入的位置。

4、直接插入排序里什么时候是 j,什么时候用j+1。

5、希尔排序里,dk到底是等于几?是向下取整吗???

我为什么看不出来是 A[1]、A[4]、A[7]、???A[4]到A[7]这一步是怎么弄的?

插入排序

直接插入排序·带哨兵

思想:要求从头到尾序列是从小到大的。如果发现序列里后一个数字要比前一个小,不符合要求,如A > B;把B的值给哨兵,然后,用A将B覆盖掉,也就是 A[i+1]=A[i]。再将哨兵值赋值给A(A[i])的位置。就实现了A和B的换位置。哨兵相当于temp。

但是和交换数据不同的是,直接插入排序不只是相邻两个元素交换位置,而是如果待排序的元素小于已经排好序的序列元素的最大值,则要在已经排好序的序列里找到相应的位置,将该位置空出来(后移操作)。

//直接插入排序·带哨兵,A[0]是哨兵的位置,从A[1开始存放排序的序列。
void InsertSort(int A[], int n){
	int i,j;

    //将各元素插入已经排好序的序列中,A[2]~A[n]插入到前面已排列序列
	for ( i = 2; i <= n; i++)//这里居然有等于号?
	{
		if (A[i] < A[i-1])
		{
			//若A[i] 关键字小于前驱
			A[0] = A[i];//哨兵更新为每次即将排序的元素的值。
			for ( j = i-1;A[0] < A[j]; --j)
			{
				//从后往前查找待插入位置
				A[j+1] = A[j];//向后挪位
			}
			A[j+1] = A[0];//复制到插入位置
		}	
	}	
}

直接插入排序·不带哨兵

//直接插入排序·不带哨兵
void InsertSort(int A[], int n){
	int i,j,temp;

	//将各元素插入已经排好序的序列中,
	for ( i = 1; i < n; i++)
	{
		if (A[i] < A[i-1])
		{
			//若A[i] 关键字小于前驱
			temp = A[i];//用temp暂存A[i]
			for ( j = i-1;j >= 0 && A[j] > temp; --j)
			{
				A[j + 1] =A[j];
			}
            A[j+1] = temp;
		}	
	}	
}

折半插入排序(二分插入排序)

利用折半查找找到待插入的位置,然后将待插入位置后的元素都往后移动,将元素插入。


//在顺序表上折半查找的实现
typedef	struct{
	//查找表的数据结构:顺序表
	ElemType *elem;	//动态数组基址
	int TableLen;	//表的长度
}SSTable;

int Binary_Search(SeList L, ElemType key)
{
	int low = 0, high = L.Tablelen - 1, mid;
	while (low <= high)
	{
		mid = (low + high) /2;
		if (L.elem[mid] == key)
		{
			return mid;
		}
		 else if (L.elem[mid] > key)
		{
			high = mid - 1;
		}
		else 
			low = mid + 1;
	}
	return -1;
}
//折半插入排序。是在已经排好序的序列里查找该插入的位置。所以high = i-1.
void  Insertsort(ElemType a[],int n){
	int i,j,mid,low,high;
	for ( i = 2; i <= n; i++)
	{
		//目的:依次将a[2]-a[n]插入到前面的已排好序列。
		a[0]=a[i];//将a[i] 暂存到a[0]
		low = 1,high = i-1;
		while (low <= high)
		{
			mid =(low + high) /2;
			if (a[mid] > a[0])
			{
				high = mid - 1;
			}
			else 
			{
				low = mid + 1;
				//但如果是要插入6,mid =5,mid+1=8怎么办? 
			}	
		}
		//后移,插入操作。注意,经过折半查找后的high等于将要插入的位置-1。
		//因为high =mid -1.最后之后,
		for (j = i -1; j >= high+1 ; j--)
		{
			a[j+1] =a[j];
		}
		a[high+1] = a[0];//因为到达j= high+1
	}
}

希尔排序

//使用希尔排序进行升序排列
#include <stdio.h>

void ShellInsert(int A[], int n);

int main() 
{
	int A[20],n;
	printf("请输入要输入的元素个数:\n");
	scanf("%d",&n);
	printf("请输入要排序的序列:\n");
	for (int i=1; i<=n; i++){
        //输入的元素从1开始,0做哨兵
        scanf("%d",&A[i]);
    } 	
	ShellInsert(A,n);
	for(int i=1; i<=n; i++)
    {
        printf("%d  ",A[i]);
    }	
	printf("\n");

	return 0;
}

void ShellInsert(int A[], int n)
{
    //A[0]只是暂存单元,不是哨兵。因为后面j可以<0,也就是越过a[0]. 当j <= 0时,插入位置已到
    //数值是从A[1]开始存储的。下标不是从0开始的。
	int dk,i,j;
	for(dk=n/2; dk>=1; dk=dk/2) 
    {
		for(i=dk+1; i<=n; i++) 
        {
			if(A[i]<A[i-dk]) 
            {
                //需将A[i]插入有序增量子表
				A[0]=A[i];//暂存在A[0]
				for(j=i-dk; j>0 && A[0]<A[j]; j -= dk)
                {
					A[j+dk]=A[j];//记录后移,查找插入的位置。
				}
				A[j+dk]=A[0];
			}
		}
	}
}

在上面的算法里,我觉得难的地方是最里层的for循环。在前面,a[i]和a[i-dk]进行了比较,那么在接下来也就是最里层的for循环里进行交换。所以j=i-dk,  那么a[j+dk] =a[j],就是把a[j]的值赋给a[i].

接下来,在for循环里,交换完成后,执行j= j-dk;如果是第一轮,那么就j-dk一定是<0。如果是第二轮、第三轮,那么会继续循环,然后判断a[0]和新的a[j]的大小,是否交换,最后一步的结果也是j<0。

接下来的j+dk会使j到原来的i-dk的地方。然后把a[i]的值给a[j]。完成交换。

但我有不明白的地方,dk=dk/2,5/2等于2呀?例子里dk=3。????

猜你喜欢

转载自blog.csdn.net/weixin_48060069/article/details/126910636