數據結構與演算法(一)

来源:https://www.cnblogs.com/haohuihai/archive/2020/06/27/13199030.html
-Advertisement-
Play Games

演算法效率的度量方法; 函數調用的時間複雜度分析; 常見的時間複雜度; 演算法的空間複雜度; ...


演算法效率的度量方法:

1. 事後統計方法:通過設計好的測試程式和數據,利用電腦計時器對不同演算法編製的程式的運行時間進行比較,從而確定演算法效率的高低。

缺陷:是根據以及編製好的程式去測試,如果測試的是糟糕的演算法,會功虧一簣。

2. 事前分析估算方法:在電腦程式編寫前,依據統計方法對演算法進行估算。

高級語言編寫的程式在電腦上運行時所消耗的時間取決於下列因素:

  1. 演算法採用的策略,方案。
  2. 編譯產生的代碼質量
  3. 問題的輸入規模
  4. 機器執行指令的速度

所以:一個程式的運行時間依賴於演算法的好壞和問題的輸入規模。

 在編寫程式的時候,我們不關心語言、所用的電腦只關心它所實現的演算法。

在分析程式的運行時間的時候,最重要的是把程式看成是獨立於程式設計語言的演算法或一系列步驟,把基本操作的數量和輸入模式進行關聯。

 函數漸進增長:

n=1時,演算法A1效率不如演算法B1;當n=2時,兩者效率相等;當n>2時,演算法A1開始優於演算法B1,隨著n的繼續增加,演算法A1比演算法B1逐漸拉大差距。所以總體上演算法A1比演算法B1優秀

定義:給定2個函數f(n)和g(n),如果存在一個整數N,使得對於所有的n>N,f(n)總是比g(n)大,那麼,我們說f(n)的增長漸進快於g(n)

例如如下演算法的增長率:

 

 

通過這組數據可以看出,當n的值非常大的時候,3n+1已經不能和2n^2的結果進行比較,最終幾乎是可以忽略不計的,演算法G在跟演算法I基本已經重合了,

結論:判斷一個演算法的時候,函數中的常數和其他次要項常常可以忽略,關註主項(最高項)的階數。

註意:不能通過少量的數據來判斷一個演算法的好壞。

 演算法時間複雜度:
定義:在進行演算法分析時,語句總的執行次數T(n)是關於問題規模n的函數,進而分析T(n)隨n的變化情況並確定T(n)的數量級,演算法的時間複雜度,也就是演算法的時間量度,記作:T(n)=O(f(n))。他表示隨問題規模n的增大,演算法執行時間的增長率和f(n)的增長率相同,稱作演算法的漸進時間複雜度,簡稱為時間複雜度,其中f(n)是問題規模n的某個函數。

用大O()來體現演算法時間複雜度的記法,一般情況下隨著輸入規模n的增大,T(n)增長最慢的演算法為最優演算法。

 推導大O階的方法

  1. 用常數1取代運行時間中的所有加法常數。
  2. 在修改後的運行函數中,只保留最高項。
  3. 如果最高項存在且不是1,則除這個項相乘的常數。
  4. 得到的最後的結果就是O()階

例如:

1.常數階

int sum=0,n=100;

printf("hello word\n");

printf("hello word\n");

printf("hello word\n");

printf("hello word\n");

sum=(1+n)*n/2

所有常數項均可以看做是1,時間複雜度為O(1);

 2.線性階:

含有非嵌套迴圈涉及線性階,就是隨著問題規模n的擴大,對應計算次數呈直線增長。

int i,n=100,sum=0;

for(i=0;i<n;i++){

sum=sum+i;

}

迴圈中的代碼需要執行n次,所以時間複雜度為O(n)

 3.平方階:

int i,j,n=100;
for(i=0;i<n;i++)
{   
for(j=0;j<n;j++){   printf("hello word")   } }

外層執行一次,內層執行100次,需要執行100*100次,n的平方次,所以時間複雜度為O(n^2),

如果有三個這樣的迴圈,則時間複雜度為O(n^3)

分析下,由於當i=0時,內迴圈執行了n次,當i=1時,內迴圈則執行n-1次.....當i=n-1時,內迴圈執行1次,所以總的執行次數應該是:- n+(n-1)+(n-2)+...+1 = n(n+1)/2,用我們推導大O的攻略,第一條忽略,因為沒有常數相加。第二條只保留最高項,所以n/2這項去掉。第三條,去除與最高項相乘的常數,最終得O(n^2)。

 4.對數階

int i=1,n=100;
while(i<n){
i=i*2;
}

由於2^x=n得到x=log(2)n,所以這個迴圈的時間複雜度為O(log(2)n)

 函數調用的時間複雜度分析:

例1:

int i,j;
for(i=0;i<n;i++){

function(i);

}

void function(int count){

printf("%d",count);

}

 函數體是列印這個參數,function函數的時間複雜度是O(1),所以整體的時間複雜度就是迴圈的次數O(n)。

例2:

void function(int count){

int j;

for(j=count;j<n;j++){

printf("%d",j);
}
count++;
}

function內部的迴圈次數隨count的增加而減少,所以它的時間複雜度為O(n^2)。

 例3:

n++; ##1

function(n);##一個內部迴圈的函數 O(N^2)
for(i=0;i<n;i++){ function(i);##內部迴圈的函數 } ## O(N^2)   for(i=0;i<n;i++){   for(j=i;j<n;j++){   printf("%d",j);   }}##O(n^2)

時間複雜度為O(n^2)

 常見的時間複雜度:

常用時間複雜度所耗費的時間從小到大依次是:

O(1)<O(logn)<(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)

最壞情況與平均情況:

演算法的分析也是類似,我們查找一個有n個隨機數字數組中的某個數字,最好的情況是第一個數字就是,那麼演算法的時間複雜度為O(1),但也有可能這個數字就在最後一個位置,它的時間複雜度為O(n),平均運行時間是期望的運行時間,最壞的運行時間是一種保證,在應用中,這是一種最重要的需求,通常除非特別的指定,我們提到的運行時間都是最壞情況的運行時間。

演算法的空間複雜度:

 演算法的空間複雜度通過計算演算法所需的存儲空間實現,演算法的空間複雜度的計算公式為:S(n)=O(f(n)),其中n為問題的規模,f(n)為語句關於n所占空間的函數。

一般情況"複雜度"指的是時間複雜度 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天博主再給大家分享一個小項目:MiNi圖書管理系統。用的是Java語言開發的,代碼不多,大概260行左右吧,系統是實現圖書的新增圖書、刪除圖書、借閱圖書、歸還圖書、查看圖書等簡單的功能(後附源代碼)! 首先展示一下運行界面效果圖:運行代碼後,會在控制台顯示如下界面: 然後讓用戶選擇,如果用戶不小心 ...
  • import pandas a=pandas.read_excel() def abc(x): return ','.join(x.values) b=a.groupby(['列名'1])['列名2'].apply(abc) c=b.reset_index() print(c) ...
  • WebSocket 非同步風格伺服器 WebSocket\Server 繼承自 Http\Server,所以 Http\Server 提供的所有 API 和配置項都可以使用。 # ws_server.php class WebSocket { public $server; public functi ...
  • 一.環境要求 安裝java 1.8 以上 命令行運行 java -version 返回版本大於1.8 如果沒有,請安裝java 1.8 二.下載與安裝 下載apktool_x.x.x.jar到本地 官網下載或者 鏡像下載 重命名下載的apktool_x.x.x.jar,改名為apktool.jar ...
  • MongoSpark為入口類,調用MongoSpark.load,該方法返回一個MongoRDD類對象,Mongo Spark Connector框架本質上就是一個大號的自定義RDD,加了些自定義配置、適配幾種分區器規則、Sql的數據封裝等等,個人認為相對核心的也就是分區器的規則實現;弄清楚了其分析 ...
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 最近一直在關註百度明星吧,發現很多有趣的帖子,於是我就想用python把這些帖子都爬下來,並對內容進行分析。 本文的知識點: 介紹了mysql資料庫內容插入及提取的簡單應用; ...
  • 在上一篇博文中,主要分析了tomcat的整體架構,通過上一篇的分析可以知道,tomcat主要有兩部分組成,分別為連接器(Connector)和容器(Container)。本文介紹連接器(Connector)。 一、Connector的主要功能 連接器主要用於對外交流,它負責接收外部的請求,然後把請求 ...
  • 1.Math類 Math類在java.lang包下,提供了一系列靜態方法用於科學計算,其方法的參數和返回值一般為double類型。 Math類常用方法: 1.abs:絕對值 2.acos,asin,atan,cos,sin,tan:三角函數 3.sqrt:平方根 4.pow(double a,dou ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...