首页 > 编程语言 >数据结构(排序算法)

数据结构(排序算法)

时间:2025-01-05 10:07:05浏览次数:3  
标签:arr 排序 int 算法 right key 数据结构 left

插入排序

插入排序(Insertion Sort)是一种简单直观的排序算法,其原理可以简述如下:
1.分已排序区间和未排序区间: 将数组分为已排序区间和未排序区间。初始时,已排序区间只包含数组的第一个元素,而未排序区间包含除第一个元素之外的所有元素。

2.依次将未排序区间中的元素插入到已排序区间中的合适位置: 从未排序区间取出第一个元素,将它插入到已排序区间的合适位置,使得已排序区间仍然保持有序。插入的方式是从已排序区间的末尾开始向前比较,找到插入位置后将元素插入其中。

3.重复步骤2直至未排序区间为空: 重复执行上述插入操作,直到未排序区间中的所有元素都被插入到已排序区间中,即整个数组排序完成。

#include <stdio.h>
void Insert_sort(int arr[], int size)
{
  int i = 0;
  int j = 0;
  int temp = 0; // 存放未排好序区间的第一个数
  for (i = 1; i < size; i++)
  {
    temp = arr[i];
    j = i - 1; // 存放已排好序区间的最后一个数下标
    while (j >= 0 && arr[j] > temp)
    {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = temp;
  }
}

void Print(int arr[], int size)
{
  for (int i = 0; i < size; i++)
  {
    printf("%-3d", arr[i]);
  }
  printf("\n");
}

int main()
{
  int arr[10] = {5, 1, 3, 8, 2, 6, 4, 9, 10, 7};
  int len = sizeof(arr) / sizeof(arr[0]);
  printf("插入排序前:");
  Print(arr, len);
  Insert_sort(arr, len);
  printf("插入排序后:");
  Print(arr, len);
  return 0;
}

这段代码实现了插入排序算法。 函数Insert_sort用于对传入的数组进行插入排序操作,参数arr表示要排序的数组,参数size表示数组的长度。在插入排序算法中,通过一个循环将数组分为已排好序的区间和未排好序的区间。从未排好序的区间中选择一个数temp,然后将它插入到已排好序的区间中的正确位置。具体操作是,将temp与已排好序的区间中的数逐个比较,如果temp比当前的数小,则将当前的数向后移动一个位置,直到找到temp的正确位置。然后将temp插入到该位置。重复这个过程直到未排好序的区间为空。

函数Print用于打印数组内容,参数arr表示要打印的数组,参数size表示数组的长度。

在主函数中,定义了一个长度为10的数组arr,并初始化了一些数据。然后调用Insert_sort函数进行排序,最后调用Print函数打印排序后的结果。

整体的思路是先将数组分为已排好序的区间和未排好序的区间,然后从未排好序的区间中选择一个数temp,将它插入到已排好序的区间中的正确位置。重复这个操作直到未排好序的区间为空,即完成了数组的排序。
在这里插入图片描述

快速排序

将一个数组的起始位置记成left,最后一个元素位置记成right,那么标记left的位置的元素,把该元素看成基准点(key)。

在这里插入图片描述

这时候right要不断的向左移动,若right所在位置的元素是小于key位置的元素,那么right停止移动。left要不断的向右移动,若left所在位置的元素是大于key位置的元素,那么left停止移动。总结就是:left找大,right找小。(注意:若将left设置为key,则先移动right然后才能移动left)

在这里插入图片描述

当left和right都停下来后,把他们的元素进行交换,交换过后继续移动。

在这里插入图片描述

如此反复操作,最后left会走到right的位置,这时候left和right是处于同一位置的,把该位置的元素和key位置的元素进行交换,更新key的位置。

在这里插入图片描述

可以观察到,此时数组有了一个特点:以key为中心点,左边区间的元素都是小于基准点key元素的,右边区间的元素都是大于key元素的。

在这里插入图片描述

将左边区间又看成一个小数组,右边区间也看成一个小数组。此时左边区间的left就是下标为0的位置,左边区间的right是key-1的位置。右边区间的left是key+1的位置,right是整个大数组的末尾处,既大数组的right。通过递归不断让每个小数组变得有序,最后整个数组也就有序了。

#include <stdio.h>

void swap(int *p1, int *p2) // 交换函数
{
  int temp = *p1;
  *p1 = *p2;
  *p2 = temp;
}
int PatrSort1(int *a, int left, int right) // hoare法
{
  int key = left;      // 定义基准点key
  while (left < right) // 当left<right说明还没相遇,继续数组内元素的交换
  {
    while (left < right && a[right] >= a[key]) // right找小
    {
      right--;
    }
    while (left < right && a[left] <= a[key]) // left找大
    {
      left++;
    }
    swap(&a[right], &a[left]); // 交换left和right位置的元素
  }
  swap(&a[key], &a[left]); // 跳出循环说明他们相遇了,将他们位置的元素与key位置的元素交换
  key = left;              // 更新key的位置
  return left;             // 返回key元素当前的下标
}

void Qsort(int *a, int begin, int end) // 快速排序(递归法),这里的begin=left,end=right
{
  if (begin >= end) //
  {
    return;
  }
  int key = PatrSort1(a, begin, end); // 每次递归都会找到一个属于该数组的key

  Qsort(a, begin, key - 1); // 递归左右区间
  Qsort(a, key + 1, end);
}

void PrintArr(int *a, int n) // 打印数组
{
  for (int i = 0; i < n; i++)
  {
    printf("%d ", a[i]);
  }
  printf("\n");
}

void Test_Qsort() // 快排(递归)测试
{
  int arr[] = {5, 10, 6, 1, 2, 4, 3, 9};
  int sz = sizeof(arr) / sizeof(int);
  printf("快速排序前:");
  PrintArr(arr, sz);
  Qsort(arr, 0, sz - 1);
  printf("快速排序后:");
  PrintArr(arr, sz);
}

int main()
{
  Test_Qsort();
  return 0;
}

该代码实现了快速排序算法。具体分析如下:

swap函数:交换两个指针所指向的值的函数。

PatrSort1函数:使用hoare算法进行快速排序。该函数接受一个数组a、左边界left和右边界right作为参数,返回排序后基准元素的下标。

hoare算法的思想是选择一个基准点key,然后将数组分成两部分,一部分是小于等于key的元素,一部分是大于等于key的元素。通过不断地交换元素,最后将基准元素放置到正确的位置。

Qsort函数:递归实现快速排序。该函数接受一个数组a、开始位置begin和结束位置end作为参数。如果开始位置大于等于结束位置,表示该部分已经有序,直接返回。否则,通过PatrSort1函数找到基准元素的下标key,然后递归调用Qsort对基准元素的左右两部分进行排序。

PrintArr函数:打印数组的函数。

Test_Qsort函数:测试快速排序的函数。首先定义一个数组arr,然后调用Qsort函数对其进行排序,并通过PrintArr函数打印排序后的结果。

main函数:调用Test_Qsort函数进行测试。
在这里插入图片描述

希尔排序

希尔排序

希尔排序是一种改进版的插入排序,普通的插入排序算法中,是从第2个节点开始,依次插入到有序序列中,这种做法虽然“一次成形”,但研究发现时间效率上这么做并不划算,更“划算”的做法是这样的:

不严格一个个插入使之有序,而是拉开插入节点的距离,让它们逐步有序,比如如下图所示,有无无序列:

84、83、88、87、61、50、70、60、80、99

第一遍,先取间隔为(Δ=5Δ=5),即依次对以下5组数据进行排序:

84、83、88、87、61、50、70、60、80、99
84、83、88、87、61、50、70、60、80、99
84、83、88、87、61、50、70、60、80、99
84、83、88、87、61、50、70、60、80、99
84、83、88、87、61、50、70、60、80、99

注意,当对84和50进行排序时,其他的元素就像不存在一样。因此,经过上述间隔为5的一遍排序后,数据如下:

50、83、88、87、61、84、70、60、80、99
50、70、88、87、61、84、83、60、80、99
50、70、60、87、61、84、83、88、80、99
50、70、60、80、61、84、83、88、87、99
50、70、60、80、61、84、83、88、87、99

最终的结果(50、70、60、80、61、84、83、88、87、99)是经过这一遍间隔Δ=5Δ=5的情况下达成的,接下去缩小间隔重复如上过程。例如让间距Δ=3Δ=3:

50、70、60、80、61、84、83、88、87、99
50、70、60、80、61、84、83、88、87、99
50、70、60、80、61、84、83、88、87、99
50、70、60、80、61、84、83、88、87、99

将上述粗体的每一组数据进行排序,得到:

50、70、60、80、61、84、83、88、87、99
50、61、60、80、70、84、83、88、87、99
50、61、60、80、70、84、83、88、87、99
50、61、60、80、70、84、83、88、87、99

最终的结果(50、61、60、80、70、84、83、88、87、99)更加接近完全有序的序列。接下去继续不断减小间隔,最终令Δ=1Δ=1,确保每一个元素都在恰当的位置。

代码如下:

#include <stdio.h>
#include <math.h>

int comp_count = 0;
int swap_count = 0;

void show(int data[], int len)
{
    int i;
    for(i=0; i<len; ++i)
    {
        printf("%d\t", data[i]);
    }

    printf("\n");
    return;
}

//                    起点    节点个数    间距
void insert_sort(int data[], int len, int delta)
{
    if(len <= 1)
        return;

    for(int i=delta; i<len*delta; i+=delta)
    {
        int j, tmp = data[i];
        for(j=i-delta; j>=0; j-=delta)
        {
            comp_count++;
            if(data[j] < tmp)
                break;

            swap_count++;
            data[j+delta] = data[j];
        }

        data[j+delta] = tmp;
    }
}

void shell_sort(int data[], int len)
{
    if(len <= 1)
        return;

    for(int delta=len/2; delta>0; delta/=2)
    {
        for(int i=0; i<delta; ++i)
        {
            //           起点     节点个数    间距
            insert_sort(data+i, len/delta, delta);
        }
    }
}

int main(void)
{
    // 准备产生一些随机数
    srand(time(NULL));

    int i, data[100];
    for(i=0; i<100; i++)
    {
        int exp = (int)pow(10, rand()%3+3);
        data[i] = rand()%exp;
    }
    printf("随机序列: ");
    show(data, 100);

    printf("希尔排序: ");
    shell_sort(data, 100);
    show(data, 100);

    printf("总共比较次数: %d\n", comp_count);
    printf("总共移动次数: %d\n", swap_count);

    return 0;
}

该代码实现了希尔排序算法。希尔排序是一种插入排序的改进版本,它通过将待排序序列分割成若干个子序列,并对每个子序列进行插入排序,最后再对整个序列进行一次插入排序。希尔排序的关键在于选择合适的间隔序列,通过不断缩小间隔来逐步完成排序。

在该代码中,首先定义了全局变量comp_count和swap_count,用于统计比较次数和移动次数。然后实现了show函数用于打印数组元素,insert_sort函数用于对子序列进行插入排序,shell_sort函数用于实现希尔排序。

在主函数中,通过调用rand函数生成一些随机数,并将其存入数组data中。然后调用shell_sort函数对数组进行希尔排序。最后打印排序后的数组以及比较次数和移动次数。

标签:arr,排序,int,算法,right,key,数据结构,left
From: https://blog.csdn.net/weixin_69851948/article/details/144904034

相关文章

  • 数据结构理论篇(期末突击)
    找往期文章包括但不限于本期文章中不懂的知识点:个人主页:我要学编程(ಥ_ಥ)-CSDN博客所属专栏: 学校课程突击下面均是为了应付学校考试所用,如果有涉及部分知识点下面未说明,可以去我的数据结构专栏看看或者自行在网上查阅资料。 以下所有知识均是阅读大话数据结构所得。如......
  • Python+Django+Mysql开发个性化旅游酒店推荐系统 python在线酒店推荐系统设计开发 可
    Python+Django+Mysql开发个性化旅游酒店推荐系统python在线酒店推荐系统设计开发可视化、爬虫协同过滤推荐算法机器学习深度学习人工智能大数据开发教程文档HotelRecommendSysPy一、项目简介1、开发工具和使用技术Python3及以上版本,Django3.6及以上版本,mysql8,nav......
  • 【优化调度】基于遗传算法的公交车调度排班优化的研究与实现(Matlab代码实现)
     ......
  • 力扣算法
    1.[两数之和]给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。输入:nums=[2,7,11,15],target=9输出:[0,1]暴力法publicint[]TwoSum(int[]nums,inttarget){//第一层循环:遍历数组......
  • java简单算法题001(保姆级教学)
    问题描述在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。要求:设计一个算法,使其时间复杂度为O(n),其中n是班级的人数。尽量减少额......
  • 【哈希算法】实战应用
    一、使用哈希进行函数调用使用哈希隐藏API调用代码#include<windows.h>#include<stdio.h>intmain(){MessageBoxA(NULL,"Meow-meow!","=^..^=",MB_OK);return0;}编译i686-w64-mingw32-g++meow.c-omeow.exe-mconsole-I/usr/share/mingw-w64......
  • 恶意软件常用加密算法
    前面主要是加密字符串信息,加密算法还可以加密shellcode、通信数据包、配置信息等一、常用加密算法概述加密配置信息、加密通信信道、加密窃取数据、混淆代码放置静态分析总体来说就是加密shellcode、代码模块、配置信息、通信等二、加密配置信息设置一个场景,恶意dll文件,放在h......
  • Python机器学习算法KNN、MLP、NB、LR助力油气钻井大数据提速参数优选及模型构建研究
    全文链接:https://tecdat.cn/?p=38601原文出处:拓端数据部落公众号分析师:HuayanMu随着机器学习和大数据分析技术的发展,帮助客户进行油气行业数字化转型势在必行,钻井提速参数优选呈现由经验驱动、逻辑驱动向数据驱动转变的趋势。机械钻速最大化、机械比能最小化是钻井过程中常考......
  • 跳跃游戏II(贪心算法)
    给定一个长度为 n 的 0索引整数数组 nums。初始位置为 nums[0]。每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i+j] 处:0<=j<=nums[i] i+j<n返回到达 nums[n-1] 的最小跳跃次数。生......
  • 算法提高 校门外的树
    时间限制:C/C++1000MS,其他语言2000MS内存限制:C/C++512MB,其他语言1024MB难度:困难分数:100 OI排行榜得分:14(0.1*分数+2*难度)描述某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位......