时间复杂度,空间复杂度和稳定性

时间复杂度

指的是算法执行语句的次数(取最多次数的那个语句来表示)
在这里插入图片描述
ax =N(a>0,且a≠1) ==> x=logaN
注: Hash的查找的时间复杂度是1,原因“key-value键值对”,离散的
下面是3个例子关于while简单的理解一下时间复杂度

//第一个算法执行次数是20,常量所以是O(1)
int x = 1;
while (x<20)
{
	x++;
}

//第二个执行次数是n决定,O(n)
int x = 1;
while (x<n)
{
	x++;
}

// 执行次数由 c 和 n共同决定,c = 1 时,O(1),c != 1时,O(n)
int x = 1;
c = c or 1;
while (x<n && c != 1)
{
	x++;
}

再来看一个简单插入排序

#include <stdio.h>

// 分类 ------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- 最坏情况为输入序列是降序排列的,此时时间复杂度O(n^2)
// 最优时间复杂度 ---- 最好情况为输入序列是升序排列的,此时时间复杂度O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定

int main()
{
    int A[] = { 6, 5, 3, 1, 8, 7, 2, 4 };// 从小到大插入排序
    int n = sizeof(A) / sizeof(int);
    int i, j, get;

    for (i = 1; i < n; i++)             // 类似抓扑克牌排序
    {
        get = A[i];                     // 右手抓到一张扑克牌
        j = i - 1;                      // 拿在左手上的牌总是排序好的
        while (j >= 0 && A[j] > get)    // 将抓到的牌与手牌从右向左进行比较
        {
            A[j + 1] = A[j];            // 如果该手牌比抓到的牌大,就将其右移
            j--;
        }
        A[j + 1] = get;// 直到该手牌比抓到的牌小(或二者相等),将抓到的牌插入到该手牌右边(相等元素的相对次序未变,所以插入排序是稳定的)
    }
    printf("插入排序结果:");
    for (i = 0; i < n; i++)
    {
        printf("%d ", A[i]);
    }
    printf("\n");
    return 0;
}

改进一下,第二层采用二分查找法

#include <stdio.h>

// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(n^2)
// 最优时间复杂度 ---- O(nlogn)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定

int main()
{
    int A[] = { 5, 2, 9, 4, 7, 6, 1, 3, 8 };// 从小到大二分插入排序
    int n = sizeof(A) / sizeof(int);
    int i, j, get, left, right, middle;
    
    for (i = 1; i < n; i++)                 // 类似抓扑克牌排序
    {
        get = A[i];                         // 右手抓到一张扑克牌
        left = 0;                           // 拿在左手上的牌总是排序好的,所以可以用二分法
        right = i - 1;                      // 手牌左右边界进行初始化
        while (left <= right)               // 采用二分法定位新牌的位置
        {
            middle = (left + right) / 2;
            if (A[middle] > get)
                right = middle - 1;
            else
                left = middle + 1;
        }
        for (j = i - 1; j >= left; j--)    // 将欲插入新牌位置右边的牌整体向右移动一个单位
        {
            A[j + 1] = A[j];            
        }
        A[left] = get;                    // 将抓到的牌插入手牌
    }
    printf("二分插入排序结果:");
    for (i = 0; i < n; i++)
    {
        printf("%d ", A[i]);
    }
    printf("\n");
    return 0;
}

再改进一下,成为希尔排序

#include <stdio.h>  

// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- 根据步长序列的不同而不同。已知最好的为O(n(logn)^2)
// 最优时间复杂度 ---- O(n)
// 平均时间复杂度 ---- 根据步长序列的不同而不同。
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 不稳定

int main()
{
    int A[] = { 5, 2, 9, 4, 7, 6, 1, 3, 8 };// 从小到大希尔排序
    int n = sizeof(A) / sizeof(int);
    int i, j, get;
    int h = 0;
    while (h <= n)                          // 生成初始增量
    {
        h = 3*h + 1;
    }
    while (h >= 1)
    {
        for (i = h; i < n; i++)
        {
            j = i - h;
            get = A[i];
            while ((j >= 0) && (A[j] > get))
            {
                A[j + h] = A[j];
                j = j - h;
            }
            A[j + h] = get;
        }
        h = (h - 1) / 3;                    // 递减增量
    }
    printf("希尔排序结果:");
    for (i = 0; i < n; i++)
    {
        printf("%d ", A[i]);
    }
    printf("\n");
    return 0;
}

空间复杂度

指对一个算法在运行过程中临时占用存储空间,看你开辟的临时空间就好了。

稳定性

排序稳定性

指的是针对相同数值,在排序前后是否有发生变化的可能。一般举返例来证明

这只是一个例子来说明稳定性,大家普遍说冒泡是稳定的,条件换成“>=”导致算法不稳定,建议不要

下面是个简单冒泡排序来排序{1,1,1,1,1,1,2, 2,1}

for (int j = 0; j < n - 1; j++)           
    {
        for (int i = 0; i < n - 1 - j; i++)   
        {
            if (A[i] > A[i + 1])            // 如果条件改成A[i] >= A[i + 1],则变为不稳定的排序算法
            {
                exchange(A, i, i + 1);        
            }
        }
    }

数值稳定性

讨论的是计算机编程中,由于四舍五入等导致的结果偏差。

  • 尽量减少运算次数
  • 加法运算时,避免大数加小数
  • 避免两个相近的数相减
  • 避免小数做除法或者大数做乘法
常见排序总结

在这里插入图片描述
编程排序算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值