复杂度与冒泡排序、二分查找

总结:
时间复杂度:衡量算法快慢的标准刻度
在CPU单位时间运行指令数恒定的情况下,求算法运行指令数和数据规模n的关系  F(n)
不求甚解

大O渐进法:
1)只保留最高次项
2)最高次项的系数化为1
时间复杂度不是绝对意义上的快慢,运行时间的变化趋势。

常见的时间复杂度:
O(1)  O(log(n)) O(n) O(n*log(n))  O(n^2)

特殊的时间复杂度:
二分查找
递归函数--画框框、数框框  了解


空间复杂度
大O渐进表示法
数据规模是n的情况下,
1)额外使用的空间大小(不考虑输入/输出中用到的空间)
2)常见形式
i.  int[] array=new int[和n的关系]; 
	int[] array=new int[255];  S(n)=O(n)
ii.递归函数  调用栈

一、数据结构与算法

数据结构:存储、组织数据的形式。
算法:一系列步骤。

二、复杂度

1.含义

是衡量算法好坏的刻度尺(标杆)
2.衡量的角度:

          快/慢--时间复杂度    ****
          使用空间的角度(内存)--空间复杂度
如:快慢:冒泡排序  其它排序  
3.拿运行时间衡量怎么样?

不好  原因:1)事后衡量  2)影响因素太多(如当时系统上打开程序的多少)

4.衡量算法快慢的标准

是算法运行的指令个数(基本指令)。这里有个前提,即:CPU每秒运行的指令数是恒定的。

5.大O渐进法

数据规模  n
for(int i=0;i<n;i++){}
运行指令个数F(n) 和数据规模n有关。n越大,F(n)越大。

衡量算法好坏,不需要精确衡量。-->大O渐进表示法
O(F(n))=
1)只保留最高次项
2)最高次项的系数变为1

//在array数组中查找value
int search(int[] array,int value){
	for(int i=0;i<array.length;i++){
		if(array[i]==value){
			return i;
		}
	}
    return -1;//没有找到
}
3   5   2   7   9   6   4
最好        平均         最坏
用平均/最坏来衡量

6.两个例子

例1:
void count(int m,int n){
int count=0;
for(int i=0;i<m;i++){
count++;
}
for(int i=0;i<n;i++){
count++;
}
System.out.println(count);
}
O(n)=O(m+n)
例2:
int String.indexOf(int ch);
数据规模:String的长度  O(n)

7.常见的时间复杂度
O(1)
O(log(n))
O(n)
O(n*log(n))
O(n^2)

8.递归函数的时间复杂度

做法:画框框,找框框的个数

例1:n的阶乘
long Factorial(int n){
    return n>2?Factorial(n-1)*n:n;
}
这个递归函数有两个出口:
1)n=1或n=2-->返回1或2
2)n>2-->求(n-1)!  递归n次。
因此,T(n)=O(n)

例2 斐波那契数列
long Fabonacci(int N){
    return N<2?N:Fabonacci(N-1)+Fabonacci(N-2);
}
两个出口:
1)N=1-->返回1
2)N>=2-->求Fabonacci(N-1)+Fabonacci(N-2)

举例说明:

三、冒泡排序和二分查找的时间复杂度

1.冒泡排序(升序)

冒泡过程:两个相邻的数依次比较,保证大的数在后面。
减治算法:每次处理都减少一个数,剩下的数用同样的方式处理。冒泡的过程就相当于减治算法。

外部循环表示比较的轮数,共比较array.length次。更优化的方式是array.length-1。

    //冒泡排序
   public static  void bubbleSort(int[] array) {
       for (int i = 0; i < array.length; i++) {
           for (int j = 0; j < array.length - 1 - i; j++) {
//保证相邻的两个数,最大的在后面。
               if (array[j] > array[j + 1]) {
                   int temp = array[j];
                   array[j + 1] = array[j];
                   array[j] = temp;
               }
           }
       }
   }

时间复杂度:F(n)=(n-1)+(n-2)+....+1=(n-1+1)(n-1)/2=(n^2-n)/2,因此冒泡排序的时间复杂度为O(n)=n^2。

冒泡排序的优化

每次冒泡之前,假设数组已经有序。如:2 3 4 5 6 7 9。可以在每轮排序前设置标志位假设已经是有序的,经过一轮排序后,如果标志位未发生变化,则说明整个数组是有序的,就不必进行后面的排序了。

for(int i=0;i<array.length;i++){
//每次冒泡之前,假设数组已经有序。
	int sorted=true;
//一次冒泡的过程,保证最大的数被推到最后。
	for(int j=0;j<array.length-1-i;j++){
//保证相邻的两个数,最大的在后面。
	if(arr[j]>arr[j+1]){
	int temp=arr[j];
	arr[j+1]=arr[j];
	arr[j]=temp;
	sorted=false;
	}
    }
    //如果过程一次交换都没有发生过,假设有序成立。
    if(sorted==true){
    break;
    }
}

2、二分查找

前提:数组有序     

查找方式:两种方式:[left,right)  [left,right](其中, left=区间的左边界   right=区间的右边界)

中间位置的下标:int m=(left+right)/2
[left,right)  区间内只有一个数:right=left+1  没有数 left==right

//二分查找
    [left,right]
    public static int binarySearch1(int[] array, int value) {
        int left = 0;
        int right = array.length - 1;//5 []

        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (array[mid] == value) {
                return mid;
            }
//说明value在(mid,right],那么left=mid+1
            if (array[mid] < value) {
                left = mid + 1;
            }
//说明value在[left,mid),那么right=mid-1
            if (array[mid] > value) {
                right = mid-1;
            }
        }
        return -1;
    }
    //[left,right)
    public static int binarySearch2(int[] array,int value){
        int left=0;
        int right=array.length;
//区间内还有一个数,就继续找,没有数就可以停下。
        while(left<right){
            int m=left+(right-left)/2;
            if(value==array[m]){
                return m;
            }
            if(value>array[m]){
                left=m+1;
            }
            if(value<array[m]){
                right=m;
            }
        }
        return -1;
    }

二分查找的时间复杂度:
长度变化:n  n/2  n/4  ..... 1
1*2*2*2*...*2=n  ->2^a=n-->a=log(n)
二分查找的时间复杂度T(n)=O(log(n))

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值