【C++】合影效果(自定义排序/sort排序练习)

老规矩:望各位小牛,小犇,中牛,中犇,大牛,大犇,神牛,神犇给予鼓励

小小蒟蒻在此先%%%%%%%%%%%%%%%%%拜大神

一.六大排序

六大排序分为:

1.冒泡排序               2.插入排序               3.选择排序

4.希尔排序               5.归并排序               6.快速排序/自定义排序

1.冒泡排序

        冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名。

冒泡排序算法的运作如下:(从后往前)

1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。

2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

3.针对所有的元素重复以上的步骤,除了最后一个。

4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

以下是实现冒泡排序的示例代码:

void bubbleSort(int arr[], int n) 
{ 
    int i, j; 
    for (i = 0; i < n-1; i++)    // 外层循环控制排序轮数
    {
        for (j = 0; j < n-i-1; j++)  // 内层循环控制每轮比较次数
        {
            if (arr[j] > arr[j+1])   // 如果前一个元素大于后一个元素,交换位置
                swap(&arr[j], &arr[j+1]);
        }
    }
}

2.插入排序

有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法--插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。

插入排序的基本思想是:每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。

有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法

一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:

⒈ 从第一个元素开始,该元素可以认为已经被排序

⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描

⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置

⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

⒌ 将新元素插入到下一位置中

⒍ 重复步骤2

如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。

以下是实现插入排序的示例代码:

void insertionSort(int arr[], int n)
{
    int i, j, key;
    for (i = 1; i < n; i++) 
    {
        key = arr[i];   // 从未排序部分中取出一个元素
        j = i - 1;
        while (j >= 0 && arr[j] > key)  // 在已排序部分中找到合适的位置插入元素
        {
            arr[j+1] = arr[j];  // 将已排序部分中大于该元素的部分向右移动一位
            j = j - 1;
        }
        arr[j+1] = key;  // 将元素插入到已排序部分的正确位置
    }
}

3.选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)。

选择排序法的第一层循环从起始元素开始选到倒数第二个元素,主要是在每次进入的第二层循环之前,将外层循环的下标赋值给临时变量,接下来的第二层循环中,如果发现有比这个最小位置处的元素更小的元素,则将那个更小的元素的下标赋给临时变量,最后,在二层循环退出后,如果临时变量改变,则说明,有比当前外层循环位置更小的元素,需要将这两个元素交换.

以下是一个实现选择排序的示例代码:

void selectionSort(int arr[], int n) {
    for (int i = 0; i < n-1; i++) {
        int min_idx = i;
        for (int j = i+1; j < n; j++) {
            if (arr[j] < arr[min_idx]) {
                min_idx = j;
            }
        }
        // 将找到的最小元素交换到已排序部分的末尾
        int temp = arr[min_idx];
        arr[min_idx] = arr[i];
        arr[i] = temp;
    }
}

4.希尔排序 

希尔排序(Shell Sort)是插入排序的一种。是针对直接插入排序算法的改进。该方法又称缩小增量排序,因D.L.Shell于1959年提出而得名。

下面是一个使用汇编语言实现的希尔排序的示例代码:

section .data
array db 12, 45, 23, 67, 54, 32, 89, 76
len equ 8

section .text
global _start

_start:
  ; 要使用希尔排序,我们需要依次使用不同的步长进行排序。
  ; 这里我们选择使用 Knuth 步长序列:h = 3*h + 1,直到 h > len/3 为止。
  mov ecx, 1
  mov eax, 1
  mov ebx, len
  shr ebx, 1

.loop_h:
  cmp ecx, ebx
  jg .loop_sort
  imul eax, eax, 3
  add eax, 1
  mov ecx, eax
  jmp .loop_h

.loop_sort:
  ; 使用当前步长 h 进行插入排序
  mov ebx, eax
  shr ebx, 1

  mov esi, 0
  cmp ebx, 0
  jle .end

  .loop_i:
    ; 插入排序的一次循环,类似于 C 代码中的:
    ; for (int i = h; i < len; i++) {
    ;   int temp = array[i];
    ;   int j = i;
    ;   while (j >= h && array[j-h] > temp) {
    ;     array[j] = array[j-h];
    ;     j -= h;
    ;   }
    ;   array[j] = temp;
    ; }

    mov eax, [array + esi + ebx] ; eax = array[i]
    mov edx, esi               ; edx = j

    .loop_j:
      cmp edx, ebx
      jl .end_j
      mov ecx, [array + edx - ebx] ; ecx = array[j-h]
      cmp ecx, eax
      jle .end_j
      mov [array + edx], ecx      ; array[j] = array[j-h]
      sub edx, ebx                ; j -= h
      jmp .loop_j

    .end_j:
      mov [array + edx], eax      ; array[j] = temp
      add esi, 1

    cmp esi, len
    jge .end

  jmp .loop_i

.end:
  ; 排序结束,输出结果
  mov esi, 0
  .loop_print:
    cmp esi, len
    jge .end_print
    mov eax, [array + esi]
    call print_int
    mov eax, ', '
    call print_str
    add esi, 1
  jmp .loop_print

.end_print:
  call print_newline
  mov eax, 1
  xor ebx, ebx
  int 0x80

; 下面是一些辅助函数,用于在终端上输出结果。
; 这些函数使用 Linux 系统调用,在 32 位系统上运行。
print_str:
  push ebp
  mov ebp, esp
  mov eax, 4
  mov ebx, 1
  mov edx, [ebp+8]
  mov ecx, eax
  int 0x80
  pop ebp
  ret

print_int:
  push ebp
  mov ebp, esp
  push eax
  push ebx
  push ecx
  push edx
  mov eax, [ebp+8]
  mov ebx, 10
  xor ecx, ecx
  .loop:
    xor edx, edx
    div ebx
    add dl, '0'
    push edx
    cmp eax, 0
    jne .loop
  .loop_print:
    pop eax
    cmp eax, 0
    je .end_print
    mov edx, eax
    dec edx
    mov ecx, esp
    mov [ecx], dl
    mov eax, 4
    mov ebx, 1
    mov edx, 1
    int 0x80
    dec esp
    jmp .loop_print
  .end_print:
    pop edx
    pop ecx
    pop ebx
    pop eax
    pop ebp
    ret

print_newline:
  push ebp
  mov ebp, esp
  mov eax, 4
  mov ebx, 1
  mov edx, newline
  mov ecx, eax
  int 0x80
  pop ebp
  ret

section .rodata
newline db 10

5.归并排序 

 归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并操作,也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。

如 设有数列{6,202,100,301,38,8,1}

初始状态:6,202,100,301,38,8,1

第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

总的比较次数为:3+4+4=11;

逆序数为14;

归并操作的工作原理如下:

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置

第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

重复步骤3直到某一指针超出序列尾

将另一序列剩下的所有元素直接复制到合并序列尾

下面是一个归并排序的模板代码(使用 C++ 实现):

void merge_sort(int arr[], int left, int right) {
  if (left >= right) return;

  int mid = left + (right - left) / 2;
  merge_sort(arr, left, mid);
  merge_sort(arr, mid+1, right);

  // 合并两个有序数组
  int i = left, j = mid+1, k = 0;
  int tmp[right-left+1];

  while (i <= mid && j <= right) {
    if (arr[i] < arr[j]) {
      tmp[k++] = arr[i++];
    } else {
      tmp[k++] = arr[j++];
    }
  }

  while (i <= mid) {
    tmp[k++] = arr[i++];
  }

  while (j <= right) {
    tmp[k++] = arr[j++];
  }

  // 将合并后的数组复制回原数组
  for (int p = 0; p < k; p++) {
    arr[left+p] = tmp[p];
  }
}

6.快速排序/自定义排序

快速排序算法是冒泡排序算法的一种改进,采用“分而治之”的思想,把大的拆分成小的,再把小的拆分成更小的。如:对于一组待排的记录,通过一趟排序后,将原序列分成两部分,其中前一部分的所有记录均比后一部分的所有记录小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中的所有记录均有序为止。

自定义排序是通过实现自定义比较函数来对数据进行排序的一种方式,其可以通过比较两个元素之间的大小关系来确定它们在排序结果中的相对位置。自定义排序在解决一些特定问题时可以发挥其优势,如根据一些特定条件对数据进行排序。

下面是一个示例代码,用来演示如何通过自定义比较函数对一组整数进行从小到大排序:

#include <iostream>
#include <algorithm>
using namespace std;

bool cmp(int a, int b) {
    return a < b; //从小到大排序
}

int main() {
    int a[] = {5, 2, 9, 4, 7};
    int n = sizeof(a) / sizeof(int);

    sort(a, a + n, cmp); //调用sort函数进行排序

    for (int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    return 0;
}

在这个示例中,我们首先定义了一个cmp函数来实现自定义比较,它返回a是否小于b。然后,我们将cmp函数传递给C++标准库的sort函数中,以对数组a进行排序。最后,我们输出排序后的结果。

通过自定义比较函数,我们可以指定按照我们需要的方式对数据进行排序,这样可以更好地适应特定的应用程序场景。例如,在处理一些比较特殊的数据时,需要根据一些特殊的规则进行排序,自定义排序就可以很好地满足这些需求。

二.合影效果

上题目

说明

小明和朋友们去爬香山,为美丽的景色所陶醉,想合影留念。如果他们站成一排,男生全部在左(从拍照者的角度),并按照从矮到高的顺序从左到右排,女生全部在右,并按照从高到矮的顺序从左到右排,请问他们合影的效果是什么样的(所有人的身高都不同)?

输入格式

第一行是人数 n(2≤n≤40,且至少有 1 个男生和 1 个女生)。
后面紧跟 n 行,每行输入一个人的性别(男male或女female)和身高(范围在 [0,2] 内的浮点数,单位米),两个数据之间以空格分隔。

输出格式

n 个浮点数,模拟站好队后,拍照者眼中从左到右每个人的身高。每个浮点数需保留到小数点后 2 位,相邻两个数之间用单个空格隔开。

样例

输入1
6
male 1.72
male 1.78
female 1.61
male 1.65
female 1.70
female 1.56
输出1
1.65 1.72 1.78 1.7

废话少说,上代码

#include<bits/stdc++.h>//万能头
using namespace std;
struct node {   //结构体node
    string sex; //string一个sex,性别
    double high; //double一个high,身高
} stu[45]; //开结构体数组
bool cmp(node x, node y){  //自定义排序,x,y(结构体)
    return x.high < y.high; //返回x小于y的值(升序)
}

int n; //人数

int main(){
    cin >> n; //输入人数
    for (int i = 1;i <= n; i++){ //循环输入结构体数组的第i个的性别,身高
        cin >> stu[i].sex >> stu[i].high; //结构体数组的第i个的性别,身高
    }
    sort(stu + 1, stu + 1 + n, cmp); //自定义排序,从stu + 1 开始 到 stu + 1 + n 结束,以cmp 的顺序
    for (int i = 1;i <= n; i++){ //循环判断
        if (stu[i].sex == "male") //男士全部在左(从拍照者的角度),并按照从矮到高的顺序从左到右排
            printf("%.2lf ", stu[i].high); //输出,别忘空格
    }
    for (int i = n;i >= 1; i--){
        if (stu[i].sex == "female") //女生女生全部在右,并按照从高到矮的顺序从左到右排
            printf("%.2lf ", stu[i].high); //输出,别忘空格
    }

我是用自定义做的,还有更多简单的方法,请各位大神多多指点,非常感谢

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

有任何细小错误请大神指教

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值