C/C 知识点总结2

今天来说一下排序,我平时利用的排序多数是STL的sort排序,很少自己去写排序算法,但是既然是知识点总结,那肯定就少不了排序算法,所以今天把我自己整理的一些写过的算法和大家一起分享一下,望各位批评指正。

c++排序算法知识点总结:

1.排序算法是否稳定:
在排序算法执行的时候,当a,b相等的时候,若对a和b进行交换则不稳定,反之则是稳定的

2.时间复杂度与空间复杂度:
时间复杂度:对于排序数据的总的操作次数,反应当n(排序数据量)变化时,操作次数呈现什么规律
空间复杂度:是指排序算法在计算机内执行时,所需存储空间的度量,也是数据规模n的函数

3.排序方法解释及代码实现:

a.快速排序
快速排序是一种不稳定排序,也就是说在遇到相等项的时候位置可能会发生变化
时间复杂度:平均O(n*logn) 最坏O(n^2)
空间复杂度:O(1)

快速排序算法思想:快速排序采用的算法思想是一种分治思想,通过递归的调用来对数组循环进行排序

例:若是相对此数组进行排序int a[]={34,65,12,43,67,5,78,10,3,70}:

此数组array 数组量10 int len = 10;

1.第一次比较 假定a[0] 为基准数 定义int K = -1;K = a[0];

定义循环变量int i = 0,j = Len - 1;

开始比较:从前开始向后找比K值大的第一个数值找到了 a[1] a[0] = a[1]; 此时a[1] 可以被视为是一个坑 那么现在就要把这个坑填好
从后向前找比K值小的数值 找到了a[8] a[1] = a[8]

此时 i,j数值都发生了变化K依然是34 此时继续重复之前的步骤 直到i >= j时退出 此时将标记变量放置在a[i]中 自此a[i]左侧都是比他大的 右侧都是比他小的

2.开始递归循环左右两侧 左侧0到i 右侧i+1到Len-1 继续执行上述步骤

代码实现:vs2015 亲测可用

主要介绍:冒泡、快速、选择、归并

 

#include <iostream>

using namespace std;

//交换函数 采用后一种方式 比较高大上,这也是面试题中的一种,不采用中间变量交换数据
void Swap(int& a,int& b)
{
    //此时容易出现一个bug 就是当需要交换的值是同一个位置,即:一个值,而此时又是传递的引用 可能最后结果为零需要注意
    /*a = a + b;
    b = a - b;
    a = a - b;*/

    int temp = a;

    a = b;

    b = temp;
}

//冒泡排序
void BubbleSort(int a[],int Len)
{
    //为了保证程序的健壮性 需要加以判空
    if (a == NULL)
        return;

    //最外层循环次数,因为是从前向后开始排列,因此最后一次应该为小于(Len-1),即(Len-2),保证了a[Len-2]与a[Len-1]的最后一次比较
    for (int i = 0;i < Len -1;i++)
    {
        //从前向后开始升序排列 因为此时最大的数据已经进入最后部分,因此后续排列不用考虑最后部分,为了提高效率采用(Len-1-i)的形式
        for (int j = 0; j < Len - 1 - i; j++)
        {
            if (a[j] > a[j + 1])
                Swap(a[j], a[j + 1]);
        }
    }
}


//选择排序
/*选择排序其实与冒泡排序类似,找到大值或者小值后,将索引进行标记,通过引用的方式对两个值进行引用传递*/
void SelectSort(int a[10],int len)
{
    //索引标记变量
    int k = -1;
    //两层循环遍历
    for (int i = 0;i < len-1;i++)
    {
        k = i;
        for (int j = i;j < len-1;j++)
        {
            if (a[j+1] < a[k])
            {
                k = j + 1;
            }
        }
        Swap(a[k], a[i]);
    }

}


//快速排序
void quickSort(int s[], int l, int r)
{
    if (l < r)
    {
        int i = l, j = r, x = s[l];

        while (i < j)
        {
            while (i < j && s[j] >= x) // 从右向左找第一个小于x的数
                j--;

            if (i < j)
                s[i++] = s[j];

            while (i < j && s[i] < x) // 从左向右找第一个大于等于x的数
                i++;

            if (i < j)
                s[j--] = s[i];
        }

        s[i] = x;

        quickSort(s, l, i - 1); // 递归调用
        quickSort(s, i + 1, r);
    }
}


// 定义三个宏,分别用于求左孩子/右孩子/父结点的下标。
#define LEFT(i) (((i) << 1) + 1)
#define RIGHT(i) (((i)+1) << 1)
#define PARENT(i) (((i)-1) >> 1)

// 小于比较函数
bool less(int lhs, int rhs)
{
    return lhs < rhs;
}

// 大于比较函数
bool greate(int lhs, int rhs)
{
    return lhs > rhs;
}

typedef bool(*Comp)(int, int);


// 假设一个节点的左子树与右子树都满足堆的性质,而该节点不满足最大堆或最小堆的性质,该
// 函数实现调整节点位置,维护堆的性质。
// 输入参数分别表示: 堆的数组/数组长度/节点i的下标/表示比较的二元谓词
// 复杂度为O(logN).
void Heapify(int array[], int nLength_, int nIndex_, Comp CompFunc)
{
   if (array == nullptr || nIndex_ >= nLength_ || nIndex_ < 0 || CompFunc == nullptr)
       return;

   int _nLeft = LEFT(nIndex_);
   int _nRight = RIGHT(nIndex_);

   // 初始化最大值节点的下标;
   int _nLargest = nIndex_;
   if (_nLeft < nLength_ && !CompFunc(array[_nLargest], array[_nLeft]))
   {
       _nLargest = _nLeft;
   }
   if (_nRight < nLength_ && !CompFunc(array[_nLargest], array[_nRight]))
   {
        _nLargest = _nRight;
    }

    /* 此时不需要维护堆的性质,直接返回   */
    if (_nLargest == nIndex_)
    {
        return;
    }

    swap(array[nIndex_], array[_nLargest]);
    Heapify(array, nLength_, _nLargest, CompFunc);
}

// 使用一个数组建立一个最小堆或最大堆。
// 输入参数为:一维数组/数组的长度/表示比较的二元谓词,用于控制建最小堆还是最大堆
// 复杂度为O(N).
void BulidHeap(int array[], int nLength_, Comp CompFunc)
{
    if (array == nullptr || nLength_ <= 1 || CompFunc == nullptr)
        return;

    // 从最后一个元素的父节点开始调用Heapify()函数来建堆。
    for (int i = PARENT(nLength_ - 1); i >= 0; --i)
    {
        Heapify(array, nLength_, i, CompFunc);
    }
}


// 堆排序的函数
// 说明:1. 通过建立[最大堆]可以实现[从小到大]的排序;
//       2. 通过建立[最小堆]可以实现[从大到小]的排序
//       3. 堆排序为原址排序,它不需要借助额外的空间.(归并排序不是原址排序)
//       4. 堆排序的复杂度为O(NlogN).
//
// 堆排序的思想 (以从小到大排序说明):
//       第一步:建立一个最大堆;
//       第二步:把首元素与最后一个元素进行交换;
//       第三步:把堆的大小减1,对新的堆进行维护维的性质;
//       第四步:把首元素与倒数第二个元素进行交换;
//       第五步:把堆的大小减1,对新的堆进行维护维的性质;
//       .......
//
void HeapSort(int array[], int nLength_, Comp CompFunc)
{
    if (array == nullptr || nLength_ <= 1 || CompFunc == nullptr)
       return;

    BulidHeap(array, nLength_, CompFunc);
    for (int i = nLength_; i >= 2; /* 循环内 */)        // i表示当前堆的大小
    {
        swap(array[0], array[--i]);
        Heapify(array, i, 0, CompFunc);
    }
}


int _count = 0;//逆序对的个数

//函数作用:合并[left,mid][mid+1,right]
void Merge(int a[],int left,int mid,int right)
{    
    //两段区间的长度    
    int length1 = mid-left+1;    
    int length2 = right-mid;     
    //分配两段新的内存空间存储原内容    
    int *l1 = new int[length1];    
    int *l2 = new int[length2];     
    for (int i = 0; i < length1; ++i)    
    {        
        l1[i] = a[left+i];    
    }    
    
    for (int j = 0; j < length2; ++j)    
    {        
        l2[j] = a[j+mid+1];    
    }     
    
    //存入原内容之后,比较两个序列    
    int i = 0,j = 0;    
    int k = length1;    
    
    //比较两个序列的重合部分,进行排序    
    while (i<length1 && j<length2)    
    {        
        if (l1[i] < l2[j])        
        {            
            a[left++] = l1[i++];        
        }        
        else        
        {            
            a[left++] = l2[j++];            
            //因为l2[j]大于l1[i],所以l2[j]肯定大于[0,length-1]之中[0,i]之间的所有数,产生逆序对            
            if (l2[j] > l1[i])            
            {                
                _count +=  length1-i+1;            
            }                
        }    
    }    
    //两序列的剩余部分分别放于结尾    
    while (i<length1)    
    {        
        a[left++] = l1[i++];    
    }     
    
    while (j<length2)    
    {        
        a[left++] = l2[j++];    
    }     
    
    //分配的内存需要释放掉    
    delete []l1;    
    delete []l2;
}


void Merge_sort(int a[],int left,int right)
{    
    if (left < right)    
    {        
        int mid = (left+right)/2;
        //首先进行分区,然后递归操作        
        Merge_sort(a,left,mid);        
        Merge_sort(a,mid+1,right);
        
        //第一次将其分为两个区间,进行合并操作        
        Merge(a,left,mid,right);    
    }
}


int main()
{
    int a[] = {3,10,1,20,2,6,4,5,8,7};

    //int 为四字节 所以除以四
    int Count = sizeof(a) / 4;

    //时间复杂度O(n²) 空间复杂度O(1)
    //BubbleSort(a, Count);

    //时间复杂度O(n²) 空间复杂度O(1)
    //SelectSort(a, Count);

    //时间复杂度O(nlogn) 空间复杂度O(logn)
    //quickSort(a, 0, 9);

    //时间复杂度O(nlogn) 空间复杂度O(1)
    //HeapSort(a, 10, greate);

    //时间复杂度O(nlogn) 空间复杂度O(n)
    Merge_sort(a, 0, 9);

    //打印数组

    for (int i = 0;i < Count;i++)
    {
        printf("%d ",a[i]);
    }

    system("pause");

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值