排序(上)---插排、希尔、堆排

排序(上)—-插排、希尔、堆排


插入排序

给每个新增的数在已有的数列中找到合适的位置,然后插入进去

例如一个由小到大的排序:
原数组为: 4, 5, 2, 9, 3, 6, 8, 7

  1. 现在我们有了一个数组,我们可以假装现在排过序的只有第一个数,也就是说已有序列是第一个数(i和j是下标,key代表当前要插入的数,j代表当前已经插入到了第几个数,i是动态的用来与key作比较)
    插入排序0
  2. 开始插入第二个数:从插入数的前一个位置(当前插入arr[1],所以i从0开始)向前寻找第一个不小于它的数,并进行交换,因为我们要把要插入的数插入到第一个(从插入的位置向前数)小于等于它的数的后面,所以当我们遇到比key大的数的时候,就直接将这个数向后挪动即可。
    插入排序1
  3. 第一次当走完0时,没有发现比要插入的数小的,所以下标为j这个数插入完毕,进行查入下一个数,即j=2,同时i从j的前一个开始进行比较
    插入排序2
  4. 我们发现i所在的数比要插入的数大,所以直接进行挪动,但是由于i没有走完0的下标,所以还要继续向前走(因为挪动后arr[j]的值就会变为5,但是我们现在时插入2,所一直要用2来进行比较,因此使用一个key来记住我们当前要插入的数)。
    插入排序3
  5. 当i走到数组的尽头,或者遇到小于等于它的数据时说明要插入的数据就可以插入到其下一个下标的位置。
  6. 每个数的插入方式都是这样,并且每插入一个数,已经插入的数就已经有序,所以当插完整个数组的时候,整个整个数组的排序也就完成了。
  7. 因为我们使用的是当遇到的数小于等于要插入的数的进行插入,所以会相对稳定,如果只是小于的话,那么碰到等于的数的时候,还会再进行向后挪动一次,这样,时间不但增加,而且稳定性还会大大降低。
  8. 插入排序的时间复杂度:

    • 最快:O(n)
    • 最慢:O(n^2)但是很稳定
  9. 空间复杂度:O(1)

以下是代码:

//插入排序
void InsertSort(int arr[], int size)
{
    int i, j;
    int  key;
    for (j=1; j<size; j++)
    {
        key = arr[j];
        for (i=j-1; i>=0; i--)
        {
            if (arr[i] > key )//如果大于要插入的数,说明要插入的数肯定再此数之前,所以直接将此数向后挪动即可
            {
                arr[i + 1] = arr[i];
            }
            else
            {
                break;
            }
        }
        arr[i + 1] = key;//运行到此位置说明已经找到了要插入的位置
    }
}

插入排序的优化

因为我们每次插入的时候,前面的数就已经有序,而我们使用的是遍历式查找比较,所以我们可以使用二分查找来增加查找的速度,当然使用二分查找适合使用数据比较多的时候。

  • 在使用二分查找的时候注意二分查找插入位置的条件

以下是代码:

void BInsertSort(int arr[], int size)
{
    int i, j;
    int  key;
    for (j = 1; j<size; j++)
    {
        key = arr[j];
        //首先是找要插入的下标
        int left, right, mid;
        left = 0;
        right = j-1;
        while (left <= right)
        {
            mid = left + ((right - left) >> 2);
            if (key >= arr[mid])//要插入的位置再mid的右边
            {
                left = mid + 1;
            }
            else
            {
                right = mid - 1;
            }
        }
        //要插入的位置已经找到
        //先将此位置到已插入的数的位置的所有数据都向后移动
        for (i = j-1; i > mid; i--)
        {
            arr[i + 1] = arr[i];
        }
        //此时已经将mid后面的数全部向后挪动了一遍,所以只需要将key插入到当前的位置
        arr[i] = key;
    }
}

希尔排序

当待排列的数是逆序的时候,插入排序就需要O(n)的时间复杂度,为了减少坏情况时排序的时间复杂度,我们使用多次插入排序,前几次排序时为了让数据基本有序,然后最后一次插入排序的时间复杂度就基本为O(n)了。
希尔排序就是对插入排序的优化,可以认为希尔排序是多次插入排序

  1. 插入排序的时候,我们一个一个数挨着的插入,但是,希尔排序的前期是排序相隔相等的数,进行排序。例如数据:
    希尔排序0
  2. 从图中我们可以知道,如果直接用来插入排序的话,排到后面的时候,时间复杂度会非常大所以我们首先将所有的白色进行排列的得到如下,因为我们是间隔三个数据进行排列的,所以速度是相当快的:
    希尔排序1
  3. 排完白色,再将其他两个颜色也都分别排一下:
    希尔排序2
    希尔排序3
  4. 最后将所有的数据进行一次插入排序,而此时数据已经基本有序了,所以最后一次插入排序的时间复杂度基本为O(n)。
    希尔排序4
  5. 时间复杂度
    • 最好O(n)
    • 最坏O(1.3n)

一下是代码:

void ShellSort(int arr[], int size)
{
    int i, j, gap;
    int key;
    gap = 3;//这里取间隔为3
    int g = size / gap;//g为根据数据的个数来确定前期插排的次数
    while (g > 0)
    {
        for ( j=2*g-1; j<size; j+= gap)
        {
            key = arr[j];
            for (i=j-gap; i>=0; i-=gap)
            {
                if (arr[i] > key)
                {
                    arr[i + gap] = arr[i];
                }
                else
                {
                    break;
                }
            }
            arr[i + gap] = key;
        }
        g--;
    }
    //此时输出的好是:4  0  1  7  5  2  9  6  8,符合前期的期望,而再次进行插排时间复杂度就会大大减少
    InsertSort(arr, size);
}

上面的方式代码看起来应该很清楚思路,但是总是觉得循环层数优点多,因为我们使用的是一层一层的排序,相对于上面的图来说就是一个颜色一个颜色的进行排序,但是如果我们能直接从第一个开始,每进入一个颜色,都能进行一次该颜色的排序,那么我们就不需要四一层循环了,我们可以通过简单的修改代码,来实现。

void ShellSort(int arr[], int size)
{
    int i, j, gap;
    int key;
    gap = 3;//这里取间隔为3
    for ( j=1; j<size; j++)
    {
        key = arr[j];
        for (i=j-gap; i>=0; i-=gap)
        {
            if (arr[i] > key)
            {
                arr[i + gap] = arr[i];
            }
            else
            {
                break;
            }
        }
        arr[i + gap] = key;
    }
    //此时输出的好是:4  0  1  7  5  2  9  6  8,符合前期的期望,而再次进行插排时间复杂度就会大大减少
    InsertSort(arr, size);
}

堆排序

因为堆的性质,顶部的数总是最大的或者最小的,所以,我们可以通过这个性质用堆来排序。

例如由大到小排序:

  1. 将所给数据建立一个小堆,堆顶数据总是最小的。

  2. 选堆顶的数据和堆的最后一个数据进行交换,然后进行向下调整,调整的时候不要调整已经交换的最大的数据,也就是不认为交换过后,这个最大的数还在堆里。

  3. 继续选出堆顶和最后一个数据进行交换,此时最后一个数据不包括之前交换过的数据,也就是说,每次和堆顶元素的交换,认为堆的元素个数就会少一个(从堆尾少)。
  4. 直到堆的元素为0,算排序完毕,此时整个数据就是有序的了,因为每次交换都是把最大的像后面搬,并且是从后到前的顺序是。
  5. 时间复杂度都是O(n*logn)

流程图:
堆排序

代码:

//向下调整
void AdjustDown(int arr[], int parent, int size)
{
    //判断是不是已经是叶子结点了
    while ( parent*2+1 < size )
    {
        //默认最小的孩子为左孩子,因为右孩子可能为空
        int minChild = 2 * parent + 1;
        //存在右孩子,并且右孩子更小
        if (minChild+1 < size && arr[minChild+1] < arr[minChild])
        {
            minChild = minChild + 1;
        }
        if (arr[parent] > arr[minChild])//父结点比最小的孩子大,就进行交换
        {
            //先进行交换
            int tmp = arr[parent];
            arr[parent] = arr[minChild];
            arr[minChild] = tmp;
            //再让父节点继续向下走
            parent = minChild;
        }
        else//符合堆了
        {
            return;
        }
    }
}
//堆排序
void HeapSort(int arr[], int size)
{
    //建堆
    for (int i=(size-2)/2; i>=0; i--)
    {
        AdjustDown(arr, i, size);
    }
    //建好了
    //让堆顶的数据和堆中最后一个数据进行交换,并且每交换一次,堆的大小减少一个
    for (int i=size-1; i>=0; i--)
    {
        int tmp = arr[0];
        arr[0] = arr[i];
        arr[i] = tmp;
        //交换完成之后进行向下调整
        AdjustDown(arr, 0, i);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: PCB封装中的HDR代表头插排,它是一种常见的连接器类型,用于电子设备中的连接和拔。HDR封装通常包括各种单、双排针排座。 单排针排座是一种具有一排金属针或管脚的连接器,通常用于单个电路板上的连接。它们可以简化电路板之间的通信和信号传输,提供可靠的连接,并易于拔。 双排针排座具有两个平行的针排,用于连接两个电路板。它们通常具有相同数量的针脚,其中一排位于连接器的上方,另一排位于下方。这种设计可增加连接的稳定性,并提供更高的连接密度。 单、双排针排座广泛应用于电子设备中,如计算机、通讯设备、消费电子产品等。它们可用于连接电路板之间的数据、电源和信号线,以实现各种功能,如数据传输、信号调制、电源供应等。这些针排座封装可以使电路板之间的连接更灵活、可靠,且易于组装和维护。 总之,HDR封装中的各种单、双排针排座在PCB设计和制造中扮演着重要的角色。它们具有可靠性高、连接密度高等优点,广泛应用于各种电子设备中,为电路板之间的通信和信号传输提供了有效的解决方案。 ### 回答2: PCB封装中的HDR指的是综合性双排针排座。它是一种电子连接器,用于将电子元件与PCB板连接。HDR封装由两个平行排列的针脚和对应的座组成,可以实现双向连接。 HDR封装主要有以下几种类型: 1. 单排针排座:单排针排座由一排平行排列的针脚组成,常见的材质有塑料和金属。它可用于将电子元件焊接在PCB上,使其与其他元器件连接。 2. 双排针排座:双排针排座是由两排平行排列的针脚组成,可以用于更多的连接选项。它可用于连接两个PCB板,或将电子元器件与PCB板相连。 3. 面贴式HDR:面贴式HDR指的是一种特殊的针排座封装,可以直接贴附在PCB板上。它可以节省空间,并提供简单的表面安装解决方案。 4. 螺口式HDR:螺口式HDR具有螺纹的连接机制,可以提供更牢固的连接。它适用于在振动或冲击环境下需要更可靠连接的应用。 单双排针排座具有多种封装类型,可以根据具体需求选择适合的封装。它们广泛应用于电子设备中,如计算机、通信设备、家用电器等。HDR封装的设计和使用能够提高电子元器件的连通性和可靠性,为电子产品的正常运行提供稳定的支持。 ### 回答3: HDR 是 PCB(Printed Circuit Board)封装的一种类型,主要用于连接电子器件和电路板。HDR 封装包括各种不同种类的单排和双排针排座,是由多个金属针脚组成的组件。 单排针排座是一种简单的连接组件,它由一排金属针脚组成,这些针脚可以入电路板上的孔位中,与电路板上的电路相连。单排针排座通常用于连接简单的电子元件,如电阻、电容和二极管等。它们可在电路设计时方便地更换和替代元件。 双排针排座是两排金属针脚平行排列而成的组件。这种封装通常用于连接较复杂的电子器件,如集成电路(IC)和处理器等。双排针排座可以提供更多的针脚,可连接更多的引脚,提供更高的连接密度和更低的电压降。 HDR 封装的针脚排座通常由优质的金属材料制成,以确保良好的连接和信号传输。它们的设计使得它们易于安装和替换,并提供稳定和可靠的连接,以便电子器件能够正常工作。 总之,HDR 封装的各种单双排针排座是 PCB 设计中常用的连接组件,用于连接各种类型的电子器件和电路板。它们为电子设备的正常功能提供了必要的电气连接,并具有易于安装和替换的特点,以满足电路设计和实现的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值