精华内容
下载资源
问答
  • 置换选择排序

    千次阅读 2014-12-15 20:16:33
    置换选择排序 描述 给定初始整数顺串,以及大小固定并且初始元素已知的二叉最小堆(为完全二叉树或类似完全二叉树,且父元素键值总小于等于任何一个子结点的键值),要求利用堆实现置换选择排序,并...

    置换选择排序

    描述


    给定初始整数顺串,以及大小固定并且初始元素已知的二叉最小堆(为完全二叉树或类似完全二叉树,且父元素键值总小于等于任何一个子结点的键值),要求利用堆实现置换选择排序,并输出第一个顺串。例如给定初始顺串29,14,35,13,以及堆(记为16 19 31 25 21 56 40), 置换选择排序得到的第一个顺串为16 19 21 25。

    输入
    第一行包含两个整数,m为初始顺串的数的个数,n为二叉最小堆的大小
    第二行包含m个整数,即初始顺串
    第三行包含n个整数,即已经建好的堆的元素(有序,按照从堆顶到堆底,从左到右的顺序)
    输出
    输出包含一行,即第一个顺串。
    样例输入
    4 7
    29 14 35 13
    16 19 31 25 21 56 40
    样例输出

    16 19 21 25
    参考代码:

    #include <stdio.h>
    #include<iostream> 
    using namespace std;
    int m,size;
    int str[1001];
    int A[1001];
    class MinHeap { // 最小堆ADT定义
    public:
    	int * heapArray; // 存放堆数据的数组
     	int CurrentSize; // 当前堆中元素数目
     	int MaxSize; // 堆所能容纳的最大元素数目
     	void BuildHeap(); // 建堆
     	MinHeap(int* array,const int n); // 构造函数,n为最大元素数目
     	void SiftDown(int left); // 筛选法
    };
    void MinHeap::SiftDown(int position) {
    	int i=position; //标识父结点
    	int j=2*i+1; //标识关键值较小的子结点
    	int  temp=heapArray[i]; //保存父结点
    	while (j<CurrentSize){ //过筛
     		if ((j<CurrentSize-1)&&(heapArray[j]>heapArray[j+1]))
     			j++; //j指向数值较小的子结点
     		if (temp>heapArray[j]){
     			heapArray[i]=heapArray[j];
     			i=j; j=2*j+1; //向下继续
     		} else break;
    	}
    	heapArray[i]=temp;
    }
    void MinHeap::BuildHeap() {
    	for (int i=CurrentSize/2-1; i>=0; i--) //反复调用筛选函数
    		SiftDown(i);
    } 
    MinHeap::MinHeap(int *array,const int n) {
    	CurrentSize=n;
    	MaxSize=n; //初始化堆容量为n
    	heapArray=new int [MaxSize]; //创建堆空间
    	for(int i=0;i<n;i++){
    		heapArray[i] = array[i];
    	}
    	BuildHeap(); //此处进行堆元素的赋值工作
    }
    void replacementSelection(int *A){
    	//建立最小值堆
    	MinHeap H(A,size);
    	int last = size-1;
    	int len = m<last? m:size;
    	for(int i=0; i<len; i++){
    		cout<<H.heapArray[0]<<" ";  	//堆的最小值
    		if(str[i]>=H.heapArray[0]) 	H.heapArray[0] = str[i];
    		else  {//否则用last位置记录代替根结点,把r放到last
    			H.heapArray[0] = H.heapArray[last];
    			H.heapArray[last] = str[i];
    			H.CurrentSize--;
    			last--;
    		} 
    	    if (last!=0) 
    			H.SiftDown(0);  //堆调整 
      	}
    }
    int main(){
    	cin>>m>>size;
    	int i;
    	for(i=0;i<m;i++){
    		cin>>str[i];
    	}
    	for(i=0;i<size;i++)
    		cin>>A[i];
    	replacementSelection(A);
    	return 0;
    }

    展开全文
  • 置换选择排序算法

    2020-01-13 23:13:56
    数据结构与算法之置换选择排序-C语言概述预备知识算法过程临界情况 概述 前面,我们已经学习过了如何进行内排序,以及内排序的常见算法,但是当文件过于大时会出现什么情况呢?如何进行排序呢?为了解决这些问题,...

    数据结构与算法之置换选择排序-C语言

    概述

    前面,我们已经学习过了如何进行内排序,以及内排序的常见算法,但是当文件过于大时会出现什么情况呢?如何进行排序呢?为了解决这些问题,置换选择排序算法出现了。

    预备知识

    1.相关库
    include<math.h>
    include<time.h>
    include<memory.h>

    算法过程

    首先用当前时间当做随机数生成器,生成大量的随机数,并写入一个txt文件。我们要做的就是对文件中的随机数进行排序,我们假设内存中最多能同时处理10 000个数,而生成了100 000个随机数。我们要处理的就是对这么多个数进行排序。并且我们用到了一个堆结构(最小堆),来进行处理。

    临界情况

    1. 直接输出最小堆中的数
    2. 输出一部分至目前的文件,另一部分数到下一个文件。
    3. 全部输出到下一个文件。

    ##代码:

    #include <iostream>
    #include<stdio.h>
    #include<time.h>
    #include<stdlib.h>
    #include<memory.h>
    #include<assert.h>
    #include<unistd.h> // windows.h sleep()
    #include<math.h>
    
    #define M_SIZE 100000			//Memory Size
    
    #define _CRT_SECURE_NO_WARNINGS
    
    typedef struct Fout_List
    {
    	FILE* fpoint;
    	Fout_List* next;
    } *Flist;
    
    Flist Replace_Selection(FILE* fin, Flist fout, long long int num, int* array, int M_size);
    void swap(int* arr, int i,int j);
    void HeapAdjust(int* a, int s, int m);
    int partition(int* arr,int left,int right);
    void quicksort(int*arr, int left, int right);
    void shell(int* arr, int size);
    
    int main()
    {
    	double sum_time = 0, average_time = 0;
    	clock_t start;
    	FILE* fin;			//Unsorted record
    	FILE* log;			//Running time
    
    	//fopen_s(&log, "log.txt", "a+");
    	log = fopen("log.txt", "a+"); // fopen_s(log, )
    	assert(log);
    
    	time_t current = time(&current);/*Get current time*/
        //char buff[26];
        char* buff;
    	//ctime(buff, sizeof(buff), &current);
    	buff = ctime(&current);
    	fprintf(log, "%s", buff);/*Print current time*/
    
    	long long int num = 0;				//The size of the array
    	for (int m = 0; m < 1; m++)		//Adjust the size of array.
    	{
    		num += 1000000;
    		printf("num = %lld\n", num);
    		int* array = (int*)malloc(M_SIZE * sizeof(int));
    		assert(array);
    
    		int repeat = 1;				//The repeat time.
    		for (int n = 0; n < repeat; n++)		//Adjust the repeat time.
    		{
    			printf("\trepeat = %d\n", repeat);
    			sum_time = 0;
    			average_time = 0;
    			for (int j = 0; j < 1; j++)
    			{
    				//fopen_s(&fin, "data.txt", "w");
    				fin = fopen("data.txt", "w");
    				assert(fin);
    				srand((unsigned)(time(NULL)));		//Initialize random number generator
    				for (int i = 0; i < num; i++)
    				{
    					int temp = rand();
    					fprintf(fin, "%d\t", temp);
    				}
    				fclose(fin);
    
    				Flist fout = NULL;
    				memset(array, 0,M_SIZE * sizeof(int));
    				start = clock();										//
    				fout = Replace_Selection(fin, fout, num,array, M_SIZE);					//
    				sum_time += ((double)clock() - (double)start);			//Calculate cumulative time
    			}
    
    			sum_time /= CLOCKS_PER_SEC;
    			average_time = sum_time / repeat;
    			fprintf(log, "NUM:\t%lld\tREPEAT:\t%d\tS_TIME:\t%lf\t\tA_TIME:\t%lf\n", num, repeat, sum_time, average_time);
    
    			fprintf(log, "\n");
    
    		}
    		free(array);
    	}
    	fprintf(log, "\n\n");
    	fclose(log);
    
    	return 0;
    }
    void swap(int * arr,int i,int j)
    {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    void shellsort(int* arr, int length)
    {
    
        int len = length;
        for (int gap = len/2; gap>0;gap = (int)(gap/2)) {
            //多个分组交替进行
            for (int i = gap; i <len; ++i) {
                int j = i;
                int current = arr[i];
                while(j-gap>=0&&current<arr[j-gap])
                {
                    arr[j] = arr[j-gap];
                    j = j - gap;
                }
                arr[j] = current;
            }
        }
    }
    int partition(int* arr,int left,int right)
    {
        int pivot = left;
        int index  = pivot+1;
        for (int i = index; i <right ; ++i) {
            if(arr[i]<arr[pivot])
            {
                swap(arr,i,index);
                index++;
            }
        }
        swap(arr,pivot,index-1);
        return index-1;
    }
    
    /*
     * 快速排序(Quick Sort)
     * 算法描述:
     * 利用分治法把一个串分为两个子串
     * 从序列中挑选一个元素,称为基准
     * 重新排序数列,所有元素比基准小的摆在基准前面,所有元素比基准大的摆在基准的后面(相同的数可以放到任一边)
     * 在这个分区退出之后,该基准就处于数列的中间位置,称之为分区操作
     * 递归的把小于基准值的子数列和大于基准值的子序列排序
     */
    void quicksort(int * arr,int left,int right)
    {
        //int len = arr->length;
        int partitionindex;
        if(left<right)
        {
            partitionindex = partition(arr,left,right);
            quicksort(arr,left,partitionindex-1);
            quicksort(arr,partitionindex+1,right);
        }
    }
    
    /*
     * 新加入一个结点至跟节点处,并调整堆结构
     */
    void HeapAdjust(int* arr, int size, int i)
    {
        int left_child = 2*i + 1;
        int right_child= 2*i + 2;
        int min = i; //选出当前结点与其左右孩子三者之中的最小值
        if(left_child<size && arr[left_child] < arr[min])
        {
            min = left_child;
        }
        if(right_child<size && arr[right_child] < arr[min])
        {
            min = right_child;
        }
        if(min != i)
        {
            swap(arr, i, min); //将最小值结点与父结点互换
            HeapAdjust(arr, size, min); //递归调用
        }
    }
    
    /*
     * 构建最小值堆
     */
    void BuildMinHeap(int* arr, int size)
    //对每一个非叶子结点向下进行最小堆排序
    {
        int i = 0;
        for(i = size/2-1; i >= 0; i--)
        {
            HeapAdjust(arr, size, i);
        }
    }
    
    /*
     * 在选择排序中,当将最小值堆的根结点输出后,
     * 再从缓冲区扫描入一个元素,再调整堆结构
     */
    int  HeadAdjust(int* arr, int size, int element)
    {
        //此时arr已经是最小值堆
        if(element>=arr[0])
        {
            //如果新加进来的元素大于原最小值,则将新元素放在堆顶,并重新建堆
            arr[0] = element;
            BuildMinHeap(arr, size);
            return size;
        }
        if(element<arr[0])
        {
            arr[0] = arr[size-1];
            arr[size-1] = element;
            BuildMinHeap(arr, size-1);
            size = size - 1;
            return size;
        }
    
    }
    
    /*
     * 现在没有外部元素传入
     */
    
    //未进行归并,num是文件中数据的个数,fout为要写入的文件
    //num为数据大小
    //M_size为内存大小
    void killbill()
    {
        
    }
    Flist Replace_Selection(FILE* fin, Flist fout, long long int num, int* array, int M_size)
    {
    	char fname[20];
    	memset(fname, 0, 20);
    	int fnum = 0;
    	fin = fopen("data.txt", "rb");
    	assert(fin);
    	for (int i = 0; i < M_size; i++)
    	{
    		fscanf(fin, "%d", array + i); // pointer point to M_size
    	}
    	//Complete the following code
        BuildMinHeap(array, M_size); // 建堆
        int temp = M_size;
        int* element = (int*)malloc(sizeof(int));
        fout = (Flist)malloc(sizeof(Fout_List));
        assert(fout);
        /*
         * 当temp = 0时说明一个顺串已经形成
         * 那么之后我们应该进行第二个顺串了
         * 循环结束条件是fin中还有数据
         */
        fseek(fin, 0L, SEEK_END);
        long long int len1 = ftell(fin);
        fseek(fin, M_size, SEEK_SET);
        long long int len2 = ftell(fin);
        long long int count = len2;
        sprintf(fname, "fout/%d.txt", fnum++);
        fout->fpoint = fopen(fname, "w");
        while(temp>0)
        {
            fprintf(fout->fpoint, "%d\t", array[0]);
            fscanf(fin, "%d", element);
            temp = HeadAdjust(array, temp, *element);
            count--;
            if(count!=0&&temp==0)
            {
                fclose(fout->fpoint);
                temp = M_size;
                BuildMinHeap(array, M_size);
                sprintf(fname, "fout/%d.txt", fnum++);
                fout->next = (Flist)malloc(sizeof(Fout_List));
                assert(fout->next);
                fout = fout->next;
                fout->fpoint = fopen(fname, "w");
            }
            if(count==0&&temp==M_size)
            {
                // 只有正序符合这种情况
                quicksort(array, 0 ,M_size);
                for (int i = 0; i < M_size; ++i) {
                    fprintf(fout->fpoint, "%d", array[i]);
                }
                fclose(fout->fpoint);
                break;
            }
            if(count==0&&temp==0)
            {
                fclose(fout->fpoint);
                fout->next = (Flist)malloc(sizeof(Fout_List));
                fout = fout->next;
                sprintf(fname, "fout/%d.txt", fnum++);
                fout->fpoint = fopen(fname, "w");
                assert(fout->fpoint);
                quicksort(array, 0, temp);
                for (int i = 0; i < M_size; ++i) {
                    fprintf(fout->fpoint, "%d\t", array[i]);
                }
                fclose(fout->fpoint);
                break;
            }
            if(count==0&&temp>0)
            {
                quicksort(array, 0, temp);
                for (int i = 0; i <temp; ++i) {
                    fprintf(fout->fpoint, "%d\t", array[i]);
                }
                fclose(fout->fpoint);
                sprintf(fname, "fout/%d.txt", fnum);
                fout->next = (Flist)malloc(sizeof(Fout_List));
                fout = fout->next;
                fout->fpoint = fopen(fname, "w");
                assert(fout->fpoint);
                quicksort(array, temp, M_size);
                for (int j = temp; j < M_size; ++j) {
                    fprintf(fout->fpoint, "%d\t", array[j]);
                }
                fclose(fout->fpoint);
                break;
            }
        }
        fout->next = nullptr;
    	return fout;
    }
    
    
    
    

    如有不明白的地方,请联系我QQ1972135329, 随时。
    我爱王艺娴。

    展开全文
  • 置换选择排序的扫雪机模型置换选择排序扫雪机模型 置换选择排序 置换选择排序是用于文件外排序的一种算法,其核心思想是:利用在内存工作区中建立的堆,对输入文件中的数据进行筛选,从而生成尽可能长的初始顺串。 ...

    置换选择排序的扫雪机模型

    置换选择排序

    置换选择排序是用于文件外排序的一种算法,其核心思想是:利用在内存工作区中建立的堆,对输入文件中的数据进行筛选,从而生成尽可能长的初始顺串。

    扫雪机模型

    扫雪机模型是一种用于解释置换选择排序生成初始顺串的平均长度的模型。

    想象有一个圆形的操场,操场上有一台扫雪机正在进行扫雪。雪正在均匀地下着,这里的均匀指的是雪落在圆形操场的任意一点处的概率相同。当扫雪机铲雪到一定时间后,操场上雪的数量恒定,其后任意时刻其形状都如下图所示,是一个三角形。那么,在这种稳定的情况下,扫雪机每转操场一圈,它铲的雪是多少呢?我们设当雪的状态相对稳定时,操场上雪的数量为M,则从下图我们很容易看出:此时铲雪机每扫一圈,它铲的雪的数量(下图中的长方形) = 操场上现存的雪的数量(下图中深红色的三角形)的两倍 = 2M.

    在这里插入图片描述
    但是扫雪机模型和置换选择排序的关系在哪呢?我觉得这是理解扫雪机模型最关键的一点。我们可以做一个类比:

    • 圆形操场类比为内存工作区中建立的堆,雪类比为待处理的数据;
    • 雪被扫雪机铲走意味着数据进入输出文件,成为输出顺串的一部分,雪没被扫雪机铲走意味着数据停留在内存工作区中,且不会在这一轮的置换选择排序中成为输出顺串的一部分;
    • 扫雪机扫一轮意味着一轮置换选择排序;

    对于一个数据而言,当它从输入文件中被读出并进入内存工作区时,它有两种选择,一种是进入内存工作区的堆中,另一种是不进入堆中。注意到,进入堆中的数据一定会成为输出顺串的一部分,因此数据进入堆可以对应雪落在扫雪机还未经过的路径上;而未进入堆的数据可以视为雪落在扫雪机已经经过的路径上。由于输入文件的数据是等概率分布的,所以输入数据的均匀性可以对应雪均匀地落下。

    因此,扫雪机模型与置换选择排序其实是有一种一一对应的关系。在一轮置换选择排序中,设不进入堆中的数据(对应操场中没有被铲走的雪)数量为M,则置换选择排序算法形成的初始顺串长度(对应操场中被铲走的雪) = 2M。

    展开全文
  • 1:置换选择排序 查看提交统计提问 总时间限制: 1000ms 内存限制: 65536kB 描述 给定初始整数顺串,以及大小固定并且初始元素已知的二叉最小堆(为完全二叉树或类似完全二叉树,且父元素键值总小于等于任何一个子结点...

    1:置换选择排序
    查看提交统计提问
    总时间限制: 1000ms 内存限制: 65536kB
    描述
    给定初始整数顺串,以及大小固定并且初始元素已知的二叉最小堆(为完全二叉树或类似完全二叉树,且父元素键值总小于等于任何一个子结点的键值),要求利用堆实现置换选择排序,并输出第一个顺串。例如给定初始顺串29,14,35,13,以及堆(记为16 19 31 25 21 56 40), 置换选择排序得到的第一个顺串为16 19 21 25。

    输入
    第一行包含两个整数,m为初始顺串的数的个数,n为二叉最小堆的大小
    第二行包含m个整数,即初始顺串
    第三行包含n个整数,即已经建好的堆的元素(有序,按照从堆顶到堆底,从左到右的顺序)
    输出
    输出包含一行,即第一个顺串。
    样例输入
    4 7
    29 14 35 13
    16 19 31 25 21 56 40
    样例输出
    16 19 21 25

    #include <iostream>
    #include <cstdio>
    using namespace std;
    int myheap[100000];
    int tmp[100000];
    int m, n;
    int last;
    void shiftdown(int k)
    {
        int f = k;
        int s = f * 2 + 1;
        int t = myheap[f];
        while(s < last)
        {
            if(s < last - 1 && myheap[s] > myheap[s + 1])
            {
                s++;
            }
            if(t > myheap[s])
            {
                myheap[f] = myheap[s];
                f = s;
                s = f * 2 + 1;
            }
            else
            {
                break;
            }
        }
        myheap[f] = t;
    }
    
    int main()
    {
        cin >> m >> n;
        last = n;
        for (int i = 0; i < m;i++)
        {
            scanf("%d", tmp + i);
        }
        for (int i = 0; i < n;i++)
        {
            scanf("%d", myheap + i);
        }
        int ago = -10000000;
        for (int i = 0; i < m;i++)
        {
            if(last <= 0) // 求第一个顺串,注意这个,m不一定小于n!!
                break;
            printf("%d ", myheap[0]);
            ago = myheap[0];
            if(tmp[i] >= ago)
            {
                myheap[0] = tmp[i];
            }
            else 
            {
                myheap[0] = myheap[last - 1];
                myheap[last - 1] = tmp[i];
                last--;
            }
            shiftdown(0);
        }
        return 0;
    }
    
    展开全文
  • 题目:编程实现置换选择排序 给定一组关键码序列,请模拟置换选择排序得到多个有序子序列。例如,关键码序列为(50、49、35、45、30、25、15、60、27),欲对其进行从小到大进行排序。假设内存中最多可以容纳3个记录...
  • 数据结构与算法习题 replacement selection sort(置换选择排序)
  • 置换选择排序算法详解(C语言实现)

    千次阅读 多人点赞 2020-03-18 17:48:24
    上一节介绍了增加 k-路归并排序中的 k 值来提高外部排序效率的方法,而除此之外,还有另外一条路可走,即减少初始归并段的个数,也就是本章第一节中提到的减小 m 的值。 m 的求值方法为:m=⌈n/l⌉(n 表示为外部...
  • 本文主要介绍了外排序算法中的选择置换排序和最佳归并树。
  • 在败者树一文中有提到,如果能一次性归并多个小文件,可以大大减少对文件...这正是这篇文章要介绍的——置换-选择排序。 过程如下: 假设内存工作区最多可容纳 n 条记录,则从大文件读取 n 条记录到内存工作区。筛选
  • 7.7.3讨论了如何使用m路归并来减少磁盘访问次数。...因此,必须探索新的算法俩生成初始归并段,这就是本节介绍的置换-选择算法。 设初始待排文件FI,初始归并段文件为FO,内存工作区为WA,内存工作区可
  • 置换选择排序实在树形选择排序的基础上的来的,她产生的归并段的长度是不同,。 置换选择排序的操作过程,可以查看书,这里只给出C++可运行成功代码, 注:这里也需要建立败者树,但这里建立败者树的过程和上一个...
  • 置换-选择排序-Java 实现说明代码和运行结果 说明 对外部排序进行优化。通过置换-选择排序算法,尽量减少归并段的数量。 置换-选择排序的相关理论,小伙伴们可以参考(包含 C++ 版本的实现): ...
  • 置换-选择排序
  • 置换-选择排序

    千次阅读 2013-09-12 13:28:02
    (2012-09-26 18:45:13) 转载▼ ...置换-选择排序 ...外部排序过程中,为了减少外存读写次数需要减小归并趟数(外部排序的过程中用到归并)...置换-选择排序就是一种减小n的、在外部排序中创建初始归并段时用到的算法
  • 本文主要讲外部排序中的败者树、置换选择排序、最佳归并树的算法原理,至于代码细节不做考虑。 原理 对于外部排序的顶层设计,我们大致可以归纳为三大步骤:首先,尽可能地读入数据到内存中进行内部排序,之后我
  • 外部排序置换-选择排序置换-选择排序算法思想: 通过减少归并段r来减少IO次数 置换-选择排序算法思想: minimax就是FO中的最后一个数据元素的大小 1、将工作区填满 2、从工作区选出最小的minimax,输出到FO 3、...
  • 置换选择排序的思想 是 将 归并段 尽量 变的 更大,而不是根据 内存 大小 限制在 固定的 大小。 这样 可以 利用赫夫曼树 来 进行 最优归并树,从而 使 外存 读写次数 最少。 下面给出 具体 代码:欢迎指出代码不足...
  • 本节内容 置换-选择 排序 王道考研/ 上上节知识回顾 可败者树减少 关键字对次数 可置换-选择排序进 步减少初始归并段数量 注按照本节介绍的法成的初始归并段若共 N 个记录内存作区可以容纳 L 个记录则初始归并段数量...
  • 文章目录外部排序归并排序法【第一阶段】初始归并段的生成(置换-选择排序方法)【可选步骤】最佳归并树的建立(哈夫曼树)【第二阶段】归并阶段(用败者树选择每个归并段的最小值)参考文章 外部排序 【为什么要...
  • 排序 —— 置换-选择算法

    千次阅读 2019-07-02 17:01:42
    生成初始归并段时,我们把含有 n 个记录的文件传入内存,按照给定的 内排序算法 或 置换-选择排序算法 划分成 m 个规模较小的有序的记录段。 内排序算法生成初始归并段的过程如下: 把含有 n 个记录的文件,按内存...
  • 石上真男人哈哈哈加油哦(☆-v-)O泡时间到~
  • 当需要对一个大文件进行排序时,计算机内存可能不够一次性装入所有数据,解决办法是归并。归并的大概做法是将大文件分为若干段,依次读入内存进行排序,...置换选择算法  先考虑如何生成顺串。我们知道,减少顺串...
  • { //在败者树ls和内存工作区wa上用置换选择排序求初始归并段,fi,fo两文件指针所指文件均已打开  int rc , rmax ;    Construct_Loser( ls , wa , fi ) ; //初建败者树  rc = rmax = 1 ; //rc指示当前生成...
  • 第11章 外部排序 -置换-选择排序 ——《数据结构》-严蔚敏.吴伟民版 源码使用说明 链接☛☛☛ 《数据结构-C语言版》(严蔚敏,吴伟民版)课本源码+习题集解析使用说明 课本源码合辑 链接☛☛☛ 《数据结构》课本...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,407
精华内容 8,562
关键字:

置换选择排序