数据结构-常用排序原理及代码

本文深入讲解了常见的排序算法,包括插入排序、希尔排序、冒泡排序、快速排序、选择排序、堆排序、归并排序等,详细阐述了各自的原理、实现关键及代码模板,帮助读者全面理解各种排序算法的特点与应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进一步的原理可以看这篇博文还有动画哦

https://blog.csdn.net/yushiyi6453/article/details/76407640

除了归并排序,其他优化排序方法,都不稳定。

大部分排序的空间复杂度是O(1),快速排序因为每回要送回一个中枢轴值,所以空间复杂度是O(logN~N),归并排序因为需要一次放入另一个数组,所以需要一个等大的空间,空间复杂度是O(N)。

1插入排序

原理:在有序序列中找到插入的位置;

实现关键:从后往前,便于位置调整;设置哨兵位,减少比较次数

算法代码:

template<class T>
void InsertSort(vector<T> List){
    for(int i = 2;i<List.size();i++)
    {
        if(LessT(List[i],List[i-1])){
            List[0] = List[i];
            List[i] = List[i-1];
            for(int j = i-2;LessT(List[0],List[j]);--j){
                List[j+1] = List[j];
            }
            List[j+1] = List[0];
        }
    }
}

2希尔排序

原理:原序列按照某个“增量”划分为一个个子序列,每次循环后增量序列基本有序,逐步缩小增量为1。

增量序列的选取很重要,研究表明增量序列设置为,比较合适,时间复杂度是

实现关键:按照增量序列循环,然后完成字节间插;

template<class T>
void shellInsert(vector<T>& vec,int dlta){
    for(int i = dlta+1;i<vec.size();++i){
        if(LessT(vec[i],vec[i-dlta]))
            vec[0] = vec[i];
        for(int j = i-dlta; j>0&&LessT(vec[0],vec[j]; j -= dlta){
            vec[j+dlta] = vec[j];
        }
        vec[j+dlta] = vec[0];
    }
}

template<class T>
void shellSort(vector<T>& vec,vector<int> addDlta){
    for(int key = 0;key<addDlta.size();++key){
        shellInsert(vec,addDlta[key]);
    }
}

空间复杂度是O(1);

3冒泡排序

思想:第一次排序使得最小的数上浮,第k次排序使得第k小的数上浮

实现关键:如果是逆序则交换,注意第二遍循环反着来

template<class T>
void BubbleSort(vector<T>& vec){
    for(int i = 0;i<vec.size();++i){
        for(int j = vec.size()-1; j > i;--j)
        {
            if(vec[j]<vec[j-1]){
                int temp = vec[j];
                vec[j] = vec[j-1];
                vec[j-1] = temp;
            }
        }
    }
}

时间复杂度O(N*N),空间复杂度O(1),算法稳定,实现简单

4快速排序

思想:通过一趟排序将待排序记录分割成独立的两个部分,其中一个部分的记录都比另外一个部分小,分别对两个记录继续排序以达到整个序列有序

实现关键:要设置两指针,一个指向前一部分记录,一个指向后一部分记录。关键是low<high。

template<class T>
int partition(vector<T>&vec,int low,int high){
    while(low<high)
    {
        while(low<high&&LessT(pivotKey,vec[high]))--high;
        vec[low] = vec[high];
        while(low<high&&LessT(vec[low],pivotKey))++low;
        vec[high] = vec[low];
    }
    vec[low] = pivotKey;
    return low;
}
template<class T>
void partQSort(vector<T>& vec,const int low,const int high){
    if(low > high) return;
    int pivot = partition(vec,low,high);
    partQSort(vec,low,pivot-1);
    partQSort(vec,pivot+1,high);
}
template<class T>
void qSort(vector<T>& vec){
    partQSort(vec,0,vec.size()-1);
}

由于递归需要在栈中存储值,所以空间复杂度就递归函数的调用次数

5选择排序

思想:每一趟在剩余的n-i+1个数中找到第i小的数的位置,和第i个数交换

实现的关键:和冒泡法的区别,冒泡法是倒着

template<class T>
void SelectSort(vector<T>& vec){
    for(int i = 0;i < vec.size();++i){
        int min = i;
        for(int j = i+1;vec.size();++j)//这里注意和冒泡算法的区别
        {
            if(LessT(vec[j],vec[min]))
                min = j;
        }
        if(min!=i)swap(vec[i],vec[min]);
    }
}

(模板类必须显式实体化,函数类都可以)

时间复杂度是O(N*N),空间复杂度是O(1);

6堆排序

思想:如前面heap相关算法所提到的sort_heap,就先make_heap然后不断的pop_heap(就是先把对顶的是移到末位,在调整为堆);

Template<class T>
void HeapAdjust(vector<T> vec,int root,int end){
    int tempRootVal = vec[root];
    for(int child = 2*root+1;child<=end;child = 2*child+1){
        if(child<end && LessT(vec[child],LessT[child+1]))child=child+1;
    //这里注意不要越界,添加限制条件
        if(LessT(vec[child],tempRootVal))break;//这里主要比较的双方
        vec[root] = vec[child]; root = child;
    }
    vec[root] = tempRootVal;
}
Template<class T>
void HeapSort(vector<T> vec){
    for(int root = vec.size()/2-1;root>=0;--root){
        HeapAdjust(vec,root,vec.size()-1);
    }
    for(int end = vec.size()-1;end>0;--end){
        swap(vec[0],vec[end]);
        HeapAdjust(vec,0,end-1);
    }
}

时间复杂度是

7归并排序

思想:2路归并的关键是将一维数组中前后相邻的有序序列合并为一个有序序列。

template<class T>
void Merge(vector<T> partSq, vector<T>& sqVec, int first, int mid, int last) {
	int forNum = first, behindNum = mid + 1;
	int num = first;
	while (forNum <= mid && behindNum <= last) {
		if (LessT(partSq[behindNum], partSq[forNum]))sqVec[num++] = partSq[behindNum++];
		else {
			sqVec[num++] = partSq[forNum++];
		}
	}
	while (forNum <= mid)sqVec[num++] = partSq[forNum++];
	while (behindNum <= last)sqVec[num++] = partSq[behindNum++];
}

template<class T>
void MSort(vector<T>& srcVec, vector<T>& sqVec, int first, int last) {
	if (first > last) return;
	if (first == last) sqVec[first] = srcVec[last];
	else {
		int mid = (first + last) / 2;
		MSort(sqVec, srcVec, first, mid);
		MSort(sqVec, srcVec, mid + 1, last);
		Merge(srcVec, sqVec, first, mid, last);
	}
}

template<class T>
void MergeSort(vector<T>& sVec) {
    vector<T> sVec_copy
	MSort(sVec_copy, sVec, 0, sVec.size() - 1);
}

先让相邻两个部分有序,再将有序序列合并。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值