/* 與平衡樹不同(平衡樹是具有非常小的深度的,這也意味着到達任何一個節點所經過的邊數很少),左偏樹並不是爲了 快速訪問所有的節點而設計的,它的目的是快速訪問最小節點以及在對樹修改後快速的恢復堆性質。 左偏樹是一種可合併堆,常用於優先級隊列。 左偏樹有兩個性質: 1)堆的性質(注意:一般堆是完全二叉樹,但這裏不是): A[parent(i)]>=A[i] or A[parent(i)]<=A[i],即父節點大於(或者小於)子節點的值(這個“值”可以看成Key或者優先級)。 2)左偏性質: 節點的左子節點的距離不小於右子節點的距離,即dist(left(i))≥dist(right(i)) 。 其中節點的距離等於它的右子節點的距離加1,即 dist(i) = dist( right(i) ) + 1 ;如果一個節點的右子節點爲空節點, 則其距離爲0;爲了滿足性質,故規定空節點的距離爲-1。 這裏左偏樹提供一下功能: 1)插入節點Insert, 時間複雜度O(logn) 2)獲得根節點(即最小節點(如果是最小堆)或者最大節點(如果是最大堆)),時間複雜度O(1) 3)刪除根節點DeleteRoot,時間複雜度O(logn) 4)合併兩個左偏樹Merge,時間複雜度O(logn) */ #include <iostream> #include <functional> #include <cassert> using namespace std; //節點數據結構 template<class Type> struct Node { Type data;//數據 int dist;//距離 Node<Type> *left;//左兒子指針 Node<Type> *right;//右兒子指針 Node(Type val) { data = val; dist = 0; left = right = NULL; } ~Node() { } }; //左偏樹 template <class Type,class Compare = less<Type>/*默認是小堆*/ > class LeftistTree { private: Node<Type> *root; //刪除以指定節點爲根的左偏樹 void Delete(Node<Type> *node) { if(NULL != node) { Delete(node->left); Delete(node->right); delete node; //node = NULL; } } //判斷指定節點是否有左兒子 //static bool HasLeft(Node<Type>* node) //{ // if(!node) return false;//空節點沒有左兒子 // return node->left; //} //獲取指定節點的左兒子 static Node<Type>*& Left(Node<Type>*& node) { assert(NULL != node); return node->left; } //判斷指定節點是否有右兒子 //static bool HasRight(Node<Type>* node) //{ // if(!node) return false;//空節點沒有右兒子 // return node->right; //} //獲取指定節點的右兒子 static Node<Type>*& Right(Node<Type>*& node) { assert(NULL != node); return node->right; } //獲取指定節點的距離 static int Dist(Node<Type>* node) { if(NULL == node) return -1;//規定空節點的距離爲-1 return node->dist; } //交換left指針與right指針 static void Swap(Node<Type>*& left,Node<Type>*& right) { Node<Type> *temp = left; left = right; right = temp; } //合併兩顆左偏樹(返回合併之後左偏樹的根結點) static Node<Type>*& Merge(Node<Type>*& t1, Node<Type>*& t2) { if(NULL == t1) return t2; else if(NULL == t2) return t1; //確定t1,t2兩個節點誰作爲合併後的根節點,以滿足左偏樹的堆的性質(A[parent(i)]>=A[i] or A[parent(i)]<=A[i])。 //但這裏的“堆”未必是完全二叉樹 //注意是個遞歸過程 if( Compare()(t2->data, t1->data) ) //Compare是比較規則,它確定堆是大堆還是小堆 Swap(t1,t2); Right(t1) = Merge(Right(t1), t2); //爲左右兒子排序,以滿足左偏樹的左偏性質,即節點的左子節點的距離不小於右子節點的距離 if( Dist(Right(t1)) > Dist(Left(t1)) ) Swap( Left(t1),Right(t1) ); //調整距離 if( NULL == Right(t1) ) t1->dist = 0; else t1->dist = Dist(Right(t1)) + 1; return t1; } //輸出以指定節點爲根的左偏樹(遞歸方式的先序遍歷) void Print(Node<Type> *node) { if(NULL != node) { cout << node->data <<endl; cout<<"節點"<<node->data<<"的左兒子爲:"; if(NULL != node->left) Print(node->left); else cout<<"NULL"; cout<<endl; cout<<"節點"<<node->data<<"的右兒子爲:"; if(NULL != node->right) Print(node->right); else cout<<"NULL"; cout<<endl; } } public: LeftistTree(): root(NULL) { } ~LeftistTree() { Delete(root); } //向左偏樹插入元素 void Insert(Type val) { Node<Type> *newNode; newNode = new Node<Type>(val); root = Merge(root, newNode); } //刪除左偏樹的根結點 void DeleteRoot() { if(NULL == root) { cout << "警告:左偏樹爲空" << endl; return; } Node<Type> *p = root; root = Merge(p->left, p->right); delete p; } //合併兩棵左偏樹 //合併後t2就爲空樹了。 void Merge(LeftistTree<Type,Compare>& t2) { root = Merge(root, t2.root); t2.root = NULL; } //獲取根結點的值(相當於優先級) Type Root() { if(NULL == root) { cout << "左偏樹爲空" << endl; return NULL; } return root->data; } //輸出整棵左偏樹中的元素 void Print() { Print(root); cout << endl; } }; int main() { //建立小堆的左偏樹 { LeftistTree<double> tree; tree.Insert(5); tree.Insert(4); tree.Insert(3); tree.Insert(8); tree.Insert(1); tree.Insert(2); tree.Insert(9); tree.Insert(7); tree.Insert(6); tree.Insert(0); cout<< "第一顆左偏樹:" << endl; tree.Print(); tree.DeleteRoot(); tree.DeleteRoot(); cout<< "新的左偏樹:" << endl; tree.Print(); cout <<"新的左偏樹的根節點:"<< tree.Root() << endl; LeftistTree<double> tr; tr.Insert(4.3); tr.Insert(9.6); tr.Insert(5.5); tr.Insert(6.6); cout<<"第二顆左偏樹:"<<endl; tr.Print(); cout <<"第二顆左偏樹的根節點:"<<tr.Root() << endl; tree.Merge(tr); cout <<"合併後的左偏樹爲:" << endl; tree.Print(); } cout<<"-----------------------------------"<<endl; //建立大堆的左偏樹 { LeftistTree< double, greater<double> > tree2; tree2.Insert(5); tree2.Insert(4); tree2.Insert(3); tree2.Insert(8); tree2.Insert(1); tree2.Insert(2); tree2.Insert(9); tree2.Insert(7); tree2.Insert(6); tree2.Insert(0); cout<< "第一顆左偏樹:" << endl; tree2.Print(); tree2.DeleteRoot(); tree2.DeleteRoot(); cout<< "新的左偏樹:" << endl; tree2.Print(); cout <<"新的左偏樹的根節點:"<< tree2.Root() << endl; LeftistTree< double, greater<double> > tr2; tr2.Insert(4.3); tr2.Insert(9.6); tr2.Insert(5.5); tr2.Insert(6.6); cout<<"第二顆左偏樹:"<<endl; tr2.Print(); cout <<"第二顆左偏樹的根節點:"<<tr2.Root() << endl; tree2.Merge(tr2); cout <<"合併後的左偏樹爲:" << endl; tree2.Print(); } return 0; }
參考文獻:
http://www.docin.com/p-1775556.html
http://www.ozobo.cn/?p=78
強化學習概覽 This overview is largely based on this article: https://medium.com/@SmartLabAI/reinforcement-learning-algorithms
插入排序法 1.工作原理(算法思路) 新建一個指針,指針左邊的所有元素都是有序的。但是他們的位置並不是最終位置,一個指針從左向右掃描,若指針所在處的元素比左邊元素小,則將該元素向前浮動至適當位置,使指針左側元素仍然保持有序。當指針掃描到整
分治基本思想影響算法複雜度的因素經典案例1 二分檢索設計思想僞碼2 二分歸併設計思想僞碼3 漢諾塔設計思想僞碼4 快速排序設計思想僞碼實例5 快速傅里葉變換(信號平滑處理)問題描述設計&分析減少子問題個數案例:大數相乘設計思想參考
XGBoost可以用來分類,迴歸,排序。 支持多種語言:C++, Python, R, Java, Scala, Julia。 安裝 參考https://xgboost.readthedocs.io/en/latest/buil
NDCG(Normalized Discounted Cumulative Gain): 維基百科寫的很清楚。 注意理解這四個詞。 Discounted:順序影響指標。 Normalized:消除文檔個數對指標的影響。
商品關聯分析 關聯 relevance: 主要用在互聯網的內容和文檔上,比如搜索引擎算法文檔中之間的關聯性。 association: 用在實際的事物之上,比如電子商務網站上的商品之間的關聯度。 支持度(support):數據集中
簡單記錄一下關於仿真優化的一些知識點和思考。主要基於:Handbook of Simulation Optimization, Michael Fu Table of Contents Overview Discrete Optimiza
點這個: https://towardsdatascience.com/a-road-map-for-deep-learning-b9aee0b2919f
Currently learning stochastic optimization (SO) theory, I will note important content here. Some book references ar
Reading notes of the paper "Distributed Optimization and Statistical Learning via ADMM" by Boyd, Parikh, Chu, Peleato a
Source:http://www.seas.ucla.edu/~vandenbe/ee236c.html Introduction Outline First-order algorithms Decomposition and s
Overview of gradient descent algorithms An overview of gradient descent optimization algorithms Gradient descent is
function TreeNode(val) { this.val = val; this.left = this.right = null; } 解一:遞歸 先判斷樹結構是否爲null,如果是null,直接
雖然網上已經很多這種排序算法了,但是爲了讓自己更熟悉一點(也順便寫篇博客),所以準備把基本的那幾種算法原理及代碼重新寫一遍 今天先來冒泡算法吧,冒泡算法的基本原理就是通過不斷的比較兩個相鄰元素的大小,如果前一個比後一個大,則交換兩個元素的