北京大學C語言學習第13天

程序或算法的時間複雜度
一個程序或算法的時間效率,也稱“時間複雜度”,有時簡稱“複雜度”
複雜度常用大的字母O和小寫字母n來表示,比如O(n),O(n2
)等。n代表問題
的規模
時間複雜度是用算法運行過程中,某種時間固定的操作需要被執行的次數和n
的關係來度量的。在無序數列中查找某個數,複雜度是O(n)
7
程序或算法的時間複雜度
一個程序或算法的時間效率,也稱“時間複雜度”,有時簡稱“複雜度”
複雜度常用大的字母O和小寫字母n來表示,比如O(n),O(n2
)等。n代表問題
的規模
時間複雜度是用算法運行過程中,某種時間固定的操作需要被執行的次數和n
的關係來度量的。在無序數列中查找某個數,複雜度是O(n)
計算複雜度的時候,只統計執行次數最多的(n足夠大時)那種固定操作的次數
。比如某個算法需要執行加法n2次,除法n次,那麼就記其複雜度是O(n2
)的。
8
插入排序
void InsertionSort(int a[] ,int size)
{
for(int i = 1;i < size; ++i ) {
//a[i]是最左的無序元素,每次循環將a[i]放到合適位置
for(int j = 0; j < i; ++j)
if( a[j]>a[i]) {
//要把a[i]放到位置j,原下標j到 i-1的元素都往後移一個位子
int tmp = a[i];
for(int k = i; k > j; --k)
a[k] = a[k-1];
a[j] = tmp;
break;
}
}
} //複雜度O(n2)
9
程序或算法的時間複雜度
如果複雜度是多個n的函數之和,則只關心隨n的增長增長得最快的那個函數
O(n3+n2
) => O(n3
)
O(2n+n3
) => O(2n
)
O(n! + 3n
) => O(n!)
10
程序或算法的時間複雜度
 如果複雜度是多個n的函數之和,則只關心隨n的增長增長得最快的那個函

O(n3+n2
) => O(n3
)
O(2n+n3
) => O(2n
)
O(n! + 3n
) => O(n!)
常數複雜度:O(1) 時間(操作次數)和問題的規模無關
對數複雜度:O(log(n))
線性複雜度:O(n)
多項式複雜度:O(nk
)
指數複雜度:O(an )
階乘複雜度:O(n! ) 11
程序或算法的時間複雜度
 複雜度有“平均複雜度”和“最壞複雜度”兩種。
兩者可能一致,也可能不一致
12
程序或算法的時間複雜度
在無序數列中查找某個數(順序查找) O(n)
平面上有n個點,要求出任意兩點之間的距離 O(n2
)
插入排序、選擇排序、冒泡排序 O(n2
)
快速排序 O( n*log(n))
二分查找 O(log(n))
13
二分查找
信息科學技術學院
甘肅張掖平山湖大峽谷
二分查找
A心裏想一個1-1000之間的數,B來猜,可以問問題,A只能回答是或否。怎
麼猜才能問的問題次數最少?
是1嗎?是2嗎?…是999嗎? 平均要問500次
大於500嗎?大於750嗎?大於625嗎? …每次縮小猜測範圍到上次的一半,
只需要 10次
15
寫一個函數BinarySeach,在包含size個元素的、從小到大排序的int數組a裏查找元素
p,如果找到,則返回元素下標,如果找不到,則返回-1。要求複雜度O(log(n))
int BinarySearch(int a[],int size,int p)
{
int L = 0; //查找區間的左端點
int R = size - 1; //查找區間的右端點
while( L <= R) { //如果查找區間不爲空就繼續查找
int mid = L+(R-L)/2; //取查找區間正中元素的下標
if( p == a[mid] )
return mid;
else if( p > a[mid])
L = mid + 1; //設置新的查找區間的左端點
else
R = mid - 1; //設置新的查找區間的右端點
}
return -1;
} //複雜度O(log(n))
16
二分查找函數
寫一個函數LowerBound,在包含size個元素的、從小到大排序的int數組a裏查找比給
定整數p小的,下標最大的元素。找到則返回其下標,找不到則返回-1

int LowerBound(int a[],int size,int p) //複雜度O(log(n))
{
int L = 0; //查找區間的左端點
int R = size - 1; //查找區間的右端點
int lastPos = -1; //到目前爲止找到的最優解
while( L <= R) { //如果查找區間不爲空就繼續查找
int mid = L+(R-L)/2; //取查找區間正中元素的下標
if(a[mid]>= p)
R = mid - 1;
else {
lastPos = mid;
L = mid+1;
}
}
return lastPos;
}

17
二分查找函數
注意:
int mid = (L+R)/2; //取查找區間正中元素的下標
爲了防止 (L+R)過大溢出:
int mid = L+(R-L)/2;
18
二分查找函數
二分法求方程的根
信息科學技術學院
祁連山風光
二分法求方程的根
求下面方程的一個根:f(x) = x3
-5x2+10x-80 = 0
若求出的根是a,則要求 |f(a)| <= 10-6
解法:對f(x)求導,得f’(x)=3x2-10x+10。由一元二次方程求根公式知方程
f’(x)= 0 無解,因此f’(x)恆大於0。故f(x)是單調遞增的。易知 f(0) < 0且
f(100)>0,所以區間[0,100]內必然有且只有一個根。由於f(x)在[0,100]內是單
調的,所以可以用二分的辦法在區間[0,100]中尋找根。
20
二分法求方程的根 #include

#include <iostream>
#include <cmath>
using namespace std;
double EPS = 1e-6;
double f(double x) { return x*x*x - 5*x*x + 10*x - 80; }
int main() {
double root, x1 = 0, x2 = 100,y;
root = x1+(x2-x1)/2;
int triedTimes = 1; //記錄一共嘗試多少次,對求根來說不是必須的
y = f(root);
while( fabs(y) > EPS) {
if( y > 0 ) x2 = root;
else x1 = root;
root = x1+(x2 - x1)/2;
y = f(root);
triedTimes ++;
}
printf("%.8f\n",root);
printf("%d",triedTimes);
return 0;
}

21
5.70508593
32
例題
尋找指定和的整數對
信息科學技術學院
青海湖
例題 尋找指定和的整數對
輸入n ( n<= 100,000)個整數,找出其中的兩個數,它們之和等於整數m(假定
肯定有解)。題中所有整數都能用 int 表示
23
例題:尋找指定和的整數對
輸入n ( n<= 100,000)個整數,找出其中的兩個數,它們之和等於整數m(假定肯
定有解)。題中所有整數都能用 int 表示
解法1:用兩重循環,枚舉所有的取數方法,複雜度是O(n2
)的。
for(int i = 0;i < n-1; ++i)
for(int j = i + 1; j < n; ++j)
if( a[i]+a[j] == m)
break;
100,0002 = 100億,在各種OJ上提交或參加各種程序設計競賽,這樣的複雜度都會超時

24
例題:尋找指定和的整數對
輸入n ( n<= 100,000)個整數,找出其中的兩個數,它們之和等於整數m(假定
肯定有解)。題中所有整數都能用 int 表示
解法2:

  1. 將數組排序,複雜度是O(n×log(n))
  2. 對數組中的每個元素a[i],在數組中二分查找m-a[i],看能否找到。複雜度log(n),最
    壞要查找n-2次,所以查找這部分的複雜度也是O(n×log(n))
    這種解法總的複雜度是O(n×log(n))的。
    25
    例題:尋找指定和的整數對
    輸入n ( n<= 100,000)個整數,找出其中的兩個數,它們之和等於整數m(假定
    肯定有解)。題中所有整數都能用 int 表示
    解法3:
  3. 將數組排序,複雜度是O(n×log(n))
  4. 查找的時候,設置兩個變量i和j,i初值是0,j初值是n-1.看a[i]+a[j],如果大於m,就讓j
    減1,如果小於m,就讓i加1,直至a[i]+a[j]=m。
    這種解法總的複雜度是O(n×log(n))的。
    26
    例題
    Aggressive cows
    信息科學技術學院
    航拍青海湖
    例題2 百練 2456: Aggressive cows
    28
    http://bailian.openjudge.cn/practice/2456
    農夫 John 建造了一座很長的畜欄,它包括N (2≤N≤100,000)個隔間,這
    些小隔間的位置爲x0
    ,…,xN-1 (0≤xi≤1,000,000,000,均爲整數,各不相同).
    John的C (2≤C≤N)頭牛每頭分到一個隔間。牛都希望互相離得遠點省得互
    相打擾。怎樣才能使任意兩頭牛之間的最小距離儘可能的大,這個最大的
    最小距離是多少呢?
    例題2
    29
    解法1:
    先得到排序後的隔間座標 x0
    ,…,xN-1
    從1,000,000,000/C到1依次嘗試這個 “最大的最近距離”D,找到的
    第一個可行的就是答案。
    嘗試方法:
  5. 第1頭牛放在x0
  6. 若第k頭牛放在xi ,則找到xi+1到xN-1中第一個位於[xi+D, 1,000,000,000]中的Xj
    ,第k+1頭牛放在Xj。找不到這樣的Xj
    ,則 D=D-1,轉 1)再試
    若所有牛都能放下,則D即答案
    例題2
    30
    解法1:
    先得到排序後的隔間座標 x0
    ,…,xN-1
    從1,000,000,000/C到1依次嘗試這個“最大的最近距離”D, 找到的
    第一個可行的就是答案。
    嘗試方法:
  7. 第1頭牛放在x0
  8. 若第k頭牛放在xi ,則找到xi+1到xN-1中第一個位於[xi+D, 1,000,000,000]中的Xj
    ,第k+1頭牛放在Xj。找不到這樣的Xj
    ,則 D=D-1,轉 1)再試
    若所有牛都能放下,則D即答案
    複雜度 1,000,000,000/C *N,即 1,000,000,000, 超時!
    例題2
    31
    解法2:
    先得到排序後的隔間座標 x0
    ,…,xN-1
    在[L,R]內用二分法嘗試“最大最近距離”D = (L+R)/2 (L,R初值爲
    [1, 1,000,000,000/C]
    若D可行,則記住該D,然後在新[L,R]中繼續嘗試(L= D+1)
    若D不可行,則在新[L,R]中繼續嘗試(R= D-1)
    複雜度 log(1,000,000,000/C) * N
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章