目录
没有考过代码。
写代码时出现的问题:
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。????