22计算机408考研—数据结构—排序(详解加例题)

Posted 发呆哥o_o ....

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了22计算机408考研—数据结构—排序(详解加例题)相关的知识,希望对你有一定的参考价值。

2022计算机考研408—数据结构—排序
手把手教学考研大纲范围内的排序
22考研大纲数据结构要求的是C/C++,笔者以前使用的都是Java,对于C++还很欠缺,
如有什么建议或者不足欢迎大佬评论区或者私信指出

Talk is cheap. Show me the code.
理论到处都有,代码加例题自己练习才能真的学会

排序过程步骤显示

文末投票:下篇22考研数据结构的博客写什么(欢迎评论区指出)

排序定义
冒泡排序
直接插入排序
二分插入排序
希尔排序⭐
快速排序
二路归并排序⭐
基数排序(附加计数排序)⭐
简单选择排序
堆排序⭐⭐

排序

排序的基本概念

顾名思义,给一个无序数组的值进行顺序存储

原数组:2 3 1 5 6 4 8 9 7
排序后:1 2 3 4 5 6 7 8 9

冒泡排序

思路
从头到尾每两个相邻的元素,进行比较,前面的比后面的大就进行交换
循环一遍后,数组元素最大的就到了最后面,
第二次循环的时候,就可以不循环到最后一个了,最后一个上次循环已经是整个数组最大的值了
然后把这次最大的放到倒数第二个元素,
第三次循环的就可以忽略最后两个元素
以此类推,全部循环后,即可完成排序

#include <iostream>
#include <vector>

using namespace std;


void bubbleSort(vector<int> &num);
int main() 
    int n;    //n为将要输入的数组长度
    cin >> n;   //输入n   cin方法需要上面使用std
    vector<int> num;    //定义vector  记得上面导入vector
    int temp;   //temp为输入vector时的中间变量
    for (int i = 0; i < n; i++) 
        cin >> temp;            //输入
        num.push_back(temp);
    
    bubbleSort(num);    //调用自定义的排序方法
    cout << "排序后" << "\\n";
    for (int i = 0; i < num.size(); i++) 
        cout << num[i] << " ";     //输出
    
    return 0;


void bubbleSort(vector<int> &num) 
    for (int i = 0; i < num.size(); i++) 
        for (int j = 0; j < num.size() - i; j++) 
            if (num[j] > num[j + 1]) 
//                int temp = num[j];
//                num[j] = num[j + 1];
//                num[j + 1] = temp;

                num[j] ^= num[j + 1];   //两两相邻交换   上面注释代码的功能与此功能相等
                num[j + 1] ^= num[j];
                num[j] ^= num[j + 1];


            
        
        
        //每次循环都把数组的变动输出出来
        for (int j = 0; j < num.size(); j++) 
            cout << num[j] << " ";
        
        cout << "\\n";
    


//冒泡排序的变种

#include <iostream>
#include <vector>

using namespace std;


void bubbleSort(vector<int> &num);
int main() 
    int n;    //n为将要输入的数组长度
    cin >> n;   //输入n   cin方法需要上面使用std
    vector<int> num;    //定义vector  记得上面导入vector
    int temp;   //temp为输入vector时的中间变量
    for (int i = 0; i < n; i++) 
        cin >> temp;            //输入
        num.push_back(temp);
    
    bubbleSort(num);    //调用自定义的排序方法
    for (int i = 0; i < num.size(); i++) 
        cout << num[i] << " ";     //输出
    
    return 0;


void bubbleSort(vector<int> &num) 
    int flag = 1;       //flag用来判断,如果本次循环没有进行交换,该数组为有序数组
    int arrBoundary  = num.size() - 1;  //用来记录上一次循环最后一次交换位置,后面没有交换的是有序的
    int largestSwapIndex = 0;           //记录最后一次交换的位置
    for (int i = 0; i < num.size(); i++) 
        flag = 1;
        for (int j = 0; j < arrBoundary ; j++) 
            if (num[j] > num[j + 1]) 
                int temp = num[j];
                num[j] = num[j + 1];
                num[j + 1] = temp;

                flag = 0;               //发生交换就改为0
                largestSwapIndex = j;   //交换位置就给largestSwapIndex
            

        
        arrBoundary = largestSwapIndex; //把当前循环交换的最后一个下标给arrBoundary
        if (flag)      //如果本次循环没有交换任何值,证明当前数组为有序数组
            break;
        
    




直接插入排序

思路
插入 == 把数插进去
也是两层循环
数组num

第一层循环从下标为1的值开始,循环变量为i
第二层循环就是把第一层的值拿出来,然后从第i-1个向前循环,找到第一个小于 num[i] 的值,
这个值的下标如果是j-1的话,那么 num[j] 就是第一个大于 num[i] 的值
num[i] 用一个变量 temp 保存一下
把下标为j到i-1的值依次向后移动一位,也就是说下标j到i-1的值移动到j+1到i
然后把 temp(原num[i])放到下标为j的地方(之前的num[j]已经移动到num[j+1]了),

按照这种排序,每次循环的都是i之前的,i之前的元素都是顺序存储的,
文字表述的不清楚的可以看每次循环i更改后数组的元素情况

#include <iostream>
#include <vector>

using namespace std;

void insertSort(vector<int> &num);
int main() 
    int n;    //n为将要输入的数组长度
    cin >> n;   //输入n   cin方法需要上面使用std
    vector<int> num;    //定义vector  记得上面导入vector
    int temp;   //temp为输入vector时的中间变量
    for (int i = 0; i < n; i++) 
        cin >> temp;            //输入
        num.push_back(temp);
    
    insertSort(num);    //调用自定义的排序方法
    cout << "排序后" << "\\n";
    for (int i = 0; i < num.size(); i++) 
        cout << num[i] << " ";     //输出
    
    return 0;


void insertSort(vector<int> &num) 
    for (int i = 1; i < num.size(); i++) 
        int temp = num[i];      //保存一下num[i]
        int j;
        //从num[j]向前开始找,一直找到比temp(原num[i])小的数就结束
        //在循环过程中的数都比temp大的,不断地把temp大的数往后移动一位
        //由此可得,等找到num[j]<=temp的时候,循环已经结束了
        // 但是他的上一个,也就是num[j+1]的值已经移动到num[j+2]了
        for (j = i - 1; j >= 0 && num[j] > temp; j--) 
            num[j + 1] = num[j];
        
        //可以直接把temp放到num[j+1],
        num[j + 1] = temp;
        //每次循环都可以把num[i]以及之前的数值排序好

        //每次循环都把数组的变动输出出来
        for(j = 0; j < num.size(); j++) 
            cout << num[j] << " ";
        
        cout <<"\\n";

    


运行截图:

二分插入排序

思路
二分插入和简单插入基本类似
不过是在寻找插入位置的时候不在采用简单插入的循环查找,而是使用二分查找
减少比较的次数,提升效率

#include <iostream>
#include <vector>

using namespace std;

void binInsertSort(vector<int> &num);
int main() 
    int n;    //n为将要输入的数组长度
    cin >> n;   //输入n   cin方法需要上面使用std
    vector<int> num;    //定义vector  记得上面导入vector
    int temp;   //temp为输入vector时的中间变量
    for (int i = 0; i < n; i++) 
        cin >> temp;            //输入
        num.push_back(temp);
    
    binInsertSort(num);    //调用自定义的排序方法
    cout << "排序后" << "\\n";
    for (int i = 0; i < num.size(); i++) 
        cout << num[i] << " ";     //输出
    
    return 0;


void binInsertSort(vector<int> &num) 
    for (int i = 1; i < num.size(); i++) 
        int temp = num[i];          //保存临时变量
        int left = 0;               //使用二分法找到插入的位置left  使得num[left]<temp<num[left+1]
        int right = i - 1;
        while (left <= right) 
            int mid = (left + right) / 2;
            if (num[mid] > temp) 
                right = mid - 1;

             else 
                left = mid + 1;
            
        
        for (int j = i - 1; j >= left; j--) 
            num[j + 1] = num[j];       //把left右面的值全部右移一位,
        
        num[left] = temp;               //把temp放到num[left]的位置

        //每次循环都把数组的变动输出出来
        for (int j = 0; j < num.size(); j++) 
            cout << num[j] << " ";
        
        cout << "\\n";

    



希尔排序

思路

希尔排序其实可以看做是插入排序的变种
插入排序是循环到某个元素就像前找合适的位置,把当前元素到合适位置的值都要向后移动一遍
插入排序对于有序的数组,比较和移动的次数都比较少
希尔排序就是把插入排序进行分组化

分组是按照长度每次除2分的,这样最后一次肯定是一个组一个元素,就相当于最原始的插入排序了
而他前面做的按组排序就是为了让这个数组变成一个有大概顺序的数组,使后面的插入排序能减少比较和移动的次数

按下图为例子,数组长度15  第一次按照7个增量分组,第二次按照3个增量,第三次按照1个增量分组

第一次循环的增量为7
第一次是下标 00+7比较   11+7比较  ……   77+7比较
第一次循环完,这些位置上有了个大概的顺序

第二次循环的增量为3
第二次是下标 036912比较   1471013   2581114
第二次循环完,这些位置上有了大概的顺序

第三次循环的增量为1
就相当于简单的插入排序

希尔排序的精髓就在于,对于一个大概有序的数组,插入排序的比较和移动次数都比较少

PS:小编作图能力有限,上图是当来的

//除main方法外的其他cout输出都是为了让读者更清楚的了解每次循环后进行排序的下标
#include <iostream>
#include <vector>

using namespace std;

void shellSort(vector<int> &num);

int main() 
    int n;    //n为将要输入的数组长度
    cin >> n;   //输入n   cin方法需要上面使用std
    vector<int> num;    //定义vector  记得上面导入vector
    int temp;   //temp为输入vector时的中间变量
    for (int i = 0; i < n; i++) 
        cin >> temp;            //输入
        num.push_back(temp);
    
    shellSort(num);    //调用自定义的排序方法
    cout << "\\n\\n排序后" << "\\n";
    for (int i = 0; i < num.size(); i++) 
        cout << num[i] << " ";     //输出
    
    return 0;


void shellSort(vector<int> &num) 
    int len = num.size();
    for (int d = len / 2; d > 0; d/=2)     //按照增量分组,增量每次/2
        cout << "\\n\\n增量为" << d;
        for (int i = d; i < len; i++)      //类似插入排序,每次都比较i之前的,
            cout << "\\n此次排序的下标为:" << i;
            for (int j = i - d; j >=0; j-=d) 
                cout << " " << j;
                //这里i-d其实也就是从前面开始,
                // j每次都是j-=d,因为我们是按照相同增量分为一组的
                                                // 对比上图更容易理解
                if (num[j] > num[j + d])   //只要前面的比后面的大,就交换位置
                    int temp = num[j];
                    num[j] = num[j + d];
                    num[j + d] = temp;
                
            

            //每次循环都把数组的变动输出出来
            cout << "\\n";
            for (int j = 0; j < num.size(); j++) 
                cout << num[j] << " ";
            

        
    

快速排序

思路
从未排序的数组中,一个一个的寻找,寻找当前值应该在排序后数组的位置,
以此类推,把每个值的位置都确定了以后,此数组就变成了排序后的数组
也是分段进行确定某个值最终排序后的下标

先选取第一个值,用一个临时变量保存这个值,然后双指针i表示这段范围的开头,j这段范围的结尾    
	j负责从后向前找小于临时变量的值,找到以后就把j的值放到i那,
		此时j位置就空出来了,我们当作把临时变量的值放到j这里
	i负责从前向后找大于临时变量的值,找到后就放到j那里,
		此时i位置就空出来了,我们同样当作把临时变量的值放到i这里
	不断循环这两步的操作,
	i是从前向后,j是从后向前
	循环结束的条件就是i==j  也就是临时变量排序后数组的位置,
	按照这种排序方式,结束后,
		比临时变量小的都在临时变量左边(左边不一定是排好序的),
		比临时变量大的都在临时变量右边(右边不一定是排好序的),
		也就是说临时变量当前的下标就是排序后的下标			
	
当前临时变量的位置确定好以后,我们可以分为前半部分和后半部分继续这种操作
以此类推,当每个值最终排序后的位置都确定的时候,此数组为排序后的数组		

下图为确定好一个值的最终位置的排序图

临时变量为50,左指针low,右指针high

右指针找到20比临时变量小,交换两个值

左指针找到90比临时变量大,交换两个值

右指针找到40比临时变量小,交换两个值位置

左指针找到70比临时变量小,交换两个值的位置

右指针左移与左指针重合,当前位置为50排序后的最终位置

我们发现,左边的数都比50小,右边的数都比50大,
当前数的位置就是排序后当前数的位置 然后在把左边的数组按照这种方法,右边的数组按照这种方法
以此类推每个值的最终下标都确定下来了,数组为排序后的数组
PS:图仍然是某度当来的o( ̄▽ ̄)ブ

#include <iostream>
#include <vector>

using namespace std;


void quickSort(vector<int> &num, int left, int right);

int main() 
    int n;    //n为将要输入的数组长度
    cin >> n;   //输入n   cin方法需要上面使用std
    vector<int> num;    //定义vector  记得上面导入vector
    int temp;   //temp为输入vector时的中间变量
    for (int i = 0; i < n; i++) 
        cin >> temp;            //输入
        num.push_back(temp);
    
    quickSort(num, 0, num.size() - 1);    //调用自定义的排序方法
    cout << "\\n\\n排序后" << "\\n";
    for (int i = 0; i < num.size(); i++) 
        cout << num[i] << " ";     //输出
    
    return 0;


void quickSort(vector<int> &num, int left, int right) 
  

以上是关于22计算机408考研—数据结构—排序(详解加例题)的主要内容,如果未能解决你的问题,请参考以下文章

22计算机408考研—数据结构—图

2022计算机考研408—数据结构—排序

22计算机408考研—数据结构—线性表栈队列数组

22计算机408考研—数据结构—线性表栈队列数组

22计算机408考研—数据结构—线性表栈队列数组

22计算机408考研—数据结构—线性表栈队列数组