線性時間選擇演算法分析
① 中位數線性時間選擇演算法 為什麼是5個數分組
一、MEDIAN函數就是用來求中位數的。二、四分位函數QUARTILE,若第二個參數為2時,也是求中位數的。
② 究竟如何才算是線性時間內
for(i = 1; i<=8; i++)
;
for(i = 1;i <= 8; i++)
;
是O(2n) 也就是O(n),因為你做了兩次線性操作,迭代起來還是線性的。
你後面講的求第k小的演算法,是一個線性演算法,但是那個演算法的分析難度很大,如果你尚且搞不清楚大O等符號的定義,建議不去想那個演算法。另外,快速排序至少是nlogn的演算法,不會是線性。
最後,你一開始說的對線性的理解,略草率。對於一般情況沒問題,但不是每個程序都有一個明顯的1到n的for循環給你看的。
③ 如何分析時間復雜度(線性表)
演算法分析
同一問題可用不同演算法解決,而一個演算法的質量優劣將影響到演算法乃至程序的效率。演算法分析的目的在於選擇合適演算法和改進演算法。一個演算法的評價主要從時間復雜度和空間復雜度來考慮。
1、時間復雜度
(1)時間頻度
一個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時間多,哪個演算法花費的時間少就可以了。並且一個演算法花費的時間與演算法中語句的執行次數成正比例,哪個演算法中語句執行次數多,它花費時間就多。一個演算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)。
(2)時間復雜度
在剛才提到的時間頻度中,n稱為問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道它變化時呈現什麼規律。為此,我們引入時間復雜度概念。
一般情況下,演算法中基本操作重復執行的次數是問題規模n的某個函數,用T(n)表示,若有某個輔助函數f(n),使得當n趨近於無窮大時,T(n)/f(n)的極限值為不等於零的常數,則稱f(n)是T(n)的同數量級函數。記作T(n)=O(f(n)),稱O(f(n)) 為演算法的漸進時間復雜度,簡稱時間復雜度。
在各種不同演算法中,若演算法中語句執行次數為一個常數,則時間復雜度為O(1),另外,在時間頻度不相同時,時間復雜度有可能相同,如T(n)=n2+3n+4與T(n)=4n2+2n+1它們的頻度不同,但時間復雜度相同,都為O(n2)。
按數量級遞增排列,常見的時間復雜度有:
常數階O(1),對數階O(log2n),線性階O(n),
線性對數階O(nlog2n),平方階O(n2),立方階O(n3),...,
k次方階O(nk),指數階O(2n)。隨著問題規模n的不斷增大,上述時間復雜度不斷增大,演算法的執行效率越低。
2、空間復雜度
與時間復雜度類似,空間復雜度是指演算法在計算機內執行時所需存儲空間的度量。記作:
S(n)=O(f(n))
我們一般所討論的是除正常佔用內存開銷外的輔助存儲單元規模。
④ 【比較難寫的演算法】最壞情況線性時間的選擇
實際上比平均情況下線性時間的選擇要復雜很多(演算法導論上偽代碼都沒有)
問題是快速排序要求樞紐元在最後一個,如果採用hoare的劃分演算法,就沒有這個要求。而給出的是樞紐元的值,然後要找到位置(搜索一遍),再交換。
如果採用hoare劃分法,不用搜索,不過演算法和書上描述的就稍有不同了。
另外,因為代碼復雜,所以對於隨機輸入,此演算法較慢
下面是hoare劃分的選擇代碼
# include <ctime>
# include <cstdlib>
# include <iostream>
inline void swap(int &x, int&y)
{
int temp = x;
x = y;
y = temp;
}
// A[p..r]
int hoarePartitionX(int *A, int p, int r, int x)
{
int i = p - 1;
int j = r + 1;
for(;;)
{
while( A[--j] > x)
;
while( A[++i] < x)
;
if(i<j)
{
swap(A[i], A[j]);
}
else
{
return j;
}
}
}
// A[0..size-1]
void insertionSort(int *A, int size)
{
int i;
int key;
for(int j=1; j<size; j+=1)
{
key = A[j];
i = j - 1;
while(i >= 0 && A[i] > key)
{
A[i+1] = A[i];
i -= 1;
}
A[i+1] = key;
}
}
// return the ith smallest element of A[p..r]
int select(int *A, int p, int r, int i)
{
if(p == r) // only one element, just return
{
return A[p];
}
// #1. groupNum & rest
int groupNum = (r - p + 1) / 5; // not counting the rest
int rest = (r - p + 1) % 5;
// #2. sort the groups
for(int t=0; t<groupNum; t+=1)
{
insertionSort(A + p + t*5, 5);
}
if(rest != 0)
{
insertionSort(A + p + groupNum * 5, rest);
}
// #3. get the mid value x
int *mids;
if(rest == 0)
mids = new int[groupNum];
else
mids = new int[groupNum+1];
for(int t=0; t<groupNum; t+=1)
{
mids[t] = A[ p + t*5 + 2 ];
}
if(rest != 0)
{
mids[groupNum] = A[ p + groupNum*5 + (rest-1)/2 ];
}
int x;
if( rest == 0 )
{
x = select(mids, 0, groupNum-1, (groupNum-1) / 2 + 1);
}
else
{
x = select(mids, 0, groupNum, groupNum / 2 + 1);
}
delete []mids;
// #4. partition with x
int k = hoarePartitionX(A, p, r, x) - p + 1; // so the value A[p+k-1] is the kth smallest
// #5.
if(i <= k)
{
return select(A, p, p+k-1, i);
}
else
{
return select(A, p+k, r, i-k);
}
}
int main()
{
int array[100];
for(int i=0; i<100; i+=1)
array[i] = i;
for(int i=0; i<100; i+=1)
{
int rnd = rand()%100;
swap(array[0], array[rnd]);
}
std::cout << select(array, 0, 99, 82);
std::cin.get();
return 0;
}
⑤ 快速排序演算法和線性時間選擇演算法的隨機化版本是什麼演算法
分治演算法(二分法) 他先把數據二分 然後排序兩個區間 然後合並 在二分
⑥ 設計一個線性時間演算法,用一個排序好的數列建立一個完全二叉樹
對一棵樹進行廣度優先遍歷,就可以一橫行一橫行的遍歷數據.反過來,也就可以一橫行一橫行的插入數據.
因此就可以採取這種方式,每次建立一個新的節點,就往隊列裡面加入它的兩個子節點,然後按照隊列來進行生成即可.
⑦ 線性時間是什麼意思
線性時間復雜度,就是時間復雜度為線性階O(n)。
同一問題可用不同演算法解決,而一個演算法的質量優劣(或者說演算法復雜度)可由時間復雜度和空間復雜度來評價。
演算法的時間復雜度是指執行演算法所需要的計算工作量,即度量演算法執行的時間長短,它定量描述了該演算法的運行時間。
按數量級遞增排列,常見的時間復雜度有:常數階O(1),對數階O(log2n),線性階O(n),線性對數階O(nlog2n),平方階O(n^2),立方階O(n^3),。
隨著問題規模n的不斷增大,時間復雜度不斷增大,演算法的執行效率越低。
⑧ 什麼是線性時間演算法
計算公式:K(N)=AO(N)+B
線性時間
在計算復雜性理論,一個被稱為線性時間或 Ο(n)時間的演算法,表示此演算法解題所需時間正比於輸入資料的大小,通常以n表示。換句話說,執行時間與輸入資料大小為線性比例。例如將一列數字加總的所需時間,正比於串列的長度。
⑨ 數據結構與演算法分析:C語言描述的目錄
第1章 引論1.1 本書討論的內容1.2 數學知識復習1.2.1 指數1.2.2 對數1.2.3 級數1.2.4 模運算1. 2.5 證明方法1.3 遞歸簡論總結練習參考文獻第2章 演算法分析2.1 數學基礎2.2 模型2.3 要分析的問題2.4 運行時間計算2.4.1 一個簡單的例子2.4.2 一般法則2.4.3 最大子序列和問題的解.2.4.4 運行時間中的對數2.4.5 檢驗你的分析2.4.6 分析結果的准確性總結練習參考文獻第3章 表、棧和隊列3.1 抽象數據類型(adt)3.2 表adt3.2.1 表的簡單數組實現3.2.2 鏈表3.2.3 程序設計細節3.2.4 常見的錯誤3.2.5 雙鏈表3.2.6 循環鏈表3.2.7 例子3.2.8 鏈表的游標實現3.3 棧adt3.3.1 棧模型3.3.2 棧的實現3.3.3 應用3.4 隊列adt3.4.1 隊列模型3.4.2 隊列的數組實現3.4.3 隊列的應用總結練習第4章 樹4.1 預備知識4.1.1 樹的實現4.1.2 樹的遍歷及應用4.2 二叉樹4.2.1 實現4.2.2 表達式樹4.3 查找樹adt--二叉查找樹4.3.1 makeempty4.3.2 find4.3.3 findmin和findmax4.3.4 insert4.3.5 delere4.3.6 平均情形分析4.4 avl樹4.4.1 單旋轉4.4.2 雙旋轉4.5 伸展樹4.5.1 一個簡單的想法4.5.2 展開4.6 樹的遍歷4.7 b-樹總結練習參考文獻第5章 散列5.1 一般想法5.2 散列函數5.3 分離鏈接法5.4 開放定址法5.4.1 線性探測法5.4.2 平方探測法5.4.3 雙散列5.5 再散列5.6 可擴散列總結練習參考文獻第6章 優先隊列(堆)6.1 模型6.2 一些簡單的實現6.3 二叉堆6.3.1 結構性質6.3.2 堆序性質6.3.3 基本的堆操作6.3.4 其他的堆操作6.4 優先隊列的應用6.4.1 選擇問題6.4.2 事件模擬6.5 d-堆6.6 左式堆6.6.1 左式堆的性質6.6.2 左式堆的操作6.7 斜堆6.8 二項隊列6.8.1 二項隊列結構6.8.2 二項隊列操作6.8.3 二項隊列的實現總結練習參考文獻第7章 排序7.1 預備知識7.2 插入排序7.2.1 演算法7.2.2 插入排序的分析7.3 一些簡單排序演算法的下界7. 4 希爾排序7.4.1 希爾排序的最壞情形分析7.5 堆排序7.5.1 堆排序的分析7.6 歸並排序7.6.1 歸並排序的分析7.7 快速排序7.7.1 選取樞紐元7.7.2 分割策略7.7.3 小數組7.7.4 實際的快速排序常式7.7.5 快速排序的分析7.7.6 選擇的線性期望時間演算法7.8 大型結構的排序7.9 排序的一般下界7.9.1 決策樹7.10 桶式排序7.11 外部排序7.11.1 為什麼需要新的演算法7.11.2 外部排序模型7.11.3 簡單演算法7.11.4 多路合並7.11.5 多相合並7.11.6 替換選擇總結練習參考文獻第8章 不相交集adt8.1 等價關系8.2 動態等價性問題8.3 基本數據結構8.4 靈巧求並演算法8.5 路徑壓縮8.6 按秩求並和路徑壓縮的最壞情形8.6.1 union/find演算法分析8.7 一個應用總結練習參考文獻第9章 圖論演算法9.1 若干定義9.1.1 圖的表示9.2 拓撲排序9.3 最短路徑演算法9.3.1 無權最短路徑9.3.2 dijkstra演算法9.3.3 具有負邊值的圖9.3.4 無圈圖9.3.5 所有點對最短路徑9.4 網路流問題9.4.1 一個簡單的最大流演算法9.5 最小生成樹9.5.1 prim演算法9.5.2 kruskal演算法9.6 深度優先搜索的應用9.6.1 無向圖9.6.2 雙連通性9.6.3 歐拉迴路9.6.4 有向圖9.6.5 查找強分支9.7 np-完全性介紹9.7.1 難與易9.7.2 np類9.7.3 np-完全問題總結練習參考文獻第10章 演算法設計技巧10.1 貪婪演算法10.1.1 一個簡單的調度問題10.1.2 huffman編碼10.1.3 近似裝箱問題10.2 分治演算法10.2.1 分治演算法的運行時間10.2.2 最近點問題10.2.3 選擇問題10.2.4 一些運算問題的理論改進10.3 動態規劃10.3.1 用一個表代替遞歸10.3.2 矩陣乘法的順序安排10.3.3 最優二叉查找樹10.3.4 所有點對最短路徑10.4 隨機化演算法10.4.1 隨機數發生器10.4.2 跳躍表10.4.3 素性測試10.5 回溯演算法10.5.1 收費公路重建問題10.5.2 博弈總結練習參考文獻第11章 攤還分析11.1 一個無關的智力問題11.2 二項隊列11.3 斜堆11.4 斐波那契堆11.4.1 切除左式堆中的節點11.4.2 二項隊列的懶惰合並11.4.3 斐波那契堆操作11.4.4 時間界的證明11. 5 伸展樹總結練習參考文獻第12章 高級數據結構及其實現12.1 自頂向下伸展樹12.2 紅黑樹12.2.1 自底向上插入12.2.2 自頂向下紅黑樹12.2.3 自頂向下刪除12.3 確定性跳躍表12.4 aa-樹12.5 treap樹12.6 k-d樹12.7 配對堆總結練習參考文獻索引
⑩ 求助!一道C語言演算法題
boolvis[11];
booljud(intx,inty){if(y<1000)returnfalse;
memset(vis,false,sizeof(vis));
if(y<10000)vis[0]=true;
if(x==0){if(。
vis[x])vis[x]=true;
elsereturnfalse;
}while(x){if(vis[x%10])returnfalse;
vis[x%10]=true;
x/=10;
}if(y==0){if(。
vis[y])vis[y]=true;
elsereturnfalse;
}while(y){if(vis[y%10])returnfalse;
vis[y%10]=true;
y/=10;
}returntrue;
}intmain(){inti,j,n;
scanf("%d",&n);
for(i=10000;
i<=99999;
i++)if(i%n==0){if(jud(i,i/n)){if(i/n<10000)printf("%d/0%d=%d\n",i,i/n,n);
elseprintf("%d/%d=%d\n",i,i/n,n);
}}return0;
}嗯..雖然jud(int,int)函數有點長...