├── .gitignore ├── Ch_1_1_Basic_Programming_Model ├── Practise_1_1_01.java ├── Practise_1_1_02.java ├── Practise_1_1_03.java ├── Practise_1_1_04.java ├── Practise_1_1_05.java ├── Practise_1_1_06.java ├── Practise_1_1_07.java ├── Practise_1_1_08.java ├── Practise_1_1_09.java ├── Practise_1_1_10.java ├── Practise_1_1_11.java ├── Practise_1_1_12.java ├── Practise_1_1_13.java ├── Practise_1_1_14.java ├── Practise_1_1_15.java ├── Practise_1_1_16.java ├── Practise_1_1_17.java ├── Practise_1_1_18.java ├── Practise_1_1_19.java ├── Practise_1_1_20.java ├── Practise_1_1_21.java ├── Practise_1_1_22.java ├── Practise_1_1_23.java ├── Practise_1_1_24.java ├── Practise_1_1_25.java ├── Practise_1_1_26.java ├── Practise_1_1_27.java ├── Practise_1_1_28.java ├── Practise_1_1_29.java ├── Practise_1_1_30.java ├── Practise_1_1_31.java ├── Practise_1_1_32.java ├── Practise_1_1_33.java ├── Practise_1_1_34.java ├── Practise_1_1_35.java ├── Practise_1_1_36.java ├── Practise_1_1_37.java ├── Practise_1_1_38.java └── Practise_1_1_39.java ├── Ch_1_2_Data_Abstraction ├── Practise_1_2_01.java ├── Practise_1_2_02.java ├── Practise_1_2_03.java ├── Practise_1_2_04.java ├── Practise_1_2_05.java ├── Practise_1_2_06.java ├── Practise_1_2_07.java ├── Practise_1_2_08.java ├── Practise_1_2_09.java ├── Practise_1_2_10.java ├── Practise_1_2_11.java ├── Practise_1_2_12.java ├── Practise_1_2_13.java ├── Practise_1_2_14.java ├── Practise_1_2_15.java ├── Practise_1_2_16.java ├── Practise_1_2_17.java ├── Practise_1_2_18.java └── Practise_1_2_19.java ├── Ch_1_3_Bags_Queues_And_Stacks ├── Practise_1_3_01.java ├── Practise_1_3_02.java ├── Practise_1_3_03.java ├── Practise_1_3_04.java ├── Practise_1_3_05.java ├── Practise_1_3_06.java ├── Practise_1_3_07.java ├── Practise_1_3_08.java ├── Practise_1_3_09.java ├── Practise_1_3_10.java ├── Practise_1_3_11.java ├── Practise_1_3_12.java ├── Practise_1_3_13.java ├── Practise_1_3_14.java ├── Practise_1_3_15.java ├── Practise_1_3_16.java ├── Practise_1_3_17.java ├── Practise_1_3_18.java ├── Practise_1_3_19.java ├── Practise_1_3_20.java ├── Practise_1_3_21.java ├── Practise_1_3_22.java ├── Practise_1_3_23.java ├── Practise_1_3_24.java ├── Practise_1_3_25.java ├── Practise_1_3_26.java ├── Practise_1_3_27.java ├── Practise_1_3_28.java ├── Practise_1_3_29.java ├── Practise_1_3_30.java ├── Practise_1_3_31.java ├── Practise_1_3_32.java ├── Practise_1_3_33.java ├── Practise_1_3_34.java ├── Practise_1_3_35.java ├── Practise_1_3_36.java ├── Practise_1_3_37.java ├── Practise_1_3_38.java ├── Practise_1_3_39.java ├── Practise_1_3_40.java ├── Practise_1_3_41.java ├── Practise_1_3_42.java ├── Practise_1_3_43.java ├── Practise_1_3_44.java ├── Practise_1_3_45.java ├── Practise_1_3_46.java ├── Practise_1_3_47.java ├── Practise_1_3_48.java ├── Practise_1_3_49.java └── Practise_1_3_50.java ├── Ch_1_4_Analysis_Of_Algorithms ├── Practise_1_4_01.java ├── Practise_1_4_02.java ├── Practise_1_4_03.java ├── Practise_1_4_04.java ├── Practise_1_4_05.java ├── Practise_1_4_06.java ├── Practise_1_4_07.java ├── Practise_1_4_08.java ├── Practise_1_4_09.java ├── Practise_1_4_10.java ├── Practise_1_4_11.java ├── Practise_1_4_12.java ├── Practise_1_4_13.java ├── Practise_1_4_14.java ├── Practise_1_4_15.java ├── Practise_1_4_16.java ├── Practise_1_4_17.java ├── Practise_1_4_18.java ├── Practise_1_4_19.java ├── Practise_1_4_20.java ├── Practise_1_4_21.java ├── Practise_1_4_22.java ├── Practise_1_4_23.java ├── Practise_1_4_24.java ├── Practise_1_4_25.java ├── Practise_1_4_26.java ├── Practise_1_4_27.java ├── Practise_1_4_28.java ├── Practise_1_4_29.java ├── Practise_1_4_30.java ├── Practise_1_4_31.java ├── Practise_1_4_32.java ├── Practise_1_4_33.java ├── Practise_1_4_34.java ├── Practise_1_4_35.java ├── Practise_1_4_36.java ├── Practise_1_4_37.java ├── Practise_1_4_38.java ├── Practise_1_4_39.java ├── Practise_1_4_40.java ├── Practise_1_4_41.java ├── Practise_1_4_42.java ├── Practise_1_4_43.java ├── Practise_1_4_44.java ├── Practise_1_4_45.java └── __MinOrMaxIndex.java ├── Ch_1_5_Case_Study_Union_Find ├── Practise_1_5_01.java ├── Practise_1_5_02.java ├── Practise_1_5_03.java ├── Practise_1_5_04.java ├── Practise_1_5_05.java ├── Practise_1_5_06.java ├── Practise_1_5_07.java ├── Practise_1_5_08.java ├── Practise_1_5_09.java ├── Practise_1_5_10.java ├── Practise_1_5_11.java ├── Practise_1_5_12.java ├── Practise_1_5_13.java ├── Practise_1_5_14.java ├── Practise_1_5_15.java ├── Practise_1_5_16.java ├── Practise_1_5_17.java ├── Practise_1_5_18.java ├── Practise_1_5_19.java ├── Practise_1_5_20.java ├── Practise_1_5_21.java ├── Practise_1_5_22.java ├── Practise_1_5_23.java ├── Practise_1_5_24.java ├── Practise_1_5_25.java ├── Practise_1_5_26.java ├── __Review.java ├── __UF.java ├── __UF_QuickFind.java ├── __UF_QuickUnion.java └── __UF_WeightedQuickUnion.java ├── Ch_2_1_Elementary_Sorts ├── Practise_2_1_01.java ├── Practise_2_1_02.java ├── Practise_2_1_03.java ├── Practise_2_1_04.java ├── Practise_2_1_05.java ├── Practise_2_1_06.java ├── Practise_2_1_07.java ├── Practise_2_1_08.java ├── Practise_2_1_09.java ├── Practise_2_1_10.java ├── Practise_2_1_11.java ├── Practise_2_1_12.java ├── Practise_2_1_13.java ├── Practise_2_1_14.java ├── Practise_2_1_15.java ├── Practise_2_1_16.java ├── Practise_2_1_17.java ├── Practise_2_1_18.java ├── Practise_2_1_19.java ├── Practise_2_1_20.java ├── Practise_2_1_21.java ├── Practise_2_1_22.java ├── Practise_2_1_23.java ├── Practise_2_1_24.java ├── Practise_2_1_25.java ├── Practise_2_1_26.java ├── Practise_2_1_27.java ├── Practise_2_1_28.java ├── Practise_2_1_29.java ├── Practise_2_1_30.java ├── Practise_2_1_31.java ├── Practise_2_1_32.java ├── Practise_2_1_33.java ├── Practise_2_1_34.java ├── Practise_2_1_35.java ├── Practise_2_1_36.java ├── Practise_2_1_37.java ├── Practise_2_1_38.java ├── __Insertion.java ├── __InsertionSortPerformenceComparasion.c ├── __Selection.java ├── __Shell.java ├── __SortCompare.java └── __希尔排序完整轨迹.png ├── Ch_2_2_MergeSort ├── Practise_2_2_01.java ├── Practise_2_2_02.java ├── Practise_2_2_03.java ├── Practise_2_2_04.java ├── Practise_2_2_05.java ├── Practise_2_2_06.java ├── Practise_2_2_07.java ├── Practise_2_2_08.java ├── Practise_2_2_09.java ├── Practise_2_2_10.java ├── Practise_2_2_11.java ├── Practise_2_2_12.java ├── Practise_2_2_13.java ├── Practise_2_2_14.java ├── Practise_2_2_15.java ├── Practise_2_2_16.java ├── Practise_2_2_17.java ├── Practise_2_2_18.java ├── Practise_2_2_19.java ├── Practise_2_2_20.java ├── Practise_2_2_21.java ├── Practise_2_2_22.java ├── Practise_2_2_23.java ├── Practise_2_2_24.java ├── Practise_2_2_25.java ├── Practise_2_2_26.java ├── Practise_2_2_27.java ├── Practise_2_2_28.java └── Practise_2_2_29.java ├── Ch_2_3_Quicksort ├── Practise_2_3_01.java ├── Practise_2_3_02.java ├── Practise_2_3_03.java ├── Practise_2_3_04.java ├── Practise_2_3_05.java ├── Practise_2_3_06.java ├── Practise_2_3_07.java ├── Practise_2_3_08.java ├── Practise_2_3_09.java ├── Practise_2_3_10.java ├── Practise_2_3_11.java ├── Practise_2_3_12.java ├── Practise_2_3_13.java ├── Practise_2_3_14.java ├── Practise_2_3_15.java ├── Practise_2_3_16.java ├── Practise_2_3_17.java ├── Practise_2_3_18.java ├── Practise_2_3_19.java ├── Practise_2_3_20.java ├── Practise_2_3_21.java ├── Practise_2_3_22.java ├── Practise_2_3_23.java ├── Practise_2_3_24.java ├── Practise_2_3_25.java ├── Practise_2_3_26.java ├── Practise_2_3_27.java ├── Practise_2_3_28.java ├── Practise_2_3_29.java ├── Practise_2_3_30.java ├── Practise_2_3_31.java ├── __AllQuickVersionComparasion.java ├── __AllSortCompare.java ├── __ExchangesCompare.java ├── __JDKSort.java ├── __QuickImpro.java ├── __QuickReview.java ├── __QuickSort.java └── __Review.java ├── Ch_2_4_Priority_Queues ├── Practise_2_4_01.java ├── Practise_2_4_02.java ├── Practise_2_4_03.java ├── Practise_2_4_04.java ├── Practise_2_4_05.java ├── Practise_2_4_06.java ├── Practise_2_4_07.java ├── Practise_2_4_08.java ├── Practise_2_4_09.java ├── Practise_2_4_10.java ├── Practise_2_4_11.java ├── Practise_2_4_12.java ├── Practise_2_4_13.java ├── Practise_2_4_14.java ├── Practise_2_4_15.java ├── Practise_2_4_16.java ├── Practise_2_4_17.java ├── Practise_2_4_18.java ├── Practise_2_4_19.java ├── Practise_2_4_20.java ├── Practise_2_4_21.java ├── Practise_2_4_22.java ├── Practise_2_4_23.java ├── Practise_2_4_24.java ├── Practise_2_4_25.java ├── Practise_2_4_26.java ├── Practise_2_4_27.java ├── Practise_2_4_28.java ├── Practise_2_4_29.java ├── Practise_2_4_30.java ├── Practise_2_4_31.java ├── Practise_2_4_32.java ├── Practise_2_4_33.java ├── Practise_2_4_34.java ├── Practise_2_4_36.java ├── Practise_2_4_37.java ├── Practise_2_4_38.java ├── Practise_2_4_39.java ├── Practise_2_4_40.java ├── Practise_2_4_41.java ├── __HeapSort.java ├── __IndexMaxPQ.java ├── __IndexMinPQ.java ├── __MaxPQ.java ├── __MinPQ.java ├── __MultiMerge.java └── __ResizeMaxPQ.java ├── Ch_2_5_Applications ├── Practise_2_5_01.java ├── Practise_2_5_02.java ├── Practise_2_5_03.java ├── Practise_2_5_04.java ├── Practise_2_5_05.java ├── Practise_2_5_06.java ├── Practise_2_5_07.java ├── Practise_2_5_08.java ├── Practise_2_5_09.java ├── Practise_2_5_10.java ├── Practise_2_5_11.java ├── Practise_2_5_12.java ├── Practise_2_5_13.java ├── Practise_2_5_14.java ├── Practise_2_5_15.java ├── Practise_2_5_16.java ├── Practise_2_5_17.java ├── Practise_2_5_18.java ├── Practise_2_5_19.java ├── Practise_2_5_20.java ├── Practise_2_5_21.java ├── Practise_2_5_22.java ├── Practise_2_5_23.java ├── Practise_2_5_24.java ├── Practise_2_5_25.java ├── Practise_2_5_26.java ├── Practise_2_5_27.java ├── Practise_2_5_28.java ├── Practise_2_5_29.java ├── Practise_2_5_30.java ├── Practise_2_5_31.java ├── Practise_2_5_32.java └── Practise_2_5_33.java ├── Ch_3_1_Symbol_Tables ├── Practise_3_1_01.java ├── Practise_3_1_02.java ├── Practise_3_1_03.java ├── Practise_3_1_04.java ├── Practise_3_1_05.java ├── Practise_3_1_06.java ├── Practise_3_1_07.java ├── Practise_3_1_08.java ├── Practise_3_1_09.java ├── Practise_3_1_10.java ├── Practise_3_1_11.java ├── Practise_3_1_12.java ├── Practise_3_1_13.java ├── Practise_3_1_14.java ├── Practise_3_1_15.java ├── Practise_3_1_16.java ├── Practise_3_1_17.java ├── Practise_3_1_18.java ├── Practise_3_1_19.java ├── Practise_3_1_21.java ├── Practise_3_1_22.java ├── Practise_3_1_23.java ├── Practise_3_1_24.java ├── Practise_3_1_25.java ├── Practise_3_1_26.java ├── Practise_3_1_27.java ├── Practise_3_1_28.java ├── Practise_3_1_29.java ├── Practise_3_1_30.java ├── Practise_3_1_31.java ├── Practise_3_1_32.java ├── Practise_3_1_35.java ├── Practise_3_1_36.java ├── Practise_3_1_37.java ├── Practise_3_1_38.java ├── Practise_3_1_39.java ├── Practise_3_1_40.java ├── Practise_3_1_41.java ├── __BinarySearchST.java └── __SequentialSearchST.java ├── Ch_3_2_Binary_Search_Trees ├── Practise_3_2_01.java ├── Practise_3_2_02.java ├── Practise_3_2_03.java ├── Practise_3_2_04.java ├── Practise_3_2_05.java ├── Practise_3_2_06.java ├── Practise_3_2_07.java ├── Practise_3_2_08.java ├── Practise_3_2_09.java ├── Practise_3_2_10.java ├── Practise_3_2_11.java ├── Practise_3_2_12.java ├── Practise_3_2_13.java ├── Practise_3_2_14.java ├── Practise_3_2_15.java ├── Practise_3_2_16.java ├── Practise_3_2_20.java ├── Practise_3_2_21.java ├── Practise_3_2_22.java ├── Practise_3_2_23.java ├── Practise_3_2_24.java ├── Practise_3_2_25.java ├── Practise_3_2_26.java ├── Practise_3_2_27.java ├── Practise_3_2_28.java ├── Practise_3_2_29.java ├── Practise_3_2_30.java ├── Practise_3_2_31.java ├── Practise_3_2_32.java ├── Practise_3_2_33.java ├── Practise_3_2_34.java ├── Practise_3_2_36.java ├── Practise_3_2_37.java ├── Practise_3_2_38.java ├── __BST.java ├── __BST_Review.java └── __BST_traversal.java ├── Ch_3_3_Balanced_Search_Trees ├── Practise_3_3_01.java ├── Practise_3_3_02.java ├── Practise_3_3_03.java ├── Practise_3_3_04.java ├── Practise_3_3_05.java ├── Practise_3_3_07.java ├── Practise_3_3_08.java ├── Practise_3_3_09.java ├── Practise_3_3_10.java ├── Practise_3_3_11.java ├── Practise_3_3_12.java ├── Practise_3_3_13.java ├── Practise_3_3_14.java ├── Practise_3_3_15.java ├── Practise_3_3_16.java ├── Practise_3_3_17.java ├── Practise_3_3_18.java ├── Practise_3_3_20.java ├── Practise_3_3_21.java ├── Practise_3_3_22.java ├── Practise_3_3_23.java ├── Practise_3_3_24.java ├── __AVLTree.java ├── __BTree.java ├── __RBTree.java ├── doc │ └── Construct_Red_Black_Tree.pdf └── image │ ├── Ch_3_3_AVL树delete()操作.png │ ├── Ch_3_3_AVL树deleteMin()过程.png │ ├── Ch_3_3_Practise_3_3_01.png │ ├── Ch_3_3_Practise_3_3_02.png │ ├── Ch_3_3_Practise_3_3_03.png │ ├── Ch_3_3_Practise_3_3_05.png │ ├── Ch_3_3_Practise_3_3_07.png │ ├── Ch_3_3_Practise_3_3_08.png │ ├── Ch_3_3_Practise_3_3_10.png │ ├── Ch_3_3_Practise_3_3_11.png │ ├── Ch_3_3_Practise_3_3_12.png │ ├── Ch_3_3_Practise_3_3_13.png │ ├── Ch_3_3_Practise_3_3_14.png │ ├── Ch_3_3_Practise_3_3_15.png │ ├── Ch_3_3_Practise_3_3_16.png │ ├── Ch_3_3_Practise_3_3_17.png │ ├── Ch_3_3_Practise_3_3_18.png │ ├── Ch_3_3_Practise_3_3_22.png │ ├── Ch_3_3_Practise_3_3_23.png │ ├── Ch_3_3_RBTree_Put().png │ ├── Ch_3_3_RBTree_delete().png │ ├── Ch_3_3_RBTree_deleteMin()_deleteMax().png │ ├── Ch_3_3_二叉树迭代版中序遍历.png │ ├── Ch_3_3_二叉树迭代版先序遍历.png │ ├── Ch_3_3_从2-3树理解红黑树delete()操作.png │ ├── Ch_3_3_在2-3树上理解红黑树deleteMin()操作.png │ ├── Ch_3_3_在2-3树基础上理解deleteMax()操作.png │ └── Ch_3_3_用26个键构造AVL树的过程.png ├── Ch_3_3_Hash_Tables ├── __SeparateChainingHashST.java └── __SequentialSearchST.java ├── Ch_4_1_Undirected_Graphs ├── C │ ├── AdjacencyListGraph │ │ ├── AdjacencyListGraph.c │ │ ├── AdjacencyListGraph.h │ │ ├── AdjacencyListGraph_test.c │ │ ├── complie.sh │ │ ├── graph_file │ │ ├── test │ │ └── tmp │ └── AdjacencyMatrixGraph │ │ ├── AdjacencyMatrixGraph.c │ │ ├── complie.sh │ │ └── test ├── EG.java ├── Pair.java ├── Practise_4_1_01.java ├── Practise_4_1_02.java ├── Practise_4_1_03.java ├── Practise_4_1_04.java ├── Practise_4_1_05.java ├── Practise_4_1_07.java ├── Practise_4_1_08.java ├── Practise_4_1_09.java ├── Practise_4_1_10.java ├── Practise_4_1_11.java ├── Practise_4_1_13.java ├── Practise_4_1_14.java ├── Practise_4_1_15.java ├── Practise_4_1_16.java ├── Practise_4_1_17.java ├── Practise_4_1_18.java ├── Practise_4_1_19.java ├── Practise_4_1_20.java ├── Practise_4_1_21.java ├── Practise_4_1_22.java ├── Practise_4_1_23.java ├── Practise_4_1_24.java ├── Practise_4_1_25.java ├── __Bag.java ├── __Queue.java ├── __Stack.java ├── ___Graph_AdjacencyList.java ├── ___Graph_AdjacencyMatrix.java ├── ___Graph_BFS_DFS.java ├── images │ ├── Practise_4_1_01.1.png │ ├── Practise_4_1_01.2.png │ ├── Practise_4_1_02.png │ ├── Practise_4_1_09.png │ ├── Practise_4_1_11.png │ ├── Practise_4_1_14.1.png │ ├── Practise_4_1_14.2.png │ ├── Practise_4_1_18.png │ ├── Practise_4_1_19.png │ └── Practise_4_1_20.png └── slink_README.md ├── Ch_4_2_Directed_Graphs ├── DepthFirstOrder.java ├── EG.java ├── Pair.java ├── Practise_4_2_01.java ├── Practise_4_2_02.java ├── Practise_4_2_03.java ├── Practise_4_2_04.java ├── Practise_4_2_05.java ├── Practise_4_2_06.java ├── Practise_4_2_07.java ├── Practise_4_2_09.java ├── Practise_4_2_12.java ├── Practise_4_2_13.java ├── Practise_4_2_14.java ├── Practise_4_2_15.java ├── Practise_4_2_16.java ├── Practise_4_2_17.java ├── __Bag.java ├── __DiGraph.java ├── __Queue.java ├── __Stack.java └── image │ ├── DirectedCycle.png │ └── Practise_4_3_06.png ├── Ch_4_3_Minimum_Spanning_Trees ├── EG.java ├── Edge.java ├── EdgeWeightedGraph.java ├── IndexMinPQ.java ├── KruskalMST.java ├── LazyPrimMST.java ├── MinPQ.java ├── Pair.java ├── Practise_4_3_01.java ├── Practise_4_3_02.java ├── Practise_4_3_03.java ├── Practise_4_3_04.java ├── Practise_4_3_05.java ├── Practise_4_3_06.java ├── Practise_4_3_07.java ├── Practise_4_3_08.java ├── PrimMST.java ├── WeightedQuickUnion.java ├── __Bag.java ├── __Queue.java └── __Stack.java ├── Ch_4_4_Shortest_Paths ├── AcyclicLP.java ├── AcyclicSP.java ├── BellmanFordSP.java ├── CPM.java ├── DijkstraSP.java ├── DirectedEdge.java ├── EG.java ├── EdgeWeightedDigraph.java ├── EdgeWeightedDigraphCycle.java ├── IndexMinPQ.java ├── Pair.java ├── TopologicSort.java ├── __Bag.java ├── __Queue.java └── __Stack.java ├── README.md ├── Review ├── Graph │ ├── AcyclicLP.java │ ├── AcyclicSP.java │ ├── AdjMatrixEdgeWeightedDigraph.java │ ├── BellmanFordSP.java │ ├── BellmanFordSP_example_1.png │ ├── BellmanFordSP_example_2_negative_cycle.png │ ├── BellmanFordSP_test_data_negative_cycle.txt │ ├── BreadthFirstBipartite.java │ ├── BreadthFirstDirectedPath.java │ ├── BreadthFirstPath.java │ ├── BreadthFirstSearch.java │ ├── CC.java │ ├── Cycle.java │ ├── DegreesOfSeparation.java │ ├── DepthFirstBipartite.java │ ├── DepthFirstDirectedPath.java │ ├── DepthFirstOrder.java │ ├── DepthFirstPath.java │ ├── DepthFirstSearch.java │ ├── Digraph.java │ ├── DigraphGenerator.java │ ├── DijkstraAllPairSP.java │ ├── DijkstraSP.java │ ├── DijkstraSP_example_1.png │ ├── DijkstraSP_test_data.txt │ ├── DijkstraUndirectedSP.java │ ├── DirectedCycle.java │ ├── DirectedCycleX.java │ ├── DirectedEdge.java │ ├── DirectedEulerianCycle.java │ ├── DirectedEulerianPath.java │ ├── DirectedGraphDFS.java │ ├── Edge.java │ ├── EdgeWeightedDigraph.java │ ├── EdgeWeightedDirectedCycle.java │ ├── EdgeWeightedGraph.java │ ├── EulerianCycle.java │ ├── EulerianPath.java │ ├── Graph.java │ ├── GraphGenerator.java │ ├── IndexMinPQ.java │ ├── KosarajuSCC.java │ ├── KruskalMST.java │ ├── LazyPrimMST.java │ ├── MinPQ.java │ ├── NonoptimizedDijkstraSP.java │ ├── NonoptimizedDijkstraSPX.java │ ├── NonrecursiveDepthFirstPath.java │ ├── NonrecursiveDepthFirstSearch.java │ ├── NonrecursiveDirectedGraphDFS.java │ ├── PrimMST.java │ ├── Solution.java │ ├── Solution2.java │ ├── SymbolGraph.java │ ├── TarjanSCC.java │ ├── TarjanSCC_example_1.png │ ├── TarjanSCC_example_2.png │ ├── TarjanSCC_example_3.png │ ├── Topological.java │ ├── TopologicalX.java │ ├── TransitiveClosure.java │ ├── UF.java │ ├── _Bag.java │ ├── _Queue.java │ ├── _Stack.java │ ├── 寻找有向图中的环_优化方案_example_1.png │ ├── 寻找有向图中的环_优化方案_example_2.png │ ├── 寻找欧拉环_example_1.png │ ├── 寻找欧拉环_example_2.png │ └── 拓扑排序_exapmle_1.png └── README.md └── Tool └── ArrayGenerator.java /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pbxproj 3 | *.pbxproj 4 | *.xcworkspacedata 5 | *.xcuserstate 6 | *.plist 7 | slink_README.md 8 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_01.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_01 { 6 | public static void main(String[] args) { 7 | /* 8 | * 整型相除,向0舍入 9 | */ 10 | StdOut.println( (0 + 15) / 2 ); 11 | /* 12 | * 字面值是双精度 13 | */ 14 | StdOut.println( 2.0e-6 * 100000000.1); 15 | /* 16 | * && 优先级高于 || 17 | */ 18 | StdOut.println( true && false || true && true ); 19 | } 20 | // output : 21 | /* 22 | * 7 23 | 200.0000002 24 | true 25 | 26 | */ 27 | } 28 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_02.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_02 { 6 | public static void main(String[] args) { 7 | /* 8 | * 整型被提升为浮点数 9 | */ 10 | StdOut.println((1 + 2.236) / 2); 11 | /* 12 | * 整型被提升为浮点数 13 | */ 14 | StdOut.println(1 + 2 + 3 + 4.0); 15 | /* 16 | * 整型被提升为浮点数 17 | */ 18 | StdOut.println(4.1 >= 4); 19 | /* 20 | * 重载的 +,连接字符串 21 | */ 22 | StdOut.println(1 + 2 + "3"); 23 | } 24 | // output : 25 | /* 26 | * 1.618 27 | 10.0 28 | true 29 | 33 30 | 31 | */ 32 | } 33 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_03.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_03 { 6 | public static void main(String[] args) { 7 | if (args.length < 3) 8 | throw new RuntimeException("arguments amount less than required!"); 9 | int a = Integer.parseInt(args[0]); 10 | int b = Integer.parseInt(args[1]); 11 | int c = Integer.parseInt(args[2]); 12 | if(a == b && b == c) 13 | StdOut.println("equal"); 14 | else 15 | StdOut.println("not equal"); 16 | } 17 | // output : configure the envionment variables and execute to see output 18 | /* 19 | * equal 20 | */ 21 | } 22 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_04.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_04 { 6 | public static void main(String[] args) { 7 | // 太简单了不做 8 | } 9 | // output : 10 | } 11 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_05.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_05 { 6 | public static void main(String[] args) { 7 | double a = StdRandom.uniform(1.0, 1000.0), 8 | b = StdRandom.uniform(1.0, 1000.0); 9 | if((a > 0 && a < 1) && (b > 0 && b < 1)) 10 | StdOut.println("true"); 11 | else 12 | StdOut.println("false"); 13 | } 14 | // output : 15 | /* 16 | * false 17 | 18 | */ 19 | } 20 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_06.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_06 { 6 | public static void main(String[] args) { 7 | 8 | // 打印斐波那契数列前15项 9 | int f = 0; 10 | int g = 1; 11 | for(int i = 0; i <= 15; i++) { 12 | f = f + g; 13 | g = f - g; 14 | StdOut.println(f); 15 | } 16 | } 17 | // output : 18 | /* 19 | * 1 20 | 1 21 | 2 22 | 3 23 | 5 24 | 8 25 | 13 26 | 21 27 | 34 28 | 55 29 | 89 30 | 144 31 | 233 32 | 377 33 | 610 34 | 987 35 | */ 36 | } 37 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_07.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_07 { 6 | /* 7 | * 1.1.7 平方根 (牛顿迭代法) 8 | */ 9 | public static double practise_1_1_07_a(double c) { 10 | double result = c; 11 | while(Math.abs(result - c / result) > .0001) 12 | result = (c / result + result) / 2.0; 13 | return result; 14 | } 15 | public static void practise_1_1_07_a_draw() { 16 | StdDraw.setXscale(0, 100); 17 | StdDraw.setYscale(0, 15); 18 | StdDraw.setPenRadius(.001); 19 | for(double t = 1; t <= 100; t += 0.01) { 20 | double result = practise_1_1_07_a(t); 21 | StdDraw.point(t, result); 22 | } 23 | } 24 | /* 25 | * 1.1.7 b 26 | * 0 + 1 + 2 + 3 + 4 + ... + 1000 等差数列求和 27 | */ 28 | public static void practise_1_1_07_b() { 29 | int sum = 0; 30 | for(int i = 1; i < 1000; i++) 31 | for(int j = 0; j < i; j++) 32 | sum++; 33 | StdOut.println(sum); 34 | } 35 | /* 36 | * 1.1.7 c 37 | * (log2(1000)向下取整 + 1) * 1000 38 | */ 39 | public static void practise_1_1_07_c() { 40 | int sum = 0; 41 | for(int i = 1; i < 1000; i *= 2) 42 | for(int j = 0; j < 1000; j++) 43 | sum++; 44 | StdOut.println(sum); 45 | } 46 | public static void main(String[] args) { 47 | practise_1_1_07_a_draw(); 48 | practise_1_1_07_b(); 49 | practise_1_1_07_c(); 50 | } 51 | // output : execute to see graph drawing 52 | /* 53 | * 499500 54 | 10000 55 | 56 | */ 57 | } 58 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_08.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_08 { 6 | public static void main(String[] args) { 7 | /* 8 | * 两个字节的 char 9 | */ 10 | StdOut.println('b'); 11 | /* 12 | * char 被提升为 int 13 | */ 14 | StdOut.println('b' + 'c'); 15 | /* 16 | * char 被提升至 int,然后再截断为 char 17 | */ 18 | StdOut.println((char)('a' + 4)); 19 | } 20 | // output : 21 | /* 22 | * b 23 | 197 24 | e 25 | 26 | */ 27 | } 28 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_09.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_09 { 6 | public static void main(String[] args) { 7 | /* 8 | * 从位模式低位开始,拼接逐个bit 9 | */ 10 | int N = StdRandom.uniform(10000); 11 | String s = ""; 12 | for(int n = N; n > 0; n /= 2) 13 | s = (n % 2) + s; 14 | System.out.println(s); 15 | } 16 | // output : 17 | /* 18 | * 1111111100001 19 | 20 | */ 21 | } 22 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_10.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_10 { 6 | public static void main(String[] args) { 7 | // int[] a; // 没有为 a 分配内存 8 | // for(int i = 0; i < 10; i++) 9 | // a[i] = i * i; 10 | } 11 | // output : complie error 12 | } 13 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_12.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_12 { 6 | public static void main(String[] args) { 7 | int[] a = new int[10]; 8 | for(int i = 0; i < 10; i++) 9 | a[i] = 9 - i; 10 | for(int i = 0; i < 10; i++) 11 | a[i] = a[a[i]]; 12 | for(int i = 0; i < 10; i++) 13 | StdOut.print(a[i] + " "); 14 | } 15 | // output : 16 | /* 17 | * 0 1 2 3 4 4 3 2 1 0 18 | */ 19 | } 20 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_14.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_14 { 6 | public static void main(String[] args) { 7 | /* 8 | * 不使用 Math 9 | */ 10 | long N = StdRandom.uniform(1000000); 11 | long sum = 1; 12 | int count = 0; 13 | while(true) { 14 | sum *= 2; 15 | if(sum >= N) break; 16 | count++; 17 | } 18 | StdOut.println("N = " + N + " result = " + count); 19 | } 20 | // output : 21 | /* 22 | * N = 902983 result = 19 23 | 24 | */ 25 | } 26 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_15.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_15 { 6 | public static void main(String[] args) { 7 | int M = StdRandom.uniform(50); 8 | StdOut.println("M = " + M); 9 | 10 | int[] a = new int[10]; 11 | for(int i = 0; i < a.length; i++) 12 | a[i] = StdRandom.uniform(M); 13 | 14 | StdOut.println("原数组 : "); 15 | for(int i = 0; i < a.length; i++) 16 | StdOut.print(a[i] + " "); 17 | 18 | int[] arr = new int[M]; 19 | for(int i = 0; i < M; i++) { 20 | int count = 0; 21 | for(int j = 0; j < a.length; j++) 22 | if(a[j] == i) 23 | count++; 24 | arr[i] = count; 25 | } 26 | StdOut.println(); 27 | 28 | StdOut.println("结果数组 : "); 29 | for(int i = 0; i < M; i++) 30 | StdOut.print(arr[i] + " "); 31 | StdOut.println(); 32 | 33 | int sum = 0; 34 | for(int i = 0; i < arr.length; i++) 35 | sum += arr[i]; 36 | StdOut.println("========================"); 37 | StdOut.println("a.length = " + a.length); 38 | StdOut.println("返回数组之和 = " + sum); 39 | } 40 | // output : 41 | /* 42 | * M = 48 43 | 原数组 : 44 | 47 15 12 19 44 16 19 46 24 14 45 | 结果数组 : 46 | 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 47 | ======================== 48 | a.length = 10 49 | 返回数组之和 = 10 50 | 51 | */ 52 | } 53 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_16.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_16 { 6 | public static String exR1(int n) { 7 | if(n <= 0) return ""; 8 | return exR1(n - 3) + n + exR1(n - 2) + n; 9 | } 10 | public static void main(String[] args) { 11 | //311361142246 12 | StdOut.println(exR1(6)); 13 | } 14 | // output : 15 | /* 16 | * 311361142246 17 | 18 | */ 19 | } 20 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_17.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_17 { 6 | public static void main(String[] args) { 7 | /* 8 | * 递归基写在递归函数后,因此递归函数永远都不会返回 9 | * 10 | */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_18.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_18 { 6 | public static int mystery(int a, int b) { 7 | /* 8 | * 返回 a * b 9 | */ 10 | if(b == 0) return 0; 11 | if(b % 2 == 0) return mystery(a + a, b / 2); 12 | return mystery(a + a, b / 2) + a; 13 | } 14 | public static int mystery_2(int a, int b) { 15 | /* 16 | * 返回 pow(a,b) 17 | */ 18 | if(b == 0) return 1; 19 | if(b % 2 == 0) return mystery_2(a * a, b / 2); 20 | return mystery_2(a * a, b / 2) * a; 21 | } 22 | public static void main(String[] args) { 23 | StdOut.println(mystery(2, 25) + " " + mystery(3, 11)); 24 | StdOut.println(mystery_2(2, 25) + " " + mystery_2(3, 11)); 25 | } 26 | // output : 27 | /* 28 | * 50 33 29 | 33554432 177147 30 | 31 | */ 32 | } 33 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_20.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_20 { 6 | /* 7 | * 方法一 8 | */ 9 | public static double lnN(int N) { 10 | return Math.log(recursive(N)); 11 | } 12 | public static double recursive(double N) { 13 | if (N == 1 || N == 0) return 1; 14 | return recursive(N - 1) * N; 15 | } 16 | /* 17 | * 方法二 18 | */ 19 | public static double lnN2(int N) { 20 | if (N == 1 || N == 0) return 0; 21 | return lnN2(N - 1) + Math.log(N); 22 | } 23 | public static void main(String[] args) { 24 | int N = 10; 25 | for(int i = 0; i < N; i++) 26 | StdOut.println(lnN(i)); 27 | 28 | StdOut.println(); 29 | for (int i = 0; i < N; i++) 30 | StdOut.println(lnN2(i)); 31 | } 32 | // output : 33 | /* 34 | * 0.0 35 | 0.0 36 | 0.6931471805599453 37 | 1.791759469228055 38 | 3.1780538303479458 39 | 4.787491742782046 40 | 6.579251212010101 41 | 8.525161361065415 42 | 10.60460290274525 43 | 12.801827480081469 44 | 45 | 0.0 46 | 0.0 47 | 0.6931471805599453 48 | 1.791759469228055 49 | 3.1780538303479453 50 | 4.787491742782046 51 | 6.579251212010101 52 | 8.525161361065415 53 | 10.60460290274525 54 | 12.80182748008147 55 | 56 | */ 57 | } 58 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_21.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | import java.util.*; 5 | 6 | public class Practise_1_1_21 { 7 | public static void main(String[] args) { 8 | int rows = 0; 9 | Object[][] item = null; 10 | Object[][] newItem = null; 11 | String name = null; 12 | while(!(name = StdIn.readString()).equals("end")) { 13 | int number1 = StdIn.readInt(); 14 | int number2 = StdIn.readInt(); 15 | rows++; 16 | 17 | if(item != null) { 18 | Object[][] old = item; 19 | newItem = new Object[rows][]; 20 | for(int i = 0; i < rows; i++) 21 | newItem[i] = new Object[4]; 22 | for(int i = 0; i < rows - 1; i++) 23 | for(int j = 0; j < 4; j++) 24 | newItem[i][j] = old[i][j]; 25 | newItem[rows - 1][0] = name; 26 | newItem[rows - 1][1] = number1; 27 | newItem[rows - 1][2] = number2; 28 | newItem[rows - 1][3] = String.format("%.3f", (double)number1 / number2); 29 | item = newItem; 30 | } else { 31 | item = new Object[1][]; 32 | for(int i = 0; i < 1; i++) 33 | item[i] = new Object[4]; 34 | item[0][0] = name; 35 | item[0][1] = number1; 36 | item[0][2] = number2; 37 | item[0][3] = String.format("%.3f", (double)number1 / number2); 38 | newItem = item; 39 | } 40 | } 41 | StdOut.println(Arrays.deepToString(newItem)); 42 | } 43 | // output : 44 | /* 45 | * yangxiaohei 46 | 32 47 | 43 48 | yangdahei 49 | 43 50 | 54 51 | yangzhonghei 52 | 99 53 | 99 54 | end 55 | [[yangxiaohei, 32, 43, 0.744], [yangdahei, 43, 54, 0.796], [yangzhonghei, 99, 99, 1.000]] 56 | */ 57 | } 58 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_22.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | import java.util.*; 5 | 6 | public class Practise_1_1_22 { 7 | private static int depath = 0; 8 | /* 9 | * 随机数组 10 | */ 11 | public static int[] sourceArr(int N) { 12 | int[] arr = new int[N]; 13 | for(int i = 0; i < N; i++) 14 | arr[i] = StdRandom.uniform(N); 15 | Arrays.sort(arr); 16 | return arr; 17 | } 18 | /* 19 | * 测试用例 20 | */ 21 | public static void practise_1_1_22() { 22 | int[] arr = sourceArr(10000); 23 | int key = StdRandom.uniform(10000); 24 | StdOut.println("index = " + binarySearch(key, arr) + " 递归深度 = " + depath); 25 | } 26 | 27 | /* 28 | * 二分查找入口 29 | */ 30 | public static int binarySearch(int key, int a[]) { 31 | return recursiveRank(key, a, 0, a.length - 1); 32 | } 33 | 34 | /* 35 | * 递归的二分查找 36 | */ 37 | public static int recursiveRank(int key, int a[], int lo, int hi) { 38 | int mid = (lo + hi) / 2; 39 | depath++; 40 | while(lo <= hi) { 41 | if(key < a[mid]) return recursiveRank(key, a, lo, mid - 1); 42 | if(key > a[mid]) return recursiveRank(key, a, mid + 1, hi); 43 | return mid; 44 | } 45 | return -1; 46 | } 47 | public static void main(String[] args) { 48 | practise_1_1_22(); 49 | } 50 | // output : 51 | /* 52 | * index = -1 递归深度 = 14 53 | */ 54 | } 55 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_23.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | import java.util.*; 5 | 6 | public class Practise_1_1_23 { 7 | public static void practise_23(char c) { 8 | if (c != '+' && c != '-') 9 | throw new RuntimeException("not supported argument"); 10 | 11 | int[] whiteList = new In("/Users/bot/Desktop/algs4-data/largeW.txt").readAllInts(); 12 | Arrays.sort(whiteList); 13 | while(!StdIn.isEmpty()) { 14 | int number = StdIn.readInt(); 15 | if(Practise_1_1_22.binarySearch(number, whiteList) < 0) { 16 | if(c == '+') 17 | StdOut.println(number + " 不在白名单哪"); 18 | } else { 19 | if(c == '-') 20 | StdOut.println(number + " 在白名单内"); 21 | } 22 | } 23 | } 24 | public static void main(String[] args) { 25 | practise_23('+'); 26 | } 27 | // output : 28 | /* 29 | * 4 30 | 4 不在白名单哪 31 | 5 32 | 5 不在白名单哪 33 | 6 34 | 7 35 | 8 36 | 8 不在白名单哪 37 | 10 38 | 11 39 | 11 不在白名单哪 40 | 12 41 | 23 42 | 34 43 | 34 44 | 45 45 | 45 不在白名单哪 46 | */ 47 | } 48 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_24.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_24 { 6 | /* 7 | * 最大公约数递归版 8 | */ 9 | public static int Euclid(int p, int q) { 10 | StdOut.println("p = " + p + " q = " + q); 11 | if(q == 0) return p; 12 | return Euclid(q, p % q); 13 | } 14 | public static void main(String[] args) { 15 | StdOut.println(Euclid(1111111, 1234567)); 16 | } 17 | // output : 18 | /* 19 | * p = 1111111 q = 1234567 20 | p = 1234567 q = 1111111 21 | p = 1111111 q = 123456 22 | p = 123456 q = 7 23 | p = 7 q = 4 24 | p = 4 q = 3 25 | p = 3 q = 1 26 | p = 1 q = 0 27 | 1 28 | 29 | */ 30 | } 31 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_25.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_25 { 6 | public static void main(String[] args) { 7 | /* 8 | * 设有两个数 a b, 要求 a b 最大公约数 9 | * 欧几里得算法计算过程如下 : 假如在 r4 = 0 10 | * 11 | * a = q0 b + r0 12 | b = q1 r0 + r1 13 | r0 = q2 r1 + r2 14 | r1 = q3 r2 + r3 15 | r2 = q4 r3 16 | * 17 | * 我们可以知道 第 k 个余数满足 18 | * 19 | * r(k-2) = qr(k-1) + r(k) 20 | * 21 | * 因为 r(k-2) 会不断的减去 r(k-1),因此 r(k) 一定小于 r(k-1) 22 | * 因此必定存在第 N 步使得 r(k) 等于 0, 此时 r(k - 1) 即是最大公约数 23 | * 24 | * 我们知道在第 N 步时,r(N-2) = q(N)r(N-1) 因此 r(N-1) 能整除 r(N-2) 25 | * 因此 r(N-3) = q(N-1)r(N-2) + r(N-1) 26 | * = q(N-1)r(N-2) + q(N)r(N-2) 27 | * = (q(N) + q(N-1)) * r(N-2) 28 | * 29 | * 以此类推,可以知道 r(N-1) 能够整除之前步骤的所有余数,包括 a 和 b 30 | * 31 | * 假设最大公约数为 g 32 | * 根据定义,a和b可以写成g的倍数:a = mg、b = ng, 33 | * 其中 m 和 n 是自然数。因为r0 = a − q0b = mg − q0ng = (m − q0n)g,所以g整除r0。 34 | * 同理可证 g 整除每个余数r1, r2, ..., rN-1。因为最大公约数g整除rN−1,因而g ≤ rN−1。 35 | * 36 | */ 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_26.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_1_26 { 6 | public static void main(String[] args) { 7 | /* 8 | * a 和 b, c 比较后,最大的元素已经被冒泡到末位, 9 | * 再比较 b, c 可得到最后按升序排列的序列 10 | */ 11 | int a = StdRandom.uniform(100), 12 | b = StdRandom.uniform(100), 13 | c = StdRandom.uniform(100); 14 | StdOut.println("a = " + a + " b = " + b + " c = " + c); 15 | if (a > b) { int t = a; a = b; b = t; } 16 | if (a > c) { int t = a; a = c; c = t; } 17 | if (b > c) { int t = b; b = c; c = t; } 18 | StdOut.println("after compare and swap"); 19 | StdOut.println("a = " + a + " b = " + b + " c = " + c); 20 | } 21 | // output : 22 | /* 23 | * a = 39 b = 67 c = 45 24 | after compare and swap 25 | a = 39 b = 45 c = 67 26 | 27 | */ 28 | } 29 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_29.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import java.util.Arrays; 4 | 5 | import edu.princeton.cs.algs4.StdOut; 6 | import edu.princeton.cs.algs4.StdRandom; 7 | 8 | public class Practise_1_1_29 { 9 | public static int[] randomArray() { 10 | int size = 20; 11 | int[] arr = new int[size]; 12 | for(int i = 0; i < size; i++) 13 | arr[i] = StdRandom.uniform(10); 14 | Arrays.sort(arr); 15 | return arr; 16 | } 17 | public static int rank(int key, int[] arr) { 18 | int count = 0; 19 | for(int i = 0; i < arr.length; i++) 20 | if (arr[i] >= key) 21 | break; 22 | else 23 | count++; 24 | return count; 25 | } 26 | public static int count(int key, int[] arr) { 27 | int index = Practise_1_1_22.binarySearch(key, arr); 28 | if (index < 0) return 0; 29 | int beg = index, end = index; 30 | while(beg >= 0 && arr[beg] == key) beg--; 31 | while(end < arr.length && arr[end] == key) end++; 32 | beg++; 33 | end--; 34 | return end - beg + 1; 35 | } 36 | 37 | public static void main(String[] args) { 38 | int[] arr = randomArray(); 39 | StdOut.println(Arrays.toString(arr)); 40 | StdOut.println("i = " + rank(4, arr)); 41 | StdOut.println("j = " + count(4, arr)); 42 | } 43 | // output : 44 | /* 45 | * [0, 0, 0, 1, 1, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8] 46 | i = 7 47 | j = 5 48 | 49 | */ 50 | } 51 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_30.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | import edu.princeton.cs.algs4.StdRandom; 5 | 6 | public class Practise_1_1_30 { 7 | /* 8 | * 求最大公约数 9 | */ 10 | public static int gcd(int p, int q) { 11 | while(q != 0) { 12 | int r = p % q; 13 | p = q; 14 | q = r; 15 | } 16 | return p; 17 | } 18 | public static boolean[][] createArr() { 19 | int N = StdRandom.uniform(20); 20 | boolean[][] arr = new boolean[N][]; 21 | for(int i = 0; i < N; i++) 22 | arr[i] = new boolean[N]; 23 | 24 | for(int i = 0; i < N; i++) 25 | for(int j = 0; j < N; j++) 26 | arr[i][j] = gcd(i, j) == 1; 27 | return arr; 28 | } 29 | public static void printArr(boolean[][] arr) { 30 | for(int i = 0; i < arr.length; i++) { 31 | for(int j = 0; j < arr[0].length; j++) 32 | StdOut.print(arr[i][j] ? " * " : " "); 33 | StdOut.println(); 34 | } 35 | } 36 | public static void main(String[] args) { 37 | printArr(createArr()); 38 | } 39 | // output : 40 | /* 41 | * * 42 | * * * * * * * * * * * * 43 | * * * * * * 44 | * * * * * * * * 45 | * * * * * * 46 | * * * * * * * * * 47 | * * * * 48 | * * * * * * * * * * 49 | * * * * * * 50 | * * * * * * * * 51 | * * * * * 52 | * * * * * * * * * * 53 | 54 | */ 55 | } 56 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_32.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | import java.util.*; 5 | 6 | public class Practise_1_1_32 { 7 | public static void draw(double arr[], int N, double l, double r) { 8 | // 设置 x 轴的边界 9 | StdDraw.setXscale(0, r); 10 | 11 | // 设置 y 轴的边界 12 | StdDraw.setYscale(0, arr.length); 13 | 14 | // 设置笔触的大小 15 | StdDraw.setPenRadius(.001); 16 | 17 | // 分配一个 N 段的数组 18 | int[] counter = new int[N]; 19 | double[] sections = new double[N + 1]; 20 | double average = (r - l) / N; 21 | for(int i = 0; i < N + 1; i++) 22 | sections[i] = l + average * i; 23 | 24 | // 在给自区间的桶中计数 25 | for(int i = 0; i < arr.length; i++) { 26 | double elem = arr[i]; 27 | for(int j = 1; j < N + 1; j++) 28 | if (elem > sections[j - 1] && elem <= sections[j]) 29 | counter[j - 1]++; 30 | } 31 | 32 | // 绘制图像 33 | for(int i = 0; i < counter.length; i++) { 34 | double x = l + i * average; 35 | double y = counter[i]; 36 | double rw = average / 2; 37 | double rh = y; 38 | StdDraw.filledRectangle(x, y, rw, rh); 39 | } 40 | } 41 | /* 42 | * 生成一个值在 l,r 之间的随机数组 43 | */ 44 | public static double[] randomArr(double l, double r) { 45 | int N = StdRandom.uniform(100); 46 | double[] arr = new double[N]; 47 | for(int i = 0; i < N; i++) 48 | arr[i] = StdRandom.uniform(l, r); 49 | return arr; 50 | } 51 | 52 | public static void main(String[] args) { 53 | draw(randomArr(1, 3), 10, 1, 3); 54 | } 55 | // output : execute to see graph drawing 56 | } 57 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_35.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import java.util.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_1_1_35 { 7 | /* 8 | * 精确数据 9 | */ 10 | public static int SIDES = 6; 11 | public static double dist[] = new double[2 * SIDES + 1]; 12 | static { 13 | for(int i = 1; i <= SIDES; i++) 14 | for(int j = 1; j <= SIDES; j++) 15 | dist[i + j] += 1.0; 16 | for(int k = 2; k <= 2 * SIDES; k++) 17 | dist[k] /= 36.0; 18 | } 19 | /* 20 | * 实验数据 21 | */ 22 | public static double[] sidesTest(int N) { 23 | double[] counter = new double[13]; 24 | for(int i = 0; i < N; i++) { 25 | int d1 = StdRandom.uniform(1, 7); 26 | int d2 = StdRandom.uniform(1, 7); 27 | counter[d2 + d1] += 1.0; 28 | } 29 | double[] result = new double[11]; 30 | for(int i = 0; i < result.length; i++) 31 | result[i] = counter[i + 2] / N; 32 | return result; 33 | 34 | } 35 | 36 | public static void main(String[] args) { 37 | /* 38 | * 据多次实验,N 至少要 一亿次 才能使吻合程度次次都能达到小数点后三位 39 | */ 40 | int N = 100000000; 41 | double[] testResult = sidesTest(N); 42 | double[] preciseResult = dist; 43 | for(int i = 0; i < testResult.length; i++) 44 | StdOut.printf("实验 : %.3f 精确 : %.3f\n", 45 | testResult[i], preciseResult[i + 2]); 46 | } 47 | // output : 48 | /* 49 | * 实验 : 0.028 精确 : 0.028 50 | 实验 : 0.056 精确 : 0.056 51 | 实验 : 0.083 精确 : 0.083 52 | 实验 : 0.111 精确 : 0.111 53 | 实验 : 0.139 精确 : 0.139 54 | 实验 : 0.167 精确 : 0.167 55 | 实验 : 0.139 精确 : 0.139 56 | 实验 : 0.111 精确 : 0.111 57 | 实验 : 0.083 精确 : 0.083 58 | 实验 : 0.056 精确 : 0.056 59 | 实验 : 0.028 精确 : 0.028 60 | */ 61 | } 62 | -------------------------------------------------------------------------------- /Ch_1_1_Basic_Programming_Model/Practise_1_1_39.java: -------------------------------------------------------------------------------- 1 | package Ch_1_1_Basic_Programming_Model; 2 | 3 | import java.util.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_1_1_39 { 7 | /* 8 | * 随机数组 9 | */ 10 | public static int[] sourceArr(int N) { 11 | int[] arr = new int[N]; 12 | for(int i = 0; i < N; i++) 13 | arr[i] = StdRandom.uniform(100000, 1000000); 14 | Arrays.sort(arr); 15 | return arr; 16 | } 17 | /* 18 | * 有序数组寻找共同元素算法 19 | */ 20 | public static int commonCount(int[] arr1, int[] arr2) { 21 | int count = 0; 22 | int i = 0, j = 0; 23 | while(i < arr1.length && j < arr2.length) { 24 | if (arr1[i] < arr2[j]) i++; 25 | else if (arr2[j] < arr1[i]) j++; 26 | else { i++; j++; count++; } 27 | } 28 | return count; 29 | } 30 | public static void main(String[] args) { 31 | int N = 1000; 32 | int T = 10; 33 | double average = 0; 34 | for (int i = 0; i < 4; i++) { 35 | for(int loop = 0; loop < T; loop++) 36 | average += (double)commonCount(sourceArr(N), sourceArr(N)); 37 | average /= T; 38 | StdOut.println("N = " + N + " " + T + " 次实验平均值 : " + average); 39 | N *= 10; 40 | } 41 | } 42 | // output : 43 | /* 44 | * N = 1000 10 次实验平均值 : 1.7 45 | N = 10000 10 次实验平均值 : 109.57000000000001 46 | N = 100000 10 次实验平均值 : 9998.757000000001 47 | N = 1000000 10 次实验平均值 : 499726.9757 48 | */ 49 | } 50 | -------------------------------------------------------------------------------- /Ch_1_2_Data_Abstraction/Practise_1_2_01.java: -------------------------------------------------------------------------------- 1 | package Ch_1_2_Data_Abstraction; 2 | 3 | import java.awt.Color; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_1_2_01 { 7 | /* 8 | * 两点间最近距离,用红线描出 9 | */ 10 | public static void nearstDistance(int N) { 11 | StdDraw.setXscale(0, 100); 12 | StdDraw.setYscale(0, 100); 13 | StdDraw.setPenRadius(.001); 14 | Point2D[] points = new Point2D[N]; 15 | for(int i = 0; i < N; i++) { 16 | points[i] = new Point2D(StdRandom.uniform(0, 100.0), 17 | StdRandom.uniform(0, 100.0)); 18 | points[i].draw(); 19 | } 20 | 21 | double distance = Double.MAX_VALUE; 22 | int index1 = 0, index2 = 0; 23 | for(int i = 0; i < N; i++) 24 | for(int j = 0; j < N; j++) 25 | if (i != j) { 26 | double dis = points[i].distanceTo(points[j]); 27 | if (dis < distance && dis != 0) { 28 | distance = dis; 29 | index1 = i; 30 | index2 = j; 31 | } 32 | } 33 | StdOut.println("两点之间最近距离为 : " + distance); 34 | StdDraw.setPenRadius(.01); 35 | StdDraw.setPenColor(Color.red); 36 | StdDraw.line(points[index1].x(), points[index1].y(), 37 | points[index2].x(), points[index2].y()); 38 | } 39 | public static void main(String[] args) { 40 | nearstDistance(100); 41 | } 42 | // output : execute to see graphic drawing 43 | /* 44 | * 两点之间最近距离为 : 0.803675497818708 45 | */ 46 | } 47 | -------------------------------------------------------------------------------- /Ch_1_2_Data_Abstraction/Practise_1_2_04.java: -------------------------------------------------------------------------------- 1 | package Ch_1_2_Data_Abstraction; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_2_04 { 6 | public static void main(String[] args) { 7 | String string1 = "hello"; 8 | String string2 = string1; 9 | string1 = "world"; 10 | StdOut.println(string1); 11 | StdOut.println(string2); 12 | } 13 | // output : 14 | /* 15 | * world 16 | hello 17 | */ 18 | } 19 | -------------------------------------------------------------------------------- /Ch_1_2_Data_Abstraction/Practise_1_2_05.java: -------------------------------------------------------------------------------- 1 | package Ch_1_2_Data_Abstraction; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_2_05 { 6 | public static void main(String[] args) { 7 | String s = "Hello World"; 8 | s.toUpperCase(); 9 | s.substring(6, 11); 10 | StdOut.println(s); 11 | } 12 | // output : 13 | /* 14 | * Hello World 15 | */ 16 | } 17 | -------------------------------------------------------------------------------- /Ch_1_2_Data_Abstraction/Practise_1_2_06.java: -------------------------------------------------------------------------------- 1 | package Ch_1_2_Data_Abstraction; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_2_06 { 6 | public static boolean isCircularRotation(String s, String t) { 7 | return s.length() == t.length() && (s + s).contains(t); 8 | } 9 | 10 | public static void main(String[] args) { 11 | StdOut.println(isCircularRotation("12345", "45123")); 12 | } 13 | // output : 14 | /* 15 | * true 16 | */ 17 | } 18 | -------------------------------------------------------------------------------- /Ch_1_2_Data_Abstraction/Practise_1_2_07.java: -------------------------------------------------------------------------------- 1 | package Ch_1_2_Data_Abstraction; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_1_2_07 { 6 | /* 7 | * 得到原字符串的逆序 8 | */ 9 | public static String mystery(String s) { 10 | int N = s.length(); 11 | if (N <= 1) return s; 12 | String a = s.substring(0, N / 2); 13 | String b = s.substring(N / 2, N); 14 | return mystery(b) + mystery(a); 15 | } 16 | public static void main(String[] args) { 17 | StdOut.println(mystery("123456")); 18 | } 19 | // output : 20 | /* 21 | * 654321 22 | */ 23 | } 24 | -------------------------------------------------------------------------------- /Ch_1_2_Data_Abstraction/Practise_1_2_08.java: -------------------------------------------------------------------------------- 1 | package Ch_1_2_Data_Abstraction; 2 | 3 | import java.util.Arrays; 4 | 5 | import edu.princeton.cs.algs4.*; 6 | 7 | public class Practise_1_2_08 { 8 | public static int[] sourceArr(int N, int beg) { 9 | int[] a = new int[N]; 10 | for(int i = 0; i < N; i++) 11 | a[i] = beg + i; 12 | return a; 13 | } 14 | public static void main(String[] args) { 15 | int[] a = sourceArr(5, 10); 16 | int[] b = sourceArr(5, 0); 17 | StdOut.println("a = " + Arrays.toString(a)); 18 | StdOut.println("b = " + Arrays.toString(b)); 19 | int[] t = a; 20 | a = b; 21 | b = t; 22 | StdOut.println("=========================="); 23 | StdOut.println("a = " + Arrays.toString(a)); 24 | StdOut.println("b = " + Arrays.toString(b)); 25 | } 26 | // output : 27 | /* 28 | * a = [10, 11, 12, 13, 14] 29 | b = [0, 1, 2, 3, 4] 30 | ========================== 31 | a = [0, 1, 2, 3, 4] 32 | b = [10, 11, 12, 13, 14] 33 | */ 34 | } 35 | -------------------------------------------------------------------------------- /Ch_1_2_Data_Abstraction/Practise_1_2_09.java: -------------------------------------------------------------------------------- 1 | package Ch_1_2_Data_Abstraction; 2 | 3 | import java.util.Arrays; 4 | 5 | import edu.princeton.cs.algs4.StdOut; 6 | import edu.princeton.cs.algs4.StdRandom;; 7 | 8 | public class Practise_1_2_09 { 9 | static class Counter { 10 | private int count; 11 | private String id; 12 | public Counter(String id) { this.id = id; } 13 | public String toString() { 14 | return id + " " + count; 15 | } 16 | public void increment() { count++; } 17 | public int tally() { return count; } 18 | } 19 | public static int rank(int key, int[] arr, Counter counter) { 20 | int lo = 0, hi = arr.length - 1; 21 | while(lo <= hi) { 22 | int mid = (lo + hi) / 2; 23 | counter.increment(); 24 | if (key < arr[mid]) hi = mid - 1; 25 | else if (key > arr[mid]) lo = mid + 1; 26 | else return mid; 27 | } 28 | return -1; 29 | } 30 | public static int[] sourceArr(int N) { 31 | int[] arr = new int[N]; 32 | for(int i = 0; i < N; i++) 33 | arr[i] = StdRandom.uniform(0, N); 34 | Arrays.sort(arr); 35 | return arr; 36 | } 37 | public static void main(String[] args) { 38 | int N = 1000000; 39 | Counter counter = new Counter("BinarySearch check times"); 40 | int[] arr = sourceArr(N); 41 | int key = StdRandom.uniform(0, N); 42 | rank(key, arr, counter); 43 | StdOut.println("在长度为 " + N + " 的数组中查找 " + key); 44 | StdOut.println(counter); 45 | } 46 | // output : 47 | /* 48 | * 在长度为 1000000 的数组中查找 626760 49 | BinarySearch check times 20 50 | */ 51 | } 52 | -------------------------------------------------------------------------------- /Ch_1_2_Data_Abstraction/Practise_1_2_10.java: -------------------------------------------------------------------------------- 1 | package Ch_1_2_Data_Abstraction; 2 | 3 | import java.util.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_1_2_10 { 7 | 8 | static class VisualCounter { 9 | /* 10 | * 操作最大次数 11 | */ 12 | private final int N; 13 | /* 14 | * 计数器最大绝对值 15 | */ 16 | private final int max; 17 | private int value; 18 | private int opCount; 19 | public VisualCounter(int N, int max) { 20 | this.N = N; 21 | this.max = Math.abs(max); 22 | 23 | StdDraw.setXscale(0, N); 24 | StdDraw.setYscale(-max - 10, max + 10); 25 | StdDraw.setPenRadius(0.01); 26 | 27 | StdDraw.setPenColor(StdDraw.RED); 28 | StdDraw.line(0, max / 2, N + 1, max / 2); 29 | StdDraw.line(0, -max / 2 , N + 1, -max / 2); 30 | 31 | StdDraw.setPenColor(StdDraw.BLACK); 32 | StdDraw.setPenRadius(.001); 33 | } 34 | public void increment() { 35 | if (opCount < N) { 36 | opCount++; 37 | if (value < max) 38 | value++; 39 | } 40 | StdDraw.point(opCount, value); 41 | } 42 | public void decrement() { 43 | if (opCount < N) { 44 | opCount++; 45 | if (value > -max) 46 | value--; 47 | } 48 | StdDraw.point(opCount, value); 49 | } 50 | public String toString() { 51 | return "VisualCounter " + value; 52 | } 53 | } 54 | 55 | public static void main(String[] args) { 56 | int N = 10000; 57 | int max = 100; 58 | VisualCounter counter = new VisualCounter(N, max); 59 | /* 60 | * 让计数器一半概率递增,一半概率递减 61 | */ 62 | double incrementProbability = 0.5; 63 | for(int i = 0; i < N; i++) 64 | if (StdRandom.bernoulli(incrementProbability)) 65 | counter.increment(); 66 | else 67 | counter.decrement(); 68 | } 69 | // output : execute to see graphic drawing 70 | } 71 | -------------------------------------------------------------------------------- /Ch_1_3_Bags_Queues_And_Stacks/Practise_1_3_07.java: -------------------------------------------------------------------------------- 1 | package Ch_1_3_Bags_Queues_And_Stacks; 2 | 3 | import java.util.Iterator; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class Practise_1_3_07 { 7 | /* 8 | * 思路 : 9 | * 10 | * 检查栈中是否有元素,没有就返回 null 11 | * 有就返回栈顶元素而不弹出 12 | * 13 | * 14 | */ 15 | interface StackInterface { 16 | void push(T item); 17 | T pop(); 18 | T peek(); 19 | boolean isEmpty(); 20 | } 21 | static class Stack implements StackInterface, Iterable { 22 | class Node { 23 | T item; 24 | Node next; 25 | Node(T item, Node next) { this.item = item; this.next = next; } 26 | Node(T item) { this(item, null); } 27 | Node() { this(null, null); } 28 | } 29 | private Node top; 30 | public void push(T item) { 31 | top = new Node(item, top); 32 | } 33 | public T peek() { 34 | if (isEmpty()) return null; 35 | return top.item; 36 | } 37 | public T pop() { 38 | if (isEmpty()) 39 | throw new RuntimeException("stack is empty, you cannot pop a element"); 40 | T pop = top.item; 41 | top = top.next; 42 | return pop; 43 | } 44 | public boolean isEmpty() { return top == null; } 45 | public Iterator iterator() { 46 | return new Iterator() { 47 | private Node n = top; 48 | public boolean hasNext() { return n != null; } 49 | public T next() { 50 | T ret = n.item; 51 | n = n.next; 52 | return ret; 53 | } 54 | }; 55 | } 56 | } 57 | public static void main(String[] args) { 58 | Stack stack = new Stack(); 59 | for(int i = 0; i < 10; i++) 60 | stack.push(i); 61 | StdOut.println(stack.peek()); 62 | } 63 | // output : 64 | /* 65 | * 9 66 | */ 67 | } 68 | -------------------------------------------------------------------------------- /Ch_1_3_Bags_Queues_And_Stacks/Practise_1_3_09.java: -------------------------------------------------------------------------------- 1 | package Ch_1_3_Bags_Queues_And_Stacks; 2 | 3 | import static Ch_1_3_Bags_Queues_And_Stacks.Practise_1_3_04.*; 4 | 5 | import edu.princeton.cs.algs4.StdOut; 6 | 7 | public class Practise_1_3_09 { 8 | /* 9 | * 思路 : 10 | * 11 | * 准备两个栈,一个用于存放拼接字符串的结果栈,一个用于读取运算符的运算符栈 12 | * 13 | * 浏览表达式,读到 + - * '/' 就入运算符栈 14 | * 读到 右括号 就在结果栈弹两个元素出来,再把运算符栈顶元素弹出来,拼接成 补全的字符串 再放回结果栈 15 | * 16 | * 17 | */ 18 | public static String transform(String str) { 19 | LinkedListStack complete = new LinkedListStack(); 20 | LinkedListStack optr = new LinkedListStack(); 21 | Boolean continuous = false; 22 | for(String s : str.split("")) { 23 | if (s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) { 24 | optr.push(s); 25 | continuous = false; 26 | } else if (s.charAt(0) >= '0' && s.charAt(0) <= '9') { 27 | if (continuous) { 28 | complete.push(complete.pop() + s); 29 | } else { 30 | complete.push(s); 31 | continuous = true; 32 | } 33 | } else if (s.equals("(") || s.equals(")")) { 34 | continuous = false; 35 | String op2 = complete.pop(), 36 | op1 = complete.pop(), 37 | opt = optr.pop(); 38 | complete.push("(" + op1 + opt + op2 + ")"); 39 | } 40 | } 41 | return complete.pop(); 42 | } 43 | 44 | public static void main(String[] args) { 45 | StdOut.println(transform("11 + 23 ) * 33 - 44 ) * 65 - 6 ) ) )")); 46 | StdOut.println(transform("11+23)*33-44)*65-6)))")); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Ch_1_3_Bags_Queues_And_Stacks/Practise_1_3_46.java: -------------------------------------------------------------------------------- 1 | package Ch_1_3_Bags_Queues_And_Stacks; 2 | 3 | public class Practise_1_3_46 { 4 | public static void main(String[] args) { 5 | /* 6 | * 我们按照数的自然顺序依次 push 入栈,所以如果我们 pop 出了一个 c, 那么说明 a,b 已经在栈中了, 7 | * 并且如果 b > a, 说明在栈中 a 更靠近栈底位置,因此在 pop 出 b 之前,a 不可能被 pop 8 | */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_01.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | public class Practise_1_4_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * n = 3,3 * 2 * 1 / 6 = 1,加法满足交换律和结合律,三个数字的和只有一种组合 7 | * 设 n = k 时成立,则 g(k) = k(k - 1)(k - 2)/6; 8 | * 则 n = k + 1 时有 g(k + 1) 9 | * = k(k + 1)(k - 1)/6 10 | * = k(k^2 - 1)/6 11 | * = [k(k^2 - 3k + 2) + k(3k - 3)]/6 12 | * = k(k - 2)(k - 1)/6 + k(k - 1)/2 13 | * = k(k - 2)(k - 1)/6 + C(n,2) 14 | * 得证 15 | */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_02.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class Practise_1_4_02 { 6 | /* 7 | * 思路 : 8 | * 9 | * 对于 int 型的溢出,我们只需要将运算数中的某一个提升为 long, 10 | * 那么结果就会被提升为 long int 型的溢出也就被正确处理了 11 | * 12 | */ 13 | static class ThreeSum { 14 | /* 15 | * 正确处理溢出 16 | */ 17 | public static int correctCount(int[] a) { 18 | int N = a.length; 19 | int cnt = 0; 20 | for (int i = 0; i < N; i++) 21 | for (int j = i + 1; j < N; j++) 22 | for (int k = j + 1; k < N; k++) 23 | if ((long)a[i] + a[j] + a[k] == 0) 24 | cnt++; 25 | return cnt; 26 | } 27 | /* 28 | * 不处理溢出 29 | */ 30 | public static int buggyCount(int[] a) { 31 | int N = a.length; 32 | int cnt = 0; 33 | for (int i = 0; i < N; i++) 34 | for (int j = i + 1; j < N; j++) 35 | for (int k = j + 1; k < N; k++) 36 | if (a[i] + a[j] + a[k] == 0) 37 | cnt++; 38 | return cnt; 39 | } 40 | } 41 | public static void main(String[] args) { 42 | int[] arr = new int[] { Integer.MIN_VALUE, Integer.MIN_VALUE, 0}; 43 | StdOut.println("正确处理溢出 :" + ThreeSum.correctCount(arr)); 44 | StdOut.println("不处理溢出 : " + ThreeSum.buggyCount(arr)); 45 | } 46 | // output 47 | /* 48 | * 正确处理溢出 :0 49 | 不处理溢出 : 1 50 | 51 | */ 52 | } 53 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_03.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | /* 5 | * 思路 : 6 | * 7 | * ThreeSum 是一个 O(n^3) 的算法,因此倍率实验得出的值应该最终会稳定在 8 8 | * 因此我们如果对运行时间取对数,会得到一条斜率为 3 的直线 9 | * 10 | */ 11 | public class Practise_1_4_03 { 12 | static class DoublingTest { 13 | public static double timeTrial(int N) { 14 | int MAX = 1000000; 15 | int[] a = new int[N]; 16 | for (int i = 0; i < N; i++) 17 | a[i] = StdRandom.uniform(-MAX, MAX); 18 | Stopwatch timer = new Stopwatch(); 19 | ThreeSum.count(a); 20 | return timer.elapsedTime(); 21 | } 22 | public static void drawStd(int N) { 23 | StdDraw.setXscale(0, N); 24 | StdDraw.setYscale(0, 1); 25 | StdDraw.setPenRadius(.001); 26 | for (int i = 1; i < N; i++) 27 | StdDraw.point(i, timeTrial(i)); 28 | } 29 | public static void drawLgN(int N) { 30 | StdDraw.setXscale(0, N); 31 | StdDraw.setYscale(-10, 10); 32 | StdDraw.setPenRadius(.001); 33 | for (int i = 1; i < N; i++) { 34 | StdDraw.point(i, Math.log(timeTrial(i))); 35 | } 36 | } 37 | } 38 | public static void main(String[] args) { 39 | DoublingTest.drawStd(3000); 40 | DoublingTest.drawLgN(3000); 41 | } 42 | // output : execute to see drawing 43 | } 44 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_04.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | import java.util.Arrays; 4 | /* 5 | * 6 | * 思路 : 7 | * 8 | * 请见下方注释 9 | */ 10 | public class Practise_1_4_04 { 11 | static class BinarySearch { 12 | public static int rank(int k, int[] a) { 13 | int lo = 0, hi = a.length - 1; 14 | while (lo <= hi) { 15 | int mid = (lo + hi) / 2; 16 | if (a[mid] > k) hi = mid - 1; 17 | else if (a[mid] < k) lo = mid + 1; 18 | else return mid; 19 | } 20 | return -1; 21 | } 22 | } 23 | static class TwoSum { 24 | public static int count(int[] a) { 25 | /* 26 | * t0 27 | */ 28 | int cnt = 0; 29 | /* 30 | * t1 31 | */ 32 | int N = a.length; 33 | /* 34 | * N * t2 35 | */ 36 | for (int i = 0; i < N; i++) 37 | /* 38 | * 使用组合数公式为 C(n, 2) = N(N-1) / 2 39 | */ 40 | for (int j = i + 1; j < N; j++) 41 | if (a[i] + a[j] == 0) 42 | /* 43 | * x * t4 44 | */ 45 | cnt++; 46 | /* 47 | * total : t0 + t1 + N * t2 + t3 * (N^2 - N) / 2 + x * t4 48 | */ 49 | return cnt; 50 | } 51 | } 52 | static class TwoSumFast { 53 | public static int count(int[] a) { 54 | /* 55 | * t0 56 | */ 57 | int cnt = 0; 58 | /* 59 | * t1 60 | */ 61 | int N = a.length; 62 | /* 63 | * N * log(N) * t2 64 | */ 65 | Arrays.sort(a); 66 | /* 67 | * N * t3 68 | */ 69 | for (int i = 0; i < N; i++) 70 | /* 71 | * N * log(N) * t4 72 | */ 73 | if (BinarySearch.rank(-a[i], a) > i) 74 | /* 75 | * x * t5 76 | */ 77 | cnt++; 78 | /* 79 | * total : t0 + t1 + N * log(N) * t2 + N * t3 + N * log(N) * t4 + x * t5 80 | */ 81 | return cnt; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_05.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | public class Practise_1_4_05 { 4 | public static void main(String[] args) { 5 | /* 6 | * a, N + 1 ~ N 7 | * b, 1 + 1/N ~ 1 8 | * c, (1 + 1/N)(1 + 2/N) ~ 1 9 | * d, 2N^3 - 15N^2 + N ~ N^3 10 | * e, lg(2N)/lgN = (lg2 + lgN) / lgN ~1 11 | * f, lg(N^2 + 1)/lgN ~ lg(N^2)/lgN = 2lgN/lgN ~ 2 12 | * N^100/2^N ~ 0 13 | */ 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_06.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | /* 4 | * 思路 : 5 | * 6 | * 请看下方注释 7 | * 8 | */ 9 | public class Practise_1_4_06 { 10 | /* 11 | * a 12 | */ 13 | public static void a(int N) { 14 | int sum = 0; 15 | /* 16 | * 假设 N 是 2 的幂次方 17 | * N + N/2 + N/4 + N/8 + = 2N - 1 ... ~2N 18 | */ 19 | for (int n = N; n > 0; n /= 2) // -> 外循环总共执行 floor(logn) + 1 次 20 | for (int i = 0; i < n; i++) // 内循环执行 1 + 2 + 4 + 8 + .... m 总共有 floor(logn) + 1 项 21 | sum++; 22 | } 23 | /* 24 | * b 25 | */ 26 | public static void b(int N) { 27 | int sum = 0; 28 | /* 29 | * 假设 N 是 2 的幂次方 30 | * 1 + 2 + 4 + 8 + ... N = 2N - 1 ~ 2N 31 | */ 32 | for (int i = 1; i < N; i *= 2) 33 | for (int j = 0; j < i; j++) 34 | sum++; 35 | } 36 | /* 37 | * c 38 | */ 39 | public static void c(int N) { 40 | int sum = 0; 41 | /* 42 | * 1 * N + 2 * N + 4 * N + ... N * N 43 | * = N *(1 + 2 + 4 + ...N) ~ N * log(N) 44 | */ 45 | for (int i = 1; i < N; i *= 2) 46 | for (int j = 0; j < N; j++) 47 | sum++; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_07.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | /* 5 | * 思路 : 6 | * 7 | * 请看下方注释 8 | */ 9 | public class Practise_1_4_07 { 10 | static class ThreeSum { 11 | public static int count(int a[]) { 12 | int cnt = 0; 13 | int count = 0; 14 | int N = a.length; 15 | /* 16 | * following analyzation ignore the every first increment and every last comparasion 17 | */ 18 | for (int i = 0; i < N; i++) 19 | /* 20 | * N times comparison, N times increment 21 | * total 2 * N 22 | */ 23 | 24 | for (int j = i + 1; j < N; j++) 25 | /* 26 | * C(n, 2) times comparison, C(n, 2) times increment 27 | * 28 | * total N * (N - 1) 29 | */ 30 | 31 | for (int k = j + 1; k < N; k++) 32 | /* 33 | * C(n, 3) times comparison, C(n, 3) times increment 34 | * 35 | * total N * (N - 1) * (N - 2) / 3 36 | */ 37 | if (a[i] + a[j] + a[k] == 0) 38 | /* 39 | * C(n, 3) * 2 times addition, C(n, 3) times equality method 40 | * 41 | * total N * (N - 1) * (N - 2) / 2 42 | */ 43 | cnt++; 44 | StdOut.println(count); 45 | /* 46 | * total : 47 | * 2 * N + N * (N - 1) + N * (N - 1) * (N - 2) / 3 + N * (N - 1) * (N - 2) / 2 48 | * 49 | * ~ N^3 50 | */ 51 | return cnt; 52 | } 53 | } 54 | public static void main(String[] args) { 55 | int[] arr = new int[4]; 56 | ThreeSum.count(arr); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_17.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | import java.util.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_1_4_17 { 7 | /* 8 | * 最遥远的一对 9 | * 10 | * 思路 : 11 | * 12 | * 最遥远的一对一定是由最大值和最小值构成的,找出最大最小即可 13 | * 14 | * 15 | */ 16 | public static void fairestPair(double[] a) { 17 | double max = Double.MIN_VALUE; 18 | double min = Double.MAX_VALUE; 19 | for (int i = 0; i < a.length; i++) { 20 | if (a[i] < min) min = a[i]; 21 | if (a[i] > max) max = a[i]; 22 | } 23 | StdOut.printf("fairest Pair : %8.3f %8.3f", max, min); 24 | } 25 | /* 26 | * 产生已排序随机数组 27 | */ 28 | public static double[] sourceArr(int N) { 29 | double[] arr = new double[N]; 30 | for (int i = 0; i < N; i++) 31 | arr[i] = StdRandom.uniform(-100.0, 100.0); 32 | return arr; 33 | } 34 | /* 35 | * 打印数组 36 | */ 37 | public static void printArray(double[] arr) { 38 | for (int i = 0; i < arr.length; i++) 39 | if ((i + 1) % 10 == 0) 40 | StdOut.printf("%8.3f\n", arr[i]); 41 | else 42 | StdOut.printf("%8.3f", arr[i]); 43 | StdOut.println(); 44 | } 45 | public static void main(String[] args) { 46 | double[] arr = sourceArr(10); 47 | printArray(arr); 48 | fairestPair(arr); 49 | } 50 | // output 51 | /* 52 | * -25.864 47.567 0.725 -99.259 -91.011 -65.103 -13.016 75.591 -50.611 -74.727 53 | 54 | fairest Pair : 75.591 -99.259 55 | */ 56 | } 57 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_26.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | public class Practise_1_4_26 { 4 | public static void main(String[] args) { 5 | /* 6 | * 如果 A(a, a^3) B(b, b^3) C(c, c^3) 三点共线,说明 AB 和 BC 斜率相等 7 | * 8 | * (b^3 - a^3) / (b - a) = (c^3 - b^3) / (c - b) 9 | * a^2 + ab + b^2 = c^2 + cb + b^2 10 | * a^2 - c^2 + b(a - c) = 0 11 | * (a - c)(a + c) + b(a - c) = 0 12 | * (a - c)(a + b + c) = 0 13 | * 故 a = c 或者 a + b + c = 0 14 | */ 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_32.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | public class Practise_1_4_32 { 4 | /* 5 | * 思路 : 6 | * 7 | * 数组扩容后的大小序列为 2 4 8 16 32 64 ... n 8 | * 数组扩容为 2 时,访问数组 4 + 1 次 9 | * 数组扩容为 4 时,访问数组 8 + 1 10 | * 数组扩容为 8 时,需要访问数组 16 + 1 = 17 次 11 | * 扩容为 16,访问 32 + 1 = 33 次 12 | * 扩容为 32, 访问 64 + 1 = 65 次 13 | * 因此扩容为 N, 需要访问数组的次数为 N + 4 + 8 + 16 + 32 + ... + 2N = 5N - 4 ~ 5N 14 | * 15 | */ 16 | } 17 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_33.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | public class Practise_1_4_33 { 4 | /* 5 | * 对象开销 8 6 | * value 4 7 | * 8 | * 共 12 个字节 9 | * 10 | */ 11 | //Integer 12 | 13 | /* 14 | * 对象开销 8 15 | * day 4 16 | * month 4 17 | * year 共计 20 字节 18 | * 19 | * 20 | */ 21 | // Date 22 | 23 | /* 24 | * 对象开销 8 字节 25 | * int 4 字节 26 | * 27 | * 共计 12 字节 28 | */ 29 | // Counter 30 | 31 | /* 32 | * 4 字节 33 | * 34 | */ 35 | // int[] 36 | 37 | /* 38 | * 4 字节 39 | * 40 | */ 41 | // double[] 42 | 43 | /* 44 | * 4 字节 45 | */ 46 | // double[][] 47 | 48 | /* 49 | * 4 数组引用 50 | * 4 哈希值 51 | * 8 对象开销 52 | * 53 | */ 54 | // String 55 | 56 | /* 57 | * 4 Data引用 58 | * 4 next 节点引用 59 | * 60 | */ 61 | // Node 单链表 62 | 63 | /* 64 | * 4 数组引用 65 | * 8 对象开销 66 | * 4 记录尺寸 67 | * 68 | * 共计 16 69 | */ 70 | // Stack (若为动态调整的数组实现) 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_42.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | public class Practise_1_4_42 { 4 | public static void main(String[] args) { 5 | /* 6 | * T(N0) -> T0 7 | * T(2N0) -> 2^bT0 8 | * T(2^rN0) -> 2^rbT0 9 | * 令 2^r * N0 = N 10 | * r = lg(N/N0) 11 | * 12 | * T(N) -> 2^(lgN/N0 * b) * T0 13 | * T(N) -> (N/N0)^b * T0 14 | * 15 | * 对于规模为 N 的数据,需要 T = (N/N0)^b * T0 的时间才能处理完, 16 | * 假如我们能接受的运行时间是 10 分钟 17 | * 那么 T <= 600 18 | * (N/N0)^b <= 600/T0 19 | * N/N0 <= logb(600/T0) 20 | * N <= N0 * logb(600/T0) 21 | * 22 | * 使用上题得到的测试数据如下 23 | * TwoSum : 规模 : 204800 用时 : 6.813850 倍率 : 3.995221 24 | * TwoSumFast : 规模 : 104857600 用时 : 4.807600 倍率 : 1.946279 25 | * ThreeSum : 规模 : 6400 用时 : 14.256600 倍率 : 7.954360 26 | * ThreeSumFast : 规模 : 25600 用时 : 17.622100 倍率 : 4.038478 27 | * 28 | * 分别带入表达式得到 29 | * 30 | * TwoSum : N <= 204800 * log2(600/6.813850) = 1323079.3732466278 ~ 一百三十万 31 | * TwoSumFast : b = 1,不符合对数定义 即 N <= 600 / 4.807600 * 104857600 ~ 13086479740.4110158915 ~ 一百三十亿 32 | * ThreeSum : N <= 6400 * log3(600/14.256600) = 21785.794964242 ~ 两万 33 | * ThreeSumFast : N <= 25600 * log2(600/17.622100) = 130291.3212732901 ~ 十三万 34 | * 35 | * 对于 TwoSum : p = log2(N/1000) = log2(1323079.3732466278/1000) = 10.3697035252 36 | * 对于 TwoSumFast : p = log2(N/1000) = log2(13086479740.4110158915/1000) = 23.6415737291 37 | * 对于 ThreeSum : p = log2(N/1000) = log2(21785.794964242/1000) = 4.4453158531 38 | * 对于 ThreeSumFast : p = log2(N/100) = log2(130291.3212732901/1000) = 7.0255971787 39 | */ 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_44.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | import java.util.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_1_4_44 { 7 | static int totalBeforeDuplicationAppear(int N) { 8 | Set set = new HashSet(); 9 | int i; 10 | while (true) { 11 | i = StdRandom.uniform(N); 12 | if (set.contains(i)) 13 | return set.size(); 14 | else 15 | set.add(i); 16 | } 17 | } 18 | public static void main(String[] args) { 19 | int N = 10000, loop = 1000; 20 | int average = 0; 21 | for (int i = 0; i < loop; i++) 22 | average += totalBeforeDuplicationAppear(N); 23 | StdOut.printf("理论值 : %f 实验值 : %f\n", 24 | Math.sqrt(Math.PI * N / 2), average * 1.0 / loop); 25 | } 26 | // output 27 | /* 28 | * 理论值 : 125.331414 实验值 : 125.462000 29 | */ 30 | } 31 | -------------------------------------------------------------------------------- /Ch_1_4_Analysis_Of_Algorithms/Practise_1_4_45.java: -------------------------------------------------------------------------------- 1 | package Ch_1_4_Analysis_Of_Algorithms; 2 | 3 | import java.util.*; 4 | 5 | import edu.princeton.cs.algs4.*; 6 | 7 | public class Practise_1_4_45 { 8 | static int totalAfterCollectedAll(int N) { 9 | Set set = new HashSet(); 10 | int count = 0; 11 | while (!containAll(set, N)) { 12 | set.add(StdRandom.uniform(N)); 13 | count++; 14 | } 15 | return count; 16 | } 17 | static boolean containAll(Set set, int N) { 18 | for (int i = 0; i < N; i++) 19 | if (!set.contains(i)) return false; 20 | return true; 21 | } 22 | public static void main(String[] args) { 23 | int loops = 100; 24 | 25 | for (int N = 1000; N < 10000; N += 1000) { 26 | double average = 0; 27 | for (int i = 0; i < loops; i++) 28 | average += totalAfterCollectedAll(N); 29 | average /= loops; 30 | StdOut.printf("实验值 : %f N = %d, Hn = %f\n", average, N, average / N); 31 | } 32 | 33 | } 34 | // output 35 | /* 36 | * 实验值 : 7369.700000 N = 1000, Hn = 7.369700 37 | 实验值 : 16877.040000 N = 2000, Hn = 8.438520 38 | 实验值 : 25673.370000 N = 3000, Hn = 8.557790 39 | 实验值 : 36134.300000 N = 4000, Hn = 9.033575 40 | 实验值 : 46122.880000 N = 5000, Hn = 9.224576 41 | 实验值 : 55376.150000 N = 6000, Hn = 9.229358 42 | 实验值 : 64615.000000 N = 7000, Hn = 9.230714 43 | 实验值 : 76428.180000 N = 8000, Hn = 9.553523 44 | 实验值 : 88905.980000 N = 9000, Hn = 9.878442 45 | * 46 | */ 47 | } 48 | -------------------------------------------------------------------------------- /Ch_1_5_Case_Study_Union_Find/Practise_1_5_05.java: -------------------------------------------------------------------------------- 1 | package Ch_1_5_Case_Study_Union_Find; 2 | 3 | public class Practise_1_5_05 { 4 | public static void main(String[] args) { 5 | /* 6 | * 对于 quick-find 算法, 7 | * 每进行一次 union 操作,都要遍历所有的触点,以便将两个两通分量中所有触点都统一成同一个树根 8 | * 9 | * 对于每个连接, 迭代 10^9 次,总共执行 10^10 条指令,对于 10^6 个连接,总共执行 10^16 次方条指令 10 | * 每秒执行 10^9 条指令,执行完 10^16 次方条指令需要 10^7 秒 11 | * 合计 10^7 / (60 * 60 * 24) = 115.74074 天 12 | */ 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Ch_1_5_Case_Study_Union_Find/Practise_1_5_06.java: -------------------------------------------------------------------------------- 1 | package Ch_1_5_Case_Study_Union_Find; 2 | 3 | public class Practise_1_5_06 { 4 | public static void main(String[] args) { 5 | /* 6 | * weighted-quick-union 和 quick-union 的 find 操作都需要进行遍历,从当前结点直到根结点 7 | * 因此 find 操作的遍历深度正比于树深度,最坏情况也就是最大的树高度 8 | * 9 | * weighted-quick-union 构造的最大树高度为 lgN 10 | * quick-union 构造的最大树高度在最坏情况下为 N 11 | * 12 | * 以下对 weighted-quick-union 进行分析 13 | * 假设 find 操作每迭代一次执行 5 条机器指令 14 | * 每执行一次 union 操作,进行两次查找跟结点操作, 则每次 union 执行 2 * lg10^9 * 5 = 299 条机器指令 15 | * 对于 10^6 个连接,总共执行 299 * 10^6 条指令,即 2.99 * 10^8 条指令 16 | * 所以可以得到总耗时不过 2.99 * 10^-1 = 0.299 秒 17 | * 18 | */ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Ch_1_5_Case_Study_Union_Find/Practise_1_5_08.java: -------------------------------------------------------------------------------- 1 | package Ch_1_5_Case_Study_Union_Find; 2 | 3 | public class Practise_1_5_08 { 4 | /* 5 | * public void union(int p, int q) 6 | { 7 | if (connected(p, q)) return; 8 | 9 | // Rename p’s component to q’s name. 10 | 11 | // 这段代码的问题在于每次用于判断是否出于相同连通分量的 id[p] 会在循环过程中被改变 12 | // 导致本该是相同连通分量的两个触点判断失败,忽略了更改相同连通分量中的另一个触点 13 | for (int i = 0; i < id.length; i++) 14 | if (id[i] == id[p]) id[i] = id[q]; 15 | count--; 16 | } 17 | 18 | 0 1 2 3 4 5 6 7 8 9 19 | 0 1 2 3 4 5 6 7 8 9 20 | 21 | 此时 1 3 相连 22 | 0 1 2 3 4 5 6 7 8 9 23 | 0 3 2 3 4 5 6 7 8 9 24 | 25 | 在连接 1 4 时,本来应该把 索引为 1 3 4 的值都改为 4, 26 | 但因为 id[p] 的值被改了,在对比 id[3] 时进行了错误的判断,本来应该进入的 if 分支进不去了 27 | 0 1 2 3 4 5 6 7 8 9 28 | 0 4 2 3 4 5 6 7 8 9 29 | 30 | */ 31 | public static void main(String[] args) { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Ch_1_5_Case_Study_Union_Find/Practise_1_5_09.java: -------------------------------------------------------------------------------- 1 | package Ch_1_5_Case_Study_Union_Find; 2 | 3 | public class Practise_1_5_09 { 4 | public static void main(String[] args) { 5 | /* 6 | * 作出树状森林图后开始分析 7 | * 8 | * 我们的连接方式都是从某个结点向上追溯直到根结点 9 | * 然后将小树根结点连接到大树根结点上,树的大小判断不是根据高度, 10 | * 而是根据树包含的结点个数 11 | * 12 | * 如果 0 -> 1, 此时 1 规模为 2 13 | * 由图可知,要完成 3 为根结点子树的连接,必须按如下步骤 14 | * 15 | * 1, 7 -> 3 16 | * 2, 2 -> 3 17 | * 3, 3 -> 1 18 | * 19 | * 在第三步中,由于 3为根结点子树规模为 3, 而此时 1为根结点 20 | * 子树规模为 2, 不可能出现大子树连接到小子树的情况 21 | * 22 | * 现在已经可以得出该连接不会出现在加权的 QuickUnion 算法中, 23 | * 只可能出现在 QuickUnion 中 24 | * 25 | * 再分析另一侧 26 | * 要完成以 5为根结点子树的连接,必须按如下步骤 27 | * 28 | * 1,8 -> 4 29 | * 2,9 -> 5 (1,2两步顺序可以互调) 30 | * 3,4 -> 5 31 | * 32 | * 所以 5为根结点子树这个局部是可能出现的 33 | * 34 | * 现在考虑以 6为根结点子树的连接,必须按如下步骤 35 | * 36 | * 1,5 -> 6 37 | * 2,9 -> 5 (不可能出现) 38 | * 39 | * 1,5 -> 6 40 | * 2,4 -> 5 (不可能出现) 41 | * 42 | * 所以 6为根结点的子树是不可能出现的 43 | * 44 | * 综上所述,该连接的诸多子部分不可能出现,因此这个整体连接不可能出现 45 | * 46 | */ 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Ch_1_5_Case_Study_Union_Find/Practise_1_5_10.java: -------------------------------------------------------------------------------- 1 | package Ch_1_5_Case_Study_Union_Find; 2 | 3 | public class Practise_1_5_10 { 4 | public static void main(String[] args) { 5 | /* 6 | * 7 | * void union(int p, int q) { 8 | * 9 | * int pRoot = find(p); 10 | * int qRoot = find(q); 11 | * 12 | * if (pRoot == qRoot) return; 13 | * 14 | * if (size(pRoot) < size(qRoot) { 15 | * 16 | * // 把 pRoot为根结点的子树连接到 qRoot为根结点子树,说明 qRoot是包含结点多的子树 17 | * // 我们通过将小子树移接到大子树上,完成查找路径的压缩 18 | * // 从当前结点向上追溯至根结点,并将其作为需要被附着子树的结点或者作为待移接的结点,也是 19 | * // 达到路径压缩这个目的的手段之一 20 | * // 假设 A 子树在结点 u 处达到最大高度 h1,B 子树在结点 m 处达到最大高度 h2 21 | * // 根据加权 quick-union 算法进行连接,形成的新树高度将为 Min{h1, h2} 22 | * // 若将 id[find(p)] 直接连接到 q 上,会造成新树的高度为两子树高度之和 23 | * // 那么路径压缩的效果将失效 24 | * // 但是我们的 find 算法将追溯至两者的根结点,因此 connected 的正确性可以保证 25 | * 26 | * id[pRoot] = qRoot; 27 | * size[qRoot] += size[pRoot]; 28 | * } else { 29 | * id[qRoot] = pRoot; 30 | * size[pRoot] += size[qRoot]; 31 | * } 32 | * 33 | * } 34 | * 35 | */ 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Ch_1_5_Case_Study_Union_Find/__UF.java: -------------------------------------------------------------------------------- 1 | package Ch_1_5_Case_Study_Union_Find; 2 | 3 | import Tool.ArrayGenerator.RandomPair; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public abstract class __UF { 7 | public __UF(int N) { 8 | id = new int[N]; 9 | count = N; 10 | for (int i = 0; i < N; i++) 11 | id[i] = i; 12 | } 13 | protected int id[]; 14 | protected int count; 15 | abstract boolean connected(int p, int q); 16 | abstract int find(int p); 17 | abstract void union(int p, int q); 18 | public int maxTreeDepth() { return -1; } 19 | public String toString() { 20 | StringBuilder sb = new StringBuilder(); 21 | sb.append("--------------------------------\n"); 22 | sb.append("索引 :\t"); 23 | for (int i = 0; i < id.length; i++) 24 | sb.append(i + " "); 25 | sb.append("\n\t"); 26 | for (int i : id) 27 | sb.append(i + " "); 28 | sb.append(String.format(" 连通分量 : %d\n", count)); 29 | sb.append("--------------------------------\n"); 30 | return sb.toString(); 31 | } 32 | public static void test(__UF uf, int N, int pairCount) { 33 | RandomPair gen = new RandomPair(N); 34 | StdOut.println(uf); 35 | for (int i = 0; i < pairCount; i++) { 36 | int[] pair = gen.nextPair(); 37 | if (uf.connected(pair[0], pair[1])) 38 | StdOut.printf("%d %d 已连通\n", pair[0], pair[1]); 39 | else { 40 | StdOut.printf("连接 %d %d\n", pair[0], pair[1]); 41 | uf.union(pair[0], pair[1]); 42 | StdOut.println(uf); 43 | } 44 | } 45 | if (uf.maxTreeDepth() <= 0) return; 46 | StdOut.printf("最大树高度 : %d\n", uf.maxTreeDepth()); 47 | } 48 | } -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_02.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | public class Practise_2_1_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * 选择排序对输入不敏感,因此无论在任何情况下,总交换的次数都是 N 7 | * 因此每个元素只交换一次 8 | * 因此平均的交换次数为 1 9 | */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_03.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | public class Practise_2_1_03 { 4 | public static void main(String[] args) { 5 | /* 6 | * 一个元素完全相等的数组 和 一个升序数组 会让所有比较都失败 7 | * 8 | * 一个逆序数组会让所有 a[j] < a[mid] 的判断都成功,因此会使 min 不断更新 9 | */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_05.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class Practise_2_1_05 { 7 | /* 8 | * 思路 : 9 | * 10 | * 一个已经排序就位的数组,逆序对数量为0,因此每次内循环判断条件都为 false 11 | */ 12 | public static void insertionSort(int[] a) { 13 | for (int i = 1; i < a.length; i++) 14 | for (int j = i; j > 0 && condition(j, a[j], a[j - 1]); j--) { 15 | int t = a[j]; 16 | a[j] = a[j - 1]; 17 | a[j - 1] = t; 18 | } 19 | } 20 | public static boolean condition(int j, int aj, int aj1) { 21 | StdOut.println(j > 0 && aj < aj1); 22 | return j > 0 && aj < aj1; 23 | } 24 | public static void main(String[] args) { 25 | int[] arr = ascendInts(10); 26 | insertionSort(arr); 27 | } 28 | // output 29 | /* 30 | * false 31 | false 32 | false 33 | false 34 | false 35 | false 36 | false 37 | false 38 | false 39 | 40 | * 41 | */ 42 | } 43 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_06.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_1_06 { 7 | /* 8 | * 思路 : 9 | * 10 | * 插入排序快,因为一次交换都不会发生,并且只比较了 N-1 次,而选择排序对输入不敏感,在此处仍然比较了 ~N^2/2 次,交换了 N 次 11 | */ 12 | public static void insertion(int[] a) { 13 | for (int i = 1; i < a.length; i++) { 14 | int b = a[i], j; 15 | for (j = i - 1; j >= 0 && b < a[j]; j--) 16 | a[j + 1] = a[j]; 17 | a[j + 1] = b; 18 | } 19 | } 20 | public static void selection(int[] a) { 21 | for (int i = 0; i < a.length; i++) { 22 | int min = i; 23 | for (int j = i; j < a.length; j++) 24 | if (a[j] < a[min]) min = j; 25 | int t = a[i]; 26 | a[i] = a[min]; 27 | a[min] = t; 28 | } 29 | } 30 | public static void main(String[] args) { 31 | int[] arr = allSameInts(100000, 10); 32 | double t1, t2; 33 | Stopwatch timer = new Stopwatch(); 34 | insertion(arr); 35 | t1 = timer.elapsedTime(); 36 | 37 | timer = new Stopwatch(); 38 | selection(arr); 39 | t2 = timer.elapsedTime(); 40 | 41 | StdOut.printf("选择排序用时 : %.3f s\n插入排序用时 : %.3f s\n", t2, t1); 42 | } 43 | // output 44 | /* 45 | * 选择排序用时 : 1.153 s 46 | 插入排序用时 : 0.002 s 47 | * 48 | * 49 | */ 50 | } 51 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_08.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | /* 7 | * 思路 : 8 | * 9 | * 根据倍率实验,可以看出仍然是平方级别的增长率 10 | * 11 | */ 12 | public class Practise_2_1_08 { 13 | public static void insertion(int[] a) { 14 | int N = a.length; 15 | for (int i = 1; i < N; i++) 16 | for (int j = i; j > 0 && a[j] < a[j - 1]; j--) { 17 | int t = a[j]; 18 | a[j] = a[j - 1]; 19 | a[j - 1] = t; 20 | } 21 | } 22 | public static void timeTrial(int N, int T) { 23 | double pre = 0, cur = 0; 24 | for (int i = N, j = 0; j < T; i += i, j++) { 25 | Stopwatch timer = new Stopwatch(); 26 | insertion(intsVrg(i, 3, 2, 1)); 27 | cur = timer.elapsedTime(); 28 | StdOut.printf("规模为 %d 耗时 %.3f 倍率 : %.3f\n", i, cur, cur / pre); 29 | pre = cur; 30 | } 31 | } 32 | public static void main(String[] args) { 33 | timeTrial(100, 13); 34 | } 35 | // output 36 | /* 37 | * 规模为 100 耗时 0.004 倍率 : Infinity 38 | 规模为 200 耗时 0.000 倍率 : 0.000 39 | 规模为 400 耗时 0.002 倍率 : Infinity 40 | 规模为 800 耗时 0.003 倍率 : 1.500 41 | 规模为 1600 耗时 0.002 倍率 : 0.667 42 | 规模为 3200 耗时 0.013 倍率 : 6.500 43 | 规模为 6400 耗时 0.008 倍率 : 0.615 44 | 规模为 12800 耗时 0.033 倍率 : 4.125 45 | 规模为 25600 耗时 0.136 倍率 : 4.121 46 | 规模为 51200 耗时 0.510 倍率 : 3.750 47 | 规模为 102400 耗时 2.102 倍率 : 4.122 48 | 规模为 204800 耗时 8.317 倍率 : 3.957 49 | 规模为 409600 耗时 33.858 倍率 : 4.071 50 | * 51 | */ 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_11.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import java.util.*; 5 | 6 | public class Practise_2_1_11 { 7 | public static void shell(int[] a) { 8 | int N = a.length, h = 1; 9 | ArrayList list = new ArrayList(); 10 | list.add(h); 11 | while (h < N / 3) 12 | list.add((h = 3 * h + 1)); 13 | int[] hs = IntegerToInt(list.toArray()); 14 | int cursor = hs.length - 1; 15 | while (cursor >= 0) { 16 | for (int i = hs[cursor]; i < N; i++) 17 | for (int j = i; j >= hs[cursor] && a[j - 1] > a[j]; j--) { 18 | int t = a[j]; 19 | a[j] = a[j - 1]; 20 | a[j - 1] = t; 21 | } 22 | cursor--; 23 | } 24 | } 25 | public static void main(String[] args) { 26 | int[] arr = ints(30); 27 | print(arr); 28 | shell(arr); 29 | print(arr); 30 | } 31 | // output 32 | /* 33 | * 34 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 35 | -1 99 -31 48 52 83 57 -99 17 51 36 73 -9 -51 49 51 67 -40 50 10 -16 24 3 65 84 19 -48 22 85 78 36 | 37 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 38 | -99 -51 -48 -40 -31 -16 -9 -1 3 10 17 19 22 24 36 48 49 50 51 51 52 57 65 67 73 78 83 84 85 99 39 | 40 | */ 41 | } 42 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_13.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | public class Practise_2_1_13 { 4 | public static void main(String[] args) { 5 | /* 6 | * 其实这个问题就是如何排序 1111111111111 2222222222222 3333333333333 4444444444444 这个序列 7 | * 这里我们使用 1 2 3 4 分别代表 spades hearts clubs diamonds 8 | * 每个数字各有 13 个 9 | * 10 | * 选择排序法 : 11 | * 翻开第 k (k < 13) 张和第 i (i > 0) 张,找到 spades 就停止,然后交换 spades 和 第 k 张的位置 12 | * 翻开第 k (12 < k < 25) 张和第 i (i > 12) 张,找到 hearts 就停止,然后交换 hearts 和 第 k 张的位置 13 | * 翻开第 k (25 < k < 38) 张和第 i (i > 25) 张,找到 clubs 就停止,然后交换 clubs 和 第 k 张的位置 14 | * 排序结束 15 | * 16 | * 插入排序法 : 17 | * 从第 k (k > 0) 张开始,检查当前牌和前一张牌,如果后面位置的花色小,就交换两张牌, 18 | * 交换后,重复前面步骤,一旦前面花色较小,就停止,然后让 k 递增,并重复整个完整步骤 19 | * 20 | * 希尔排序法 : 21 | * 40-sorting 22 | * 13-sorting 23 | * 4-sorting 24 | * 1-sorting 25 | */ 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_18.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | public class Practise_2_1_18 { 4 | public static void main(String[] args) { 5 | /* 6 | * 请看 Practise_2_1_17 7 | * 8 | */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_20.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import java.util.Arrays; 5 | import edu.princeton.cs.algs4.StdOut; 6 | 7 | public class Practise_2_1_20 { 8 | private static int compares; 9 | public static void shell(int[] a) { 10 | int N = a.length, h = 1; 11 | while (h < N / 3) h = 3 * h + 1; 12 | while (h >= 1) { 13 | for (int i = h; i < N; i++) { 14 | int v = a[i], j; 15 | for (j = i - h; j >= 0 && less(v, a[j]); j -= h) 16 | a[j + h] = a[j]; 17 | a[j + h] = v; 18 | } 19 | h /= 3; 20 | } 21 | } 22 | public static boolean less(int a, int b) { compares++; return a < b; } 23 | public static void main(String[] args) { 24 | int[] arr = ints(1, 30); 25 | int[] copy = copy(arr); 26 | shell(arr); 27 | StdOut.printf("compares : %d\n", compares); 28 | StdOut.println(Arrays.toString(copy)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_23.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | public class Practise_2_1_23 { 4 | public static void main(String[] args) { 5 | /* 6 | * 插入排序,选择排序,希尔排序 7 | * 8 | * 请见练习 2.1.13 9 | * 10 | */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_24.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_1_24 { 7 | public static double insertion_A(int[] a) { 8 | Stopwatch timer = new Stopwatch(); 9 | int N = a.length; 10 | int min = Integer.MAX_VALUE, minIndex = 0; 11 | for (int i = 0; i < a.length; i++) 12 | if (a[i] < min) { 13 | min = a[i]; 14 | minIndex = i; 15 | } 16 | int t = a[0]; 17 | a[0] = a[minIndex]; 18 | a[minIndex] = t; 19 | for (int i = 2; i < N; i++) { 20 | for (int j = i; a[j] < a[j - 1]; j--) { 21 | t = a[j]; 22 | a[j] = a[j - 1]; 23 | a[j - 1] = t; 24 | } 25 | } 26 | return timer.elapsedTime(); 27 | } 28 | public static double insertion_B(int[] a) { 29 | Stopwatch timer = new Stopwatch(); 30 | int N = a.length; 31 | for (int i = 1; i < N; i++) 32 | for (int j = i; j > 0 && a[j] < a[j - 1]; j--) { 33 | int t = a[j]; 34 | a[j] = a[j - 1]; 35 | a[j - 1] = t; 36 | } 37 | return timer.elapsedTime(); 38 | } 39 | public static void main(String[] args) { 40 | int[] arr = ints(1, 100000); 41 | int[] copy1 = copy(arr); 42 | StdOut.printf("哨兵法 : %f\n", insertion_A(arr)); 43 | StdOut.printf("普通法 : %f\n", insertion_B(copy1)); 44 | } 45 | // output 46 | /* 47 | * 哨兵法 : 1.725000 48 | 普通法 : 4.027000 49 | */ 50 | } 51 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_25.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_1_25 { 7 | public static double insertion_A(int[] a) { 8 | Stopwatch timer = new Stopwatch(); 9 | int N = a.length; 10 | for (int i = 1; i < N; i++) { 11 | int t = a[i], j; 12 | for (j = i - 1; j >= 0 && t < a[j]; j--) 13 | a[j + 1] = a[j]; 14 | a[j + 1] = t; 15 | } 16 | return timer.elapsedTime(); 17 | } 18 | public static double insertion_B(int[] a) { 19 | Stopwatch timer = new Stopwatch(); 20 | int N = a.length; 21 | for (int i = 1; i < N; i++) 22 | for (int j = i; j > 0 && a[j - 1] > a[j]; j--) { 23 | int t = a[j]; 24 | a[j] = a[j - 1]; 25 | a[j - 1] = t; 26 | } 27 | return timer.elapsedTime(); 28 | } 29 | public static void main(String[] args) { 30 | int[] arr = ints(1, 50000); 31 | int[] copy = copy(arr); 32 | StdOut.printf("不交换 : %f\n", insertion_A(arr)); 33 | StdOut.printf("交换 : %f\n", insertion_B(copy)); 34 | } 35 | // output 36 | /* 37 | * 不交换 : 0.823000 38 | 交换 : 1.225000 39 | */ 40 | } 41 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_26.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_1_26 { 7 | public static double shell(int[] a) { 8 | Stopwatch timer = new Stopwatch(); 9 | int N = a.length, h = 1; 10 | while (h < N / 3) h = 3 * h + 1; 11 | while (h >= 1) { 12 | for (int i = h; i < N; i++) { 13 | int t = a[i], j; 14 | for (j = i - h; j >= 0 && a[j + h] < a[j]; j -= h) 15 | a[j + h] = a[j]; 16 | a[j + h] = t; 17 | } 18 | h /= 3; 19 | } 20 | return timer.elapsedTime(); 21 | } 22 | public static double shell(Integer[] a) { 23 | Stopwatch timer = new Stopwatch(); 24 | int N = a.length, h = 1; 25 | while (h < N / 3) h = 3 * h + 1; 26 | while (h >= 1) { 27 | for (int i = h; i < N; i++) { 28 | Integer t = a[i], j; 29 | for (j = i - h; j >= 0 && a[j + h].compareTo(a[j]) < 0; j -= h) 30 | a[j + h] = a[j]; 31 | a[j + h] = t; 32 | } 33 | h /= 3; 34 | } 35 | return timer.elapsedTime(); 36 | } 37 | public static void main(String[] args) { 38 | Integer[] arr = Integers(0, 4000000); 39 | int[] arr1 = IntegerToInt(arr); 40 | StdOut.printf("基本数据类型 : %f\n", shell(arr1)); 41 | StdOut.printf("包装类 : %f\n", shell(arr)); 42 | } 43 | // output 44 | /* 45 | * 基本数据类型 : 0.224000 46 | 包装类 : 5.014000 47 | */ 48 | } 49 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_33.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import java.awt.Color; 5 | import edu.princeton.cs.algs4.*; 6 | 7 | public class Practise_2_1_33 { 8 | public static double shell(int N) { 9 | int[] a = ints(N, 1, N * 10); 10 | Stopwatch timer = new Stopwatch(); 11 | int h = 1; 12 | while (h < N / 3) h = 3 * h + 1; 13 | while (h >= 1) { 14 | for (int i = h; i < N; i++) { 15 | int t = a[i], j; 16 | for (j = i - h; j >= 0 && t < a[j]; j -= h) 17 | a[j + h] = a[j]; 18 | a[j + h] = t; 19 | } 20 | h /= 3; 21 | } 22 | return timer.elapsedTime(); 23 | } 24 | public static void main(String[] args) { 25 | StdDraw.setXscale(0, 500); 26 | StdDraw.setYscale(-1, 1); 27 | double sum = 0; 28 | for (int i = 1;; i++) { 29 | StdDraw.setPenRadius(.004); 30 | StdDraw.setPenColor(Color.GRAY); 31 | double time = shell(30000); 32 | StdDraw.point(i, time); 33 | sum += time; 34 | StdDraw.setPenRadius(.002); 35 | StdDraw.setPenColor(Color.RED); 36 | StdDraw.point(i, sum / i); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/Practise_2_1_35.java: -------------------------------------------------------------------------------- 1 | package Ch_2_1_Elementary_Sorts; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_1_35 { 7 | public static double shell(double[] a) { 8 | a = copy(a); 9 | Stopwatch timer = new Stopwatch(); 10 | int N = a.length, h = 1; 11 | while (h < N / 3) h = 3 * h + 1; 12 | while (h >= 1) { 13 | for (int i = h; i < N; i++) { 14 | double t = a[i]; 15 | int j; 16 | for (j = i - h; j >= 0 && t < a[j]; j -= h) 17 | a[j + h] = a[j]; 18 | a[j + h] = t; 19 | } 20 | h /= 3; 21 | } 22 | return timer.elapsedTime(); 23 | } 24 | public static void main(String[] args) { 25 | StdOut.printf("对照试验 : %f\n", shell(doubles(4000000))); 26 | StdOut.printf("高斯分布 : %f\n", shell(gaussian(4000000, 100))); 27 | StdOut.printf("泊松分布 : %f\n", shell(possion(4000000, 100))); 28 | StdOut.printf("几何分布 : %f\n", shell(geometric(4000000, 0.4))); 29 | StdOut.printf("离散分布 : %f\n", shell(discrete(4000000, 0.3, 0.3, 0.4))); 30 | } 31 | // output 32 | /* 33 | * 对照试验 : 1.256000 34 | 高斯分布 : 1.234000 35 | 泊松分布 : 0.381000 36 | 几何分布 : 0.233000 37 | 离散分布 : 0.191000 38 | 39 | */ 40 | } 41 | -------------------------------------------------------------------------------- /Ch_2_1_Elementary_Sorts/__希尔排序完整轨迹.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_2_1_Elementary_Sorts/__希尔排序完整轨迹.png -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_01.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | public class Practise_2_2_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * A E Q S U Y E I N O S T 7 | * 8 | * A E E I N O Q S S T U Y 9 | * 10 | */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_02.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | public class Practise_2_2_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * 0 1 2 3 4 5 6 7 8 9 10 11 7 | * E A S Y Q U E S T I O N 8 | * 9 | * 0 1 10 | * A E 11 | * 12 | * 2 2 13 | * S 14 | * 15 | * 0 1 2 16 | * A E - S merge -> A E S 17 | * 18 | * 3 4 19 | * Q Y 20 | * 21 | * 5 5 22 | * U 23 | * 24 | * 3 4 5 25 | * Q Y - U merge -> Q U Y 26 | * 27 | * 0 2 5 28 | * A E S - Q U Y merge -> A E Q S U Y 29 | * 30 | * 6 7 31 | * E S 32 | * 33 | * 8 34 | * T 35 | * 36 | * 6 7 8 37 | * E S - T merge -> E S T 38 | * 39 | * 9 10 40 | * I O 41 | * 42 | * 11 43 | * N 44 | * 45 | * 9 10 11 46 | * I O - N merge -> I N O 47 | * 48 | * 6 8 11 49 | * E S T - I N O merge -> E I N O S T 50 | * 51 | * 0 5 11 52 | * A E Q S U Y - E I N O S T merge -> A E E I N O Q S S T U Y 53 | * 54 | */ 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_03.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | public class Practise_2_2_03 { 4 | private static int[] aux; 5 | public static void merge(int[] a) { 6 | int N = a.length; 7 | aux = new int[N]; 8 | for (int sz = 1; sz < N; sz += sz) 9 | for (int lo = 0; lo < N - sz; lo += 2 * sz) 10 | mergeSort(a, lo, lo + sz - 1, Math.min(lo + 2 * sz - 1, N - 1)); 11 | } 12 | private static void mergeSort(int[] a, int lo, int mid, int hi) { 13 | int i = lo, j = mid + 1; 14 | for (int k = lo; k <= hi; k++) 15 | aux[k] = a[k]; 16 | for (int k = lo; k <= hi; k++) 17 | if (i > mid) a[k] = aux[j++]; 18 | else if (j > hi) a[k] = aux[i++]; 19 | else if (a[j] < a[i]) a[k] = aux[j++]; 20 | else a[k] = aux[i++]; 21 | } 22 | public static void main(String[] args) { 23 | /* 24 | * E A S Y Q U E S T I O N 25 | * 26 | * A E S Y Q U E S I T N O sz = 1 27 | * 28 | * A E S Y E Q S U I N O T sz = 2 29 | * 30 | * A E E Q S S U Y I N O T sz = 4 31 | * 32 | * A E E I N O Q S S T U Y sz = 8 33 | */ 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_04.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | public class Practise_2_2_04 { 4 | public static void main(String[] args) { 5 | /* 6 | * 原地归并的抽象方法是一种互相让步的策略 7 | * 8 | * A : 我现在栈顶元素是 3,你的是几??如果比我小就 pop,否则把机会让给我 9 | * B : 我现在栈顶元素是 5, 你的是几??如果比我小就 pop, 否则把机会让给我 10 | * 11 | * 两个人互相谦让,所以 pop 的元素会从最小的开始,当然,这要求两个人的栈中元素都是已经按升序排列的 12 | * 13 | * 所以当且仅当两个输入的子数组都有序时,这种策略才能得到正确的结果 14 | */ 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_07.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | public class Practise_2_2_07 { 4 | public static void main(String[] args) { 5 | /* 6 | * 因为当 N 是 2的幂次方时, 比较次数 C(N) = N * log(N) 7 | * 8 | * 因此 C(N + 1) - C(N) = (N + 1) *log(N + 1) - N * log(N) 9 | * 10 | * 因为 N 和 log(N) 都是单调递增函数,而单调递增函数之积仍然是单调递增函数 11 | * 12 | * 所以 C(N) 是单调递增的 13 | */ 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_10.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_2_10 { 7 | private static int[] aux; 8 | public static double merge(int[] a) { 9 | Stopwatch timer = new Stopwatch(); 10 | aux = new int[a.length]; 11 | merge(a, 0, a.length - 1); 12 | return timer.elapsedTime(); 13 | } 14 | private static void merge(int[] a, int lo, int hi) { 15 | if (lo >= hi) return; 16 | int mid = (lo + hi) / 2; 17 | merge(a, lo, mid); 18 | merge(a, mid + 1, hi); 19 | mergeSort(a, lo, mid, hi); 20 | } 21 | private static void mergeSort(int[] a, int lo, int mid, int hi) { 22 | for (int k = lo; k <= mid; k++) 23 | aux[k] = a[k]; 24 | for (int k = mid + 1; k <= hi; k++) 25 | aux[k] = a[hi - k + 1 + mid]; 26 | int i = lo, j = hi; 27 | for (int k = lo; k <= hi; k++) 28 | if (aux[j] < aux[i]) a[k] = aux[j--]; 29 | else a[k] = aux[i++]; 30 | } 31 | public static void main(String[] args) { 32 | int[] arr = ints(20); 33 | merge(arr); 34 | print(arr); 35 | } 36 | // output 37 | /* 38 | * 39 | 0 1 2 3 4 5 6 7 8 9 40 | -8 -5 -3 -1 0 5 5 6 7 8 41 | 42 | */ 43 | } 44 | -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_13.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | public class Practise_2_2_13 { 4 | public static void main(String[] args) { 5 | /* 6 | * 对于 N 个元素 { a1,a2, a3, a4 ... an }的可能出现的所有排列方式共计 N! 种 7 | * 比如 1 2 3 4 第一个位置有 4 种,第二个位置有 3 种,以此类推共计 4! = 24 种排列方式 8 | * 所以其中 a1 < a2 < a3 < a4 ... < an 的这种排列占总排列个数的 1 / N! 9 | * 每进行一次比较,就是把最终得到的一个叶子节点划分到了 ak < am 对应的路径,或者 ak >= am 对应的路径下 10 | * 因此可以构造出一棵基于比较的二叉树,所有叶结点都是我们最终得到的排列的一种可能,而除此外的节点 11 | * 代表了比较操作 12 | * 13 | * 根据二叉树的性质,如果叶子节点有 N! 个,那么二叉树高度最少为 logN!,此时的二叉树是满二叉树 14 | * 因为从根结点到叶子结点的一条路径也就是树高代表了比较的深度,所以对于 N 个元素 15 | * 基于比较的排序算法最少比较次数为 logN! 16 | * 17 | * 因为 N! = N * (N-1) * (N-2) * ... 1 < N^N 18 | * 所以 logN! < N * logN 19 | * 因为 N! = N * (N-1) * (N-2) * ... 1 > (N/2)^(N/2) 20 | * 所以 logN! > N/2 * log(N/2) 21 | * 因此 logN! 和 N * logN 的增长率相同,我们可以说基于比较的排序算法,至少需要 N * logN 次比较 22 | */ 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_25.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | public class Practise_2_2_25 { 4 | public static void main(String[] args) { 5 | // 这题没做出来,等做完整个第二章再回过头来想想 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Ch_2_2_MergeSort/Practise_2_2_27.java: -------------------------------------------------------------------------------- 1 | package Ch_2_2_Mergesort; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_2_27 { 7 | private static int subArrLength; 8 | private static int[] aux; 9 | public static void merge(int[] a) { 10 | aux = new int[a.length]; 11 | merge(a, 0, a.length - 1); 12 | } 13 | private static void merge(int[] a, int lo, int hi) { 14 | if (lo >= hi) return; 15 | int mid = (lo + hi) / 2; 16 | merge(a, lo, mid); 17 | merge(a, mid + 1, hi); 18 | mergeSort(a, lo, mid, hi); 19 | } 20 | private static void mergeSort(int[] a, int lo, int mid, int hi) { 21 | for (int k = lo; k <= hi; k++) 22 | aux[k] = a[k]; 23 | int i = lo, j = mid + 1; 24 | for (int k = lo; k <= hi; k++) 25 | if (i > mid) { a[k] = aux[j++]; subArrLength++; } 26 | else if (j > hi) { a[k] = aux[i++]; subArrLength++; } 27 | else if (aux[j] < aux[i]) a[k] = aux[j++]; 28 | else a[k] = aux[i++]; 29 | } 30 | public static void main(String[] args) { 31 | int N = 8123053; 32 | int[] a = ints(N); 33 | merge(a); 34 | StdOut.printf("子数组平均长度 : %.3f\n", subArrLength * 1.0 / N); 35 | } 36 | // output 37 | /* 38 | * 子数组平均长度 : 1.277 39 | 40 | */ 41 | } 42 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_01.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | public class Practise_2_3_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * E A S Y Q U E S T I O N 7 | * 8 | * E A S Y Q U E S T I O N 9 | * 👆 👆 10 | * E A E Y Q U S S T I O N 11 | * 👆👆 12 | * E A E Y Q U S S T I O N 13 | * 👆 14 | * A E E Y Q U S S T I O N 15 | * 16 | * A E E Y Q U S S T I O N 17 | * 👆 18 | * A E E N Q U S S T I O Y 19 | * 👆 👆 20 | * A E E N I U S S T Q O Y 21 | * 👆👆 22 | * A E E I N U S S T Q O Y 23 | * 👆 24 | * A E E I N O S S T Q U Y 25 | * 26 | * A E E I N O S S T Q U Y 27 | * 👆👆 28 | * A E E I N O S S T Q U Y 29 | * 👆 👆 30 | * A E E I N O S Q T S U Y 31 | * 👆👆 32 | * A E E I N O Q S T S U Y 33 | * 👆 34 | * A E E I N O Q S S T U Y 35 | * 36 | * 排序完成 37 | */ 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_02.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | public class Practise_2_3_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * 7 | * 请看第一题 8 | */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_05.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class Practise_2_3_05 { 7 | /* 8 | * 针对大量重复元素,当然是三向切分的 parition 更好啦~ 9 | */ 10 | public static void quick(int[] a) { 11 | quick(a, 0, a.length - 1); 12 | } 13 | private static void quick(int[] a, int lo, int hi) { 14 | if (lo >= hi) return; 15 | int lt = lo, i = lo + 1, gt = hi, v = a[lo]; 16 | while (i <= gt) { 17 | if (a[i] > v) exch(a, i, gt--); 18 | else if (a[i] < v) exch(a, lt++, i++); 19 | else i++; 20 | } 21 | quick(a, lo, lt - 1); 22 | quick(a, gt + 1, hi); 23 | } 24 | private static void exch(int[] a, int i, int j) { 25 | int t = a[i]; a[i] = a[j]; a[j] = t; 26 | } 27 | public static void main(String[] args) { 28 | int[] a = intsVrgWithEachAmount(1000, 1, 2); 29 | quick(a); 30 | assert isSorted(a); 31 | StdOut.println("排序完成"); 32 | } 33 | // output 34 | /* 35 | * 排序完成 36 | 37 | */ 38 | } 39 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_08.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class Practise_2_3_08 { 7 | private static int compares; 8 | public static int quick(int[] a) { 9 | compares = 0; 10 | quick(a, 0, a.length - 1); 11 | return compares; 12 | } 13 | private static void quick(int[] a, int lo, int hi) { 14 | if (lo >= hi) return; 15 | int j = parition(a, lo, hi); 16 | quick(a, lo, j - 1); 17 | quick(a, j + 1, hi); 18 | } 19 | private static int parition(int[] a, int lo, int hi) { 20 | int i = lo, j = hi + 1, v = a[lo]; 21 | while (true) { 22 | while (i < hi && less(a[++i], v)); 23 | while (j > lo && less(v, a[--j])); 24 | if (i >= j) break; 25 | exch(a, i, j); 26 | } 27 | exch(a, j, lo); 28 | return j; 29 | } 30 | private static boolean less(int i, int j) { compares++; return i < j; } 31 | private static void exch(int[] a, int i, int j) { 32 | int t = a[i]; a[i] = a[j]; a[j] = t; 33 | } 34 | public static void main(String[] args) { 35 | int N = 100; 36 | int[] a = allSameInts(N, 1); 37 | quick(a); 38 | StdOut.printf("规模 : %d 比较次数 : %d 理论值 : %.0f\n", 39 | N, compares, 40 | N * (Math.log(N) / Math.log(2))); 41 | } 42 | // output 43 | /* 44 | * 规模 : 100 比较次数 : 564 理论值 : 664 45 | 46 | */ 47 | } 48 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_10.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | public class Practise_2_3_10 { 4 | public static void main(String[] args) { 5 | /* 6 | * 根据切比雪夫不等式 : P{ |X - u| >= kQ } <= 1/(k^2) 7 | * 8 | * 即描述为随机变量 X 偏离均值的距离超过 k 倍标准差的概率的上界是 1/(k^2) 9 | * 也可以描述为随机变量 X 偏离均值的距离在 k 倍标准差内的概率的下界是 1 - 1/(k^2) 10 | * 11 | * 我们知道 快速排序的平均比较次数 ~2NlnN 标准差为 0.65N 12 | * 因此假如 N = 100万,求快速排序比较次数超过 1000亿 次的概率为 13 | * 14 | * P { |X - 2NlnN| >= 10^11 } <= 1/(k^2) 15 | * 16 | * 那么我们只需要求出 k 就可以,由于 0.65Nk = 10^11 ==> k = 10^7/65 17 | * 18 | * 因此 P { |X - 2NlnN| >= 10^11 } <= 4225/(10^14) 19 | * 20 | * 我们可以得到,这个概率的上界为 0.00000000004225 21 | * 22 | * 也就是说真实的概率还要比这个值更小 23 | */ 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_13.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | public class Practise_2_3_13 { 4 | public static void main(String[] args) { 5 | /* 6 | * 最坏情况是 N-1 7 | * 比如对于升序序列,降序序列来说,每次切分都会得到一个 0 数组,一个 N - 1 数组 8 | * 所以递归深度仅比数组长度少一 9 | * 10 | * 最佳情况是 logN 11 | * 12 | * 比如所有元素都相同的数组,每次切分差不多刚好分割成相等长度的两个子数组 13 | * 所以递归深度约等于 logN 14 | * 15 | * 平均情况是 NlogN 16 | * 17 | */ 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_14.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | public class Practise_2_3_14 { 4 | public static void main(String[] args) { 5 | /* 6 | * 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_15.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | public class Practise_2_3_15 { 4 | public static void main(String[] args) { 5 | /* 6 | * 假设螺丝是 A0 A1 A2... 7 | * 假设螺帽是 B0 B1 B2 ... 8 | * 9 | * step1 :把螺丝螺帽分成两堆 10 | * 有 A8 A2 A5 A6 A4 A2 A1 A3 A9 A0 11 | * 有 B1 B8 B0 B3 B5 B2 B9 B0 B1 B7 12 | * 13 | * 取出螺丝 A8,将螺帽分成大于和小于 A8 的两堆,同时找出了 B8 14 | * 15 | * A8 和 B8 配对成功 16 | * 17 | * 此时螺帽成为如下两堆 18 | * B1 B0 B3 B5 B2 B0 B1 B7 B9 19 | * 此时用找出来的 B8 把螺丝分成大于和小于 B8 的两堆 20 | * A2 A5 A6 A4 A2 A1 A3 A0 A9 21 | * 22 | * A9 和 B9 配对成功 23 | * 24 | * 取出螺丝 A2,将螺帽分成大于和小于 A2 的两堆,同时找出了 B2 25 | * 26 | * A2 和 B2 配对成功 27 | * 28 | * 此时螺帽分成如下两堆 29 | * B1 B0 B3 B5 B0 B1 B7 30 | * 此时用找出来的 B2 把螺丝分成大于和小于 B2 的两堆 31 | * A0 A1 A5 A6 A4 A2 A3 32 | * 33 | * 重复上述步骤,直到得到所有匹配 34 | * 35 | */ 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_16.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_3_16 { 7 | public static int[] best(int N) { 8 | int[] a = new int[N]; 9 | for (int i = 0; i < N; i++) 10 | a[i] = i; 11 | best(a, 0, N - 1); 12 | return a; 13 | } 14 | private static void best(int[] a, int lo, int hi) { 15 | if (lo >= hi) return; 16 | int mid = (lo + hi) >> 1; 17 | best(a, lo, mid - 1); 18 | best(a, mid + 1, hi); 19 | exch(a, lo, mid); 20 | } 21 | private static void exch(int[] a, int i, int j) { 22 | int t = a[i]; a[i] = a[j]; a[j] = t; 23 | } 24 | public static double quick(int[] a) { 25 | Stopwatch timer = new Stopwatch(); 26 | quick(a, 0, a.length - 1); 27 | return timer.elapsedTime(); 28 | } 29 | private static void quick(int[] a, int lo, int hi) { 30 | if (lo >= hi) return; 31 | int i = lo, j = hi + 1, v = a[lo]; 32 | while (true) { 33 | while (i < hi && a[++i] < v); 34 | while (a[--j] > v); 35 | if (i >= j) break; 36 | exch(a, i, j); 37 | } 38 | exch(a, j, lo); 39 | quick(a, lo, j - 1); 40 | quick(a, j + 1, hi); 41 | } 42 | public static void main(String[] args) { 43 | int N = 10000000; 44 | int[] average = ints(0, N - 1); 45 | int[] best = best(N); 46 | StdOut.printf("平均情况 : %.3f\n", quick(average)); 47 | StdOut.printf("最佳情况 : %.3f\n", quick(best)); 48 | } 49 | // output 50 | /* 51 | * 平均情况 : 2.321 52 | 最佳情况 : 0.846 53 | */ 54 | } 55 | -------------------------------------------------------------------------------- /Ch_2_3_Quicksort/Practise_2_3_21.java: -------------------------------------------------------------------------------- 1 | package Ch_2_3_Quicksort; 2 | 3 | public class Practise_2_3_21 { 4 | public static void main(String[] args) { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_02.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * 栈无法保证在常数时间内找到最大值 7 | * 8 | * 假如最大值是 10,入栈顺序是 10 9 8 7 6 5 4 3 2 1 9 | * 10 | * 我们知道,栈是后进先出的数据结构,因此,即便我们知道最大值是10,我们也需要把 10 之前的所有元素都 11 | * 弹出,才能得到它 12 | * 换个角度,如果入栈顺序是 9 8 7 6 5 4 3 2 1 10 13 | * 我们知道,最大值是10,并且也仅需要一步操作,就可以将最大值弹出,但是接下来,我们需要弹出当前栈空间 14 | * 的最大值,第一,我们没有记录过这个最大值,因为最大值的记录会随着每次入栈操作而更新, 15 | * 因此我们仅仅只能弹出一次最大值,而不能弹出“当前栈中的最大值” 16 | * 17 | * 队列也无法保证在常数时间内找到最大值 18 | * 19 | * 假如最大值是10,入对顺序是 0 1 2 3 4 5 6 7 8 9 10 20 | * 21 | * 我们知道,队列是先进先出的数据结构,因此,即便我们知道最大值是10,我们也需要把 10 之前的所有元素都 22 | * 出队,才轮得到弹出它 23 | * 并且,我们同样无法得到第二大元素,第三大元素,以及第 k 大元素的记录 24 | * 25 | * 26 | * 27 | */ 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_04.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_04 { 4 | public static void main(String[] args) { 5 | /* 6 | * 很显然是的,树形图如下 7 | * 8 | * 10 9 | * 9 8 10 | * 7 6 5 4 11 | * 3 2 1 12 | * 13 | * 可以看出,延每个叶结点从底向上都是一条非递减的路径 14 | */ 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_07.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_07 { 4 | public static void main(String[] args) { 5 | /* 6 | * 脑补一棵二叉树的图 7 | * 8 | * k = 2 第二大的位置只可能出现在索引为 2, 3 的位置上,其他位置都不可能出现 9 | * k = 3 第三大的位置可能出现在第二层的 2, 3 结点中,也可能作为第二大结点的子结点出现在第三层,但不可能出现在第四层以及往后的位置 10 | * k = 4 第四大可能作为根结点的子结点出现在第二层,也可能作为第三大或者第二大的子结点出现在第三层,也可能作为第三大的子结点出现在第四层,但不可能出现在第五层以及往后的位置 11 | * 12 | * 13 | * 综上所述,第二大可能出现的位置是 {2, 3} 14 | * 第三大可能出现的位置是 {2, 7} 15 | * 第四大可能出现的位置是 {2, 15} 16 | */ 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_08.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_08 { 4 | public static void main(String[] args) { 5 | /* 6 | * 脑补一棵二叉树的图像 7 | * 8 | * 最小的元素可能出现在最末层,也可能出现在倒数第二层 9 | * 第二小的元素可能出现在最末层,也可能出现在倒数第二层 10 | * 第三小的元素可能出现在最末层,也可能出现在倒数第二层,倒数第三层 11 | * 第四小的元素可能出现在最末层,也可能出现在倒数第二层,倒数第三层 12 | */ 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_09.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_09 { 4 | public static void main(String[] args) { 5 | /* 6 | * 我们知道,由 A B C D E 构造出来的堆只有三层,并且根结点一定是 E 7 | * 而第二层一定是 C D,第三层一定是 A B 8 | * 9 | * 所以所有可能的情况如下所列四种 10 | * 11 | * E C D A B 12 | * 13 | * E C D B A 14 | * 15 | * E D C A B 16 | * 17 | * E D C B A 18 | * 19 | * 对于序列 A A A B B 这五个元素构造出来的堆也只有三层,根结点一定是 B 20 | * 第二层一定是 A B 第三层一定是 A A 21 | * 22 | * 所以所有可能的情况如下所列两种 23 | * 24 | * B A B A A 25 | * B B A A A 26 | */ 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_10.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_10 { 4 | public static void main(String[] args) { 5 | /* 6 | * 7 | * 设 p[k] 子结点为 SUB(k) 推理可知,0 -> 12 -> 3456 -> 7891011121314 -> ... 8 | * 9 | * SUB(k) = {左 : 2k+1, 右 : 2k+2} 10 | * 11 | * 设 p[k] 父结点为 PAR(k) 12 | * 13 | * PAR(k) = floor[(k-1)/2] 14 | * 15 | */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_12.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_12 { 4 | public static void main(String[] args) { 5 | /* 6 | * 请看 2.4.11 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_17.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_17 { 4 | public static void main(String[] args) { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_20.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_20 { 4 | public static void main(String[] args) { 5 | /* 6 | * 假设一棵满二叉树,它的根结点高度为 h, 叶结点高度为 0 7 | * 8 | * 那么高度为 h 这一层的交换次数最大为 h 9 | * 高度为 h - 1 这一层,最大交换次数为 2 * (h - 1) 10 | * 高度为 h - 2 这一层,最大交换次数为 4 * (h - 2) 11 | * ... 12 | * 13 | * 总交换次数为 h + 2 * (h - 1) + 4 * (h - 2) + ... + 2^(h - 1) 14 | * 15 | * = 2^(h + 1) - h - 2 = N - h + 1 < N 16 | * 17 | * 因为比较次数是交换次数的两倍(在交换前会进行 less(j, j + 1) 和 less(k, j) 两次比较) 18 | * 所以最坏情况下比较次数少于 2N 19 | */ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Ch_2_4_Priority_Queues/Practise_2_4_32.java: -------------------------------------------------------------------------------- 1 | package Ch_2_4_Priority_Queues; 2 | 3 | public class Practise_2_4_32 { 4 | public static void main(String[] args) { 5 | /* 6 | * 如果插入用 NloglogN 删除也只用 NloglogN 7 | * 8 | * 那么只需要先插入,然后逐个删除并添加到数组中,就完成了排序 9 | * 于是基于比较的排序算法就可以在 N*logN 次比较内完成,显然这违背了2.3节结论 10 | * 基于比较的算法 N*logN 的比较次数是最优的 11 | */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Ch_2_5_Applications/Practise_2_5_01.java: -------------------------------------------------------------------------------- 1 | package Ch_2_5_Applications; 2 | 3 | public class Practise_2_5_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * 如果内存地址相等,那么这两个字符串肯定相等,因此无需比较 7 | * 这样避免了多余的比较操作 8 | * 9 | */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ch_2_5_Applications/Practise_2_5_03.java: -------------------------------------------------------------------------------- 1 | package Ch_2_5_Applications; 2 | 3 | public class Practise_2_5_03 { 4 | public static void main(String[] args) { 5 | /* 6 | * Comparable 的比较需要满足传递性,比如 a = b b = c,那么 a = c 7 | * 8 | * 但是该实现会违反传递性 9 | * 10 | * 假设该实现是 11 | * 12 | * public int compareTo(Balance that) { 13 | * if (this.amount < that.amount - 1) return -1; 14 | * if (this.amount > that.amount + 1) return 1; 15 | * return 0; 16 | * } 17 | * 18 | * 假设 a.amount = 0 b.amount = 0.5, c.amount = 1.1 19 | * 20 | * 那么显然 a = b, b = c 成立,但是 a < c 21 | * 22 | * 违背了传递性 23 | * 24 | * 25 | * 我觉得改进方法是把 后面加减的那个数尽量设置得小一些,比如 1E-30 26 | */ 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Ch_2_5_Applications/Practise_2_5_05.java: -------------------------------------------------------------------------------- 1 | package Ch_2_5_Applications; 2 | 3 | public class Practise_2_5_05 { 4 | public static void main(String[] args) { 5 | /* 6 | * 稳定性指的是排序算法能否保留数组中重复元素的相对位置 7 | * 8 | * 那么证明选择排序是不稳定的,只需要举出一个反例即可 9 | * 10 | * 对于 元素序列 A1 B2 B3 B4 A5 主键是 "A" "B" 11 | * 12 | * 那么在排序过后变成了 A1 A5 B3 B4 B2 13 | * 14 | * 可以看到重复元素的相对顺序已经被改变 15 | * 16 | * 而对于稳定的排序比如归并排序 17 | * 18 | * 排序过后仍然是 A1 A5 B2 B3 B4 保留了重复元素的相对位置 19 | */ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Ch_2_5_Applications/Practise_2_5_15.java: -------------------------------------------------------------------------------- 1 | package Ch_2_5_Applications; 2 | 3 | public class Practise_2_5_15 { 4 | public static void main(String[] args) { 5 | /* 6 | * 用域名排序 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_2_5_Applications/Practise_2_5_27.java: -------------------------------------------------------------------------------- 1 | package Ch_2_5_Applications; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_2_5_27 { 7 | public static int[] indirectSort(int[] a) { 8 | int[] p = new int[a.length]; 9 | for (int i = 0; i < a.length; i++) 10 | p[i] = i; 11 | for (int i = 0; i < a.length; i++) { 12 | int t = a[p[i]], j, index = p[i]; 13 | for (j = i - 1; j >= 0 && t < a[p[j]]; j--) 14 | p[j + 1] = p[j]; 15 | p[j + 1] = index; 16 | } 17 | return p; 18 | } 19 | public static void main(String[] args) { 20 | int[] a = ints(0, 10); 21 | print(a); 22 | int[] p = indirectSort(a); 23 | StdOut.println(); 24 | for (int i = 0; i < p.length; i++) 25 | StdOut.print(a[p[i]] + " "); 26 | } 27 | // output 28 | /* 29 | * 30 | 0 1 2 3 4 5 6 7 8 9 10 31 | 0 7 1 10 9 6 5 3 4 2 8 32 | 33 | 0 1 2 3 4 5 6 7 8 9 10 34 | */ 35 | } 36 | -------------------------------------------------------------------------------- /Ch_2_5_Applications/Practise_2_5_28.java: -------------------------------------------------------------------------------- 1 | package Ch_2_5_Applications; 2 | 3 | import java.io.File; 4 | import edu.princeton.cs.algs4.*; 5 | import java.util.*; 6 | 7 | public class Practise_2_5_28 { 8 | public static void main(String[] args) { 9 | File directory = new File("/Users/bot/Desktop/Algorithms4/Algorithms4/src/第二章_应用"); 10 | File[] files = null; 11 | if (directory.exists() && 12 | directory.isDirectory() && 13 | (files = directory.listFiles()) != null) { 14 | } 15 | Arrays.sort(files); 16 | for (int i = 0; i < files.length; i++) 17 | StdOut.println(files[i].getName()); 18 | } 19 | // output 20 | /* 21 | * Practise_2_5_01.java 22 | Practise_2_5_02.java 23 | Practise_2_5_03.java 24 | Practise_2_5_04.java 25 | Practise_2_5_05.java 26 | Practise_2_5_06.java 27 | Practise_2_5_07.java 28 | Practise_2_5_08.java 29 | Practise_2_5_09.java 30 | Practise_2_5_10.java 31 | Practise_2_5_11.java 32 | Practise_2_5_12.java 33 | Practise_2_5_13.java 34 | Practise_2_5_14.java 35 | Practise_2_5_15.java 36 | Practise_2_5_16.java 37 | Practise_2_5_17.java 38 | Practise_2_5_18.java 39 | Practise_2_5_19.java 40 | Practise_2_5_20.java 41 | Practise_2_5_21.java 42 | Practise_2_5_22.java 43 | Practise_2_5_23.java 44 | Practise_2_5_24.java 45 | Practise_2_5_25.java 46 | Practise_2_5_26.java 47 | Practise_2_5_27.java 48 | Practise_2_5_28.java 49 | Practise_2_5_30.java 50 | Practise_2_5_31.java 51 | Practise_2_5_32.java 52 | Practise_2_5_33.java 53 | */ 54 | } 55 | -------------------------------------------------------------------------------- /Ch_2_5_Applications/Practise_2_5_31.java: -------------------------------------------------------------------------------- 1 | package Ch_2_5_Applications; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import java.util.*; 5 | import edu.princeton.cs.algs4.*; 6 | 7 | public class Practise_2_5_31 { 8 | public static int RB(int[] a, int key) { 9 | int lo = 0, hi = a.length - 1; 10 | while (lo < hi) { 11 | int mid = (lo + hi) >> 1; 12 | hi = a[mid] > key ? mid : hi; 13 | lo = a[mid] <= key ? mid + 1 : lo; 14 | } 15 | if (a[lo] == key) return lo; 16 | if (--lo < 0) return -1; 17 | return a[lo] == key ? lo : -1; 18 | } 19 | /* 20 | * 计算重复值的个数 21 | */ 22 | public static int countCommon(int[] a) { 23 | Arrays.sort(a); 24 | int cnt = 0, i = -1, right; 25 | while (++i < a.length) { 26 | if ((right = RB(a, a[i])) != i) { 27 | cnt++; 28 | i = right; 29 | } 30 | } 31 | return cnt; 32 | } 33 | /* 34 | * 计算不重复值的个数 35 | */ 36 | public static int countDistinct(int[] a) { 37 | Arrays.sort(a); 38 | int cnt = 0; 39 | for (int i = 1; i < a.length; i++) 40 | if (a[i - 1] != a[i]) 41 | cnt++; 42 | return cnt; 43 | } 44 | public static void main(String[] args) { 45 | int M = 1000000, N = 234254, T = 10, cnt = 0; 46 | for (int i = 0; i < T; i++) 47 | cnt += countDistinct(ints(N, 0, M - 1)); 48 | cnt /= T; 49 | StdOut.printf("实验值 : %d 理论值 : %d\n", cnt, (int)(M * (1 - Math.exp(-N * 1.0 / M)))); 50 | } 51 | // output 52 | /* 53 | * 实验值 : 208918 理论值 : 208839 54 | */ 55 | } 56 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_06.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_3_1_06 { 6 | public static void main(String[] args) { 7 | /* 8 | * 输入中的单词总数 W 和不同单词总数 D 9 | */ 10 | int minLen = Integer.parseInt(args[0]); 11 | ST st = new ST(); 12 | while (!StdIn.isEmpty()) { 13 | String word = StdIn.readString(); 14 | if (word.length() < minLen) continue; 15 | /* 16 | * 在这里每个单词都对应一次 put,因此此循环中 put 总数为 W 17 | * 18 | * 不同的单词总数为 D, 那么假设这 D 个单词先放入符号表,那么一次 get 都不会发生 19 | * 接下来每个单词都会触发 get, 因为不同的单词已经都放完了, 20 | * 接下来放的每一个都会和已有键重复, 因此此循环中 get 总数等于 W - D 21 | */ 22 | if (!st.contains(word)) st.put(word, 1); 23 | else st.put(word, st.get(word) + 1); 24 | } 25 | String max = " "; 26 | /* 27 | * put 1次 28 | */ 29 | st.put(max, 0); 30 | for (String word : st.keys()) 31 | if (st.get(word) > st.get(max)) // 这里的 get 次数为不同的单词数 * 2 = 2 * D 32 | max = word; 33 | StdOut.println(max + " " + st.get(max)); // 这里有的 get 1次 34 | /* 35 | * 所以总的 put 次数为 W + 1 36 | * 总的 get 次数为 W - D + 2 * D + 1 = W + D + 1 37 | */ 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_07.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_3_1_07 { 7 | public static void main(String[] args) { 8 | 9 | for (int N = 10, j = 1; j <= 6; N *= 10, j++) { 10 | ST st = new ST(); 11 | for (Integer i : Integers(N, 0, 1000 - 1)) { 12 | if (st.contains(i)) 13 | st.put(i, st.get(i) + 1); 14 | else 15 | st.put(i, 1); 16 | } 17 | StdOut.printf("规模 : %d, 总共能找到 : %d 个不同的键\n",N, st.size()); 18 | } 19 | } 20 | // output 21 | /* 22 | * 规模 : 10, 总共能找到 : 10 个不同的键 23 | 规模 : 100, 总共能找到 : 94 个不同的键 24 | 规模 : 1000, 总共能找到 : 637 个不同的键 25 | 规模 : 10000, 总共能找到 : 1000 个不同的键 26 | 规模 : 100000, 总共能找到 : 1000 个不同的键 27 | 规模 : 1000000, 总共能找到 : 1000 个不同的键 28 | 29 | */ 30 | } 31 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_08.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_3_1_08 { 6 | public static void main(String[] args) { 7 | String[] all = new In("/Users/bot/Desktop/algs4-data/tale.txt").readAll().split("\\s+"); 8 | ST st = new ST(); 9 | for (String s : all) { 10 | if (s.length() < 10) continue; 11 | if (st.contains(s)) 12 | st.put(s, st.get(s) + 1); 13 | else 14 | st.put(s, 1); 15 | } 16 | String max = " "; 17 | st.put(max, 0); 18 | for (String key : st.keys()) { 19 | if (st.get(key) > st.get(max)) 20 | max = key; 21 | } 22 | StdOut.printf("出现频率最高的单词是 : %s 总共出现 %d 次\n", max, st.get(max)); 23 | } 24 | // output 25 | /* 26 | * 出现频率最高的单词是 : monseigneur 总共出现 101 次 27 | 28 | */ 29 | } 30 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_09.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | import edu.princeton.cs.algs4.*; 4 | 5 | public class Practise_3_1_09 { 6 | public static void main(String[] args) { 7 | int count = 0; String last = null; 8 | String[] all = new In("/Users/bot/Desktop/algs4-data/tale.txt").readAll().split("\\s+"); 9 | ST st = new ST(); 10 | for (String s : all) { 11 | if (s.length() < 10) continue; 12 | count++; 13 | last = s; 14 | if (st.contains(s)) 15 | st.put(s, st.get(s) + 1); 16 | else 17 | st.put(s, 1); 18 | } 19 | StdOut.printf("最后一个插入的单词是 : %s 此前总共处理了 %d 个单词\n", last, count - 1); 20 | } 21 | // output 22 | /* 23 | * 最后一个插入的单词是 : known 此前总共处理了 135642 个单词 24 | 25 | * 最后一个插入的单词是 : faltering 此前总共处理了 14345 个单词 26 | 27 | * 最后一个插入的单词是 : disfigurement 此前总共处理了 4578 个单词 28 | 29 | */ 30 | } 31 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_10.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_10 { 4 | public static void main(String[] args) { 5 | /* 6 | * E A S Y Q U E S T I O N 7 | * 8 | * 插入 E 9 | * 10 | * header -> E 0 11 | * 12 | * 插入 A 13 | * 14 | * header -> A -> E 1 15 | * 16 | * 插入 S 17 | * 18 | * header -> S -> A -> E 2 19 | * 20 | * 插入 Y 21 | * 22 | * header -> Y -> S -> A -> E 3 23 | * 24 | * 插入 Q 25 | * 26 | * header -> Q -> Y -> S -> A -> E 4 27 | * 28 | * 插入 U 29 | * 30 | * header -> U -> Q -> Y -> S -> A -> E 5 31 | * 32 | * 插入 E 33 | * 34 | * header -> U -> Q -> Y -> S -> A -> E 6 35 | * 36 | * 插入 S 37 | * 38 | * header -> S -> U -> Q -> Y -> S -> A -> E 6 39 | * 40 | * 插入 T 41 | * 42 | * header -> T -> S -> U -> Q -> Y -> S -> A -> E 7 43 | * 44 | * 插入 I 45 | * 46 | * header -> I -> T -> S -> Q -> Y -> S -> A -> E 8 47 | * 48 | * 插入 O 49 | * 50 | * header -> O -> I -> T -> S -> Q -> Y -> S -> A -> E 9 51 | * 52 | * 插入 N 53 | * 54 | * header -> N -> O -> I -> T -> S -> Q -> Y -> S -> A -> E 10 55 | * 56 | * 57 | * 总共进行了 1 + 2 + 3 + 4 + 5 + 6 + 6 + 7 + 8 + 9 + 10 = 61次比较 58 | * 59 | */ 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_13.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_13 { 4 | public static void main(String[] args) { 5 | /* 6 | * get 远大于 put 7 | * 8 | * 我选有序数组,get 操作使用二分查找,每次只需要 O(log(N)) 9 | * 对无序数组,有序链表,无序链表,get 都需要 O(N) 10 | * 11 | */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_14.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_14 { 4 | public static void main(String[] args) { 5 | /* 6 | * 可以用无序链表,无序数组,这样的话 put 都只需要 O(1) 7 | * 对于有序链表和有序数组 put 均需要 O(N) 8 | * 9 | */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_16.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_16 { 4 | /* 5 | * 请看 3.1.11 6 | */ 7 | } 8 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_17.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_17 { 4 | /* 5 | * 请看 3.1.11 6 | */ 7 | } 8 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_18.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_18 { 4 | public static void main(String[] args) { 5 | /* 6 | * 设想一个序列 .....3 5....... 7 | * 我们现在要查找键 4 8 | * 9 | * 假设某一步 mid 命中了 3 那么由于 3 < 4 所以 lo 指向了 5,接下来 lo 在跳出循环前都不会改变 10 | * 因为右边的所有数字都大于 4,所以最后 lo 指向一个大于 4 的最小整数的位置 11 | * 12 | * 假设某一步 mid 命中了 5, 那么由于 5 > 4 所以 hi 指向了 3, 接下来 hi 在跳出循环前都不会改变 13 | * 因为左边所有数字都小于 4,因为循环跳出条件是 lo > hi,所以最后 lo 指向了 5 14 | * 15 | * 综上所述,当查找目标没有被命中时,lo 指向查找目标比查找目标大的最小整数位置 16 | */ 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_21.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_21 { 4 | public static void main(String[] args) { 5 | /* 6 | * 对于 SequentailSearchST 一个结点包含了 key 和 value 的引用, 同时还有 16 字节对象固定开销 7 | * 所以没创建一个新结点就增加 16 + 8 + 8 = 32 字节内存使用 8 | * 9 | * 对于 N 对键值,也就使用了 32N 字节的内存 10 | * 11 | * 对于 BinarySearchST 两个数组各表示 key 和 value, 对象固定开销为 32字节 12 | * 其间涉及到数组的缩容和扩容操作,那么 N 个键数组的最小尺寸为 N, 最大尺寸为 4N 13 | * 所以内存使用为 8N ~ 32N, 再加上值数组的内存使用,总共为 16N ~ 64N 14 | * 所以 BinarySearchST 的内存使用为 (16N + 32) ~ (64N + 32) 15 | * 16 | * 17 | */ 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_23.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import java.util.Arrays; 5 | import edu.princeton.cs.algs4.StdOut; 6 | 7 | public class Practise_3_1_23 { 8 | private static int compares; 9 | public static int binarySearch(int[] a, int key) { 10 | int lo = 0, hi = a.length - 1; 11 | while (lo <= hi) { 12 | int mid = (lo + hi) >> 1; 13 | int less = compare(a[mid], key); 14 | if (less < 0) lo = mid + 1; 15 | else if (less > 0) hi = mid - 1; 16 | else return mid; 17 | } 18 | return -1; 19 | } 20 | public static int compare(int i, int j) { 21 | compares++; 22 | return i - j; 23 | } 24 | public static void main(String[] args) { 25 | int N = 1000, k = 1; 26 | int[] a = ints(0, N - 1); 27 | Arrays.sort(a); 28 | StdOut.println("k 的索引为 : " + binarySearch(a, k)); 29 | StdOut.println("比较次数 : " + compares); 30 | StdOut.println("N 的二进制长度 : " + Integer.toBinaryString(N).length()); 31 | } 32 | // output 33 | /* 34 | * k 的索引为 : 1 35 | 比较次数 : 10 36 | N 的二进制长度 : 10 37 | 38 | */ 39 | } 40 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_27.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_27 { 4 | public static void main(String[] args) { 5 | /* 6 | * 7 | * lg1 + lg2 + lg3 + ... + lgN 8 | * 9 | * = lgN! 10 | * 11 | * 12 | */ 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_28.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_28 { 4 | public static void main(String[] args) { 5 | /* 6 | * 在 put 里面加个判断,如果大于最大值,那么就不进行二分查找, 7 | * 直接走扩容然后插入那一套 8 | * 9 | * 请看 3.1.26 10 | * 11 | */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_29.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_29 { 4 | public static void main(String[] args) { 5 | /* 6 | * 太简单了不做 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_30.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_30 { 4 | public static void main(String[] args) { 5 | /* 6 | * 太简单不做 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_32.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class Practise_3_1_32 { 7 | public static void main(String[] args) { 8 | Practise_3_1_26.ST st = new Practise_3_1_26.ST(); 9 | int N = 1000; 10 | Integer[] ascend = ascendIntegers(0, N - 1); 11 | Integer[] descend = descendIntegers(N - 1, 0); 12 | Integer[] allSame = intToInteger(allSameInts(N, 5)); 13 | Integer[] twoValue = intToInteger(intsVrg(N, 1, 2)); 14 | // for (Integer i : ascend) 15 | // st.put(i, "A"); 16 | // StdOut.println(st); 17 | // for (Integer i : descend) 18 | // st.put(i, "A"); 19 | // StdOut.println(st); 20 | // for (Integer i : allSame) 21 | // st.put(i, "A"); 22 | // StdOut.println(st); 23 | for (Integer i : twoValue) 24 | st.put(i, "A"); 25 | StdOut.println(st); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_36.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | public class Practise_3_1_36 { 4 | public static void main(String[] args) { 5 | /* 6 | * put 操作在查找符号表中是否有与新添加的重复的键时,SequentialSearchST 按照顺序查找,耗时 O(N) 7 | * 而有序符号表使用二分查找,耗时 O(lgN) 一个是平方级别,一个是线性对数级别 8 | * 9 | * 10 | */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_40.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_3_1_40 { 7 | public static long binarySearch(int[] a, int key) { 8 | long start = System.nanoTime(); 9 | int lo = 0, hi = a.length - 1; 10 | while (lo <= hi) { 11 | int mid = (lo + hi) >> 1; 12 | if (a[mid] > key) hi = mid - 1; 13 | else if (a[mid] < key) lo = mid + 1; 14 | else return System.nanoTime() - start; 15 | } 16 | return System.nanoTime() - start; 17 | } 18 | public static long sequentialSearch(int[] a, int key) { 19 | long start = System.nanoTime(); 20 | for (int i = 0; i < a.length; i++) 21 | if (a[i] == key) return System.nanoTime() - start; 22 | return System.nanoTime() - start; 23 | } 24 | public static void main(String[] args) { 25 | // int N = 350000; 快1000倍 26 | int N = 60000000; // 暂时没有找到快 10000 倍的 N,在此之前已经 Java Heap space limit 异常了.. 27 | int[] a = ascendInts(0, N - 1); 28 | int key = N - 1; 29 | double t1 = binarySearch(a, key); 30 | double t2 = sequentialSearch(a, key); 31 | StdOut.println(t2 / t1); 32 | if (t2 / t1 > 1000) { 33 | StdOut.printf("二分查找比顺序查找快 1000 倍的 N = %d t2/t1 = %.3f\n", N, t2 / t1); 34 | } 35 | if (t2 / t1 > 10000) { 36 | StdOut.printf("二分查找比顺序查找快 10000 倍的 N = %d\n", N); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Ch_3_1_Symbol_Tables/Practise_3_1_41.java: -------------------------------------------------------------------------------- 1 | package Ch_3_1_Symbol_Tables; 2 | 3 | import static Tool.ArrayGenerator.*; 4 | import edu.princeton.cs.algs4.*; 5 | 6 | public class Practise_3_1_41 { 7 | public static double interpolation(int[] a, int key) { 8 | long start = System.nanoTime(); 9 | int lo = 0, hi = a.length - 1; 10 | while (lo <= hi) { 11 | double scale = (key - a[lo]) / ((a[hi] - a[lo]) * 1.0); 12 | int mid = lo + (int)(scale * (hi - lo)); 13 | if (mid > hi || mid < lo) break; 14 | if (a[mid] > key) hi = mid - 1; 15 | else if (a[mid] < key) lo = mid + 1; 16 | else { return System.nanoTime() - start; } 17 | } 18 | return System.nanoTime() - start; 19 | } 20 | public static double binary(int[] a, int key) { 21 | long start = System.nanoTime(); 22 | int lo = 0, hi = a.length - 1; 23 | while (lo <= hi) { 24 | int mid = (lo + hi) >> 1; 25 | if (a[mid] > key) hi = mid - 1; 26 | else if (a[mid] < key) lo = mid + 1; 27 | else { return System.nanoTime() - start; } 28 | } 29 | return System.nanoTime() - start; 30 | } 31 | public static void main(String[] args) { 32 | // int N = 3000000; // 会让插值大概率比二分快 1 倍 33 | int N = 60000000; // 会让插值大概率比二分快 2 倍 34 | int[] a = ints(N, 0, N * 2); 35 | int key = StdRandom.uniform(N); 36 | double t1 = interpolation(a, key); 37 | double t2 = binary(a, key); 38 | StdOut.printf("二分/插值 = %.3f\n", t2 / t1); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_01.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * 总比较次数 28 次 7 | * 8 | */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_02.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * 下列插入顺序都能构造处高度为 6 的树 7 | * 8 | * A C E H R S X 9 | * 10 | * X S R H E C A 11 | * 12 | * A E C R H X S 13 | * 14 | * A X S R H E C 15 | * 16 | * X R S E H A C 17 | * 18 | * A C X E H R S 19 | * 20 | * X A C E H R S 21 | * 22 | * 23 | */ 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_03.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_03 { 4 | public static void main(String[] args) { 5 | /* 6 | * A X C S E R H 共有 7 个结点,我们知道一个3层满二叉树的结点总共有 2^3-1 = 7 7 | * 8 | * 所以我们的目标是用这7个结点构造一棵满二叉树 9 | * 10 | * 可以由中序遍历反推,若要构造出一棵中序遍历结果为 A C E H R S X 的满二叉树 11 | * 12 | * 根结点必定是 H,也就是说排列的第一个插入元素必须是 H 13 | * 14 | * 接下来仅次于根结点的两个结点必须是 C 和 S,只有这样,才能让剩下的元素填满 C 和 S 15 | * 的左右孩子,而不会留下空链接 16 | * 17 | * 因此可行的排列有 18 | * 19 | * H C E A S R X 20 | * H C E A S X R 21 | * H C A E S R X 22 | * H C A E S X R 23 | * H S R X C A E 24 | * H S R X C E A 25 | * H S X R C A E 26 | * H S X R C E A 27 | * 28 | * 29 | */ 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_04.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_04 { 4 | public static void main(String[] args) { 5 | /* 6 | * 查找的过程是,从某个结点出发,先用目标键和当前函数栈帧中的参数的结点键比较 7 | * 如果相等,那么返回当前结点,如果目标键小于当前的参数结点键,那么递归调用自身,并把当前参数结点的左孩子 8 | * 传下去,否则就把当前参数结点的右孩子传下去,递归基是如果结点为空,说明没找到 9 | * 10 | * 对于序列 a : 这是一棵按照 10 9 8 7 6 5 ... 顺序插入的树,检查序列是可能的 11 | * 对于序列 b : 当检查到 5 时递归调用就开始在此处逐层返回,因此不可能还检查一下3 12 | * 对于序列 c : 这是一棵按照 1 10 2 9 3 8 4 7 6 5 顺序插入的树,检查序列是可能的 13 | * 对于序列 d : 这个序列是不可能的,在检查7后,转向7的左子树,因此往后检查的所有元素,必定都要小于7,然而序列中出现了8 14 | * 对于序列 e : 这是一棵按照 1 2 10 4 8 5 ... 顺序插入的树,检查序列是可能的 15 | */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_05.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_05 { 4 | public static void main(String[] args) { 5 | /* 6 | * 这道题的意思,我理解是相当于对双主键的序列排序,一个主键是查找频率,一个主键是使二叉树保持结构的键 7 | * 8 | * 二叉查找树之所以能保持高效,是因为每次比较后,所需要查找的规模都比之前减少了一半 9 | * 比如进入了右子树,那其实相当于左子树都不可能,排除了一半的情况,每次比较都如此 10 | * 11 | * 假如我们按照查找频率的顺序插入,很可能使二叉查找树退化成但链表的线性结构 12 | * 13 | * 比如(括号中代表查找频率) 10(10) 9(9) 8(8) 7(7) 6(6) 5(5) 4(4) 14 | * 15 | * 假如按照查找频率插入,我们得到了一棵单链表树,即使可以保证最高查找频率的几个结点能在接近常数 16 | * 时间内被查找到,但是却让最低查找频率的结点在接近线性时间内才能被查找到,感觉这和二叉查找树 17 | * 的精神背道而驰啊...因此我认为构造顺序一定是要以除查找频率外另一个主键为主,尽量构造出一棵 18 | * 树高最小的树 19 | * 20 | * 21 | * 22 | * 23 | */ 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_09.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_09 { 4 | public static void main(String[] args) { 5 | /* 6 | * 以下仅考虑键互不相同的情况 7 | * 8 | * 按照公式 C(2n, n)/(n + 1) 来算 9 | * 10 | * N = 2 两种 11 | * 12 | * N = 3 5种 13 | * 14 | * N = 4 14 种 15 | * 16 | * N = 5 好不容易画出了 42 种... 17 | * 18 | * N = 6 总共 132 种,不画了,画完黄花菜都凉了 19 | */ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_11.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_11 { 4 | public static void main(String[] args) { 5 | /* 6 | * 设 N 个结点可以组成 h(N) 个形状不同的二叉树 7 | * 则 h(N) = C(2N, N) / (N + 1) 8 | * 9 | * N 个键能构成的树最大高度为 N - 1,因此不可能构成高度为 N 的二叉树 10 | * 11 | */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_14.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_14 { 4 | public static void main(String[] args) { 5 | /* 6 | * 请看 Practise_3_2_13.java 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_15.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | import java.util.LinkedList; 4 | public class Practise_3_2_15 { 5 | public static void main(String[] args) { 6 | /* 7 | * floor("Q") 8 | * 9 | * E -> Q 10 | * 11 | * select(5) 12 | * 13 | * E -> Q 14 | * 15 | * ceiling("Q") 16 | * 17 | * E -> Q 18 | * 19 | * rank("J") 20 | * 21 | * E -> Q -> J 22 | * 23 | * size("D", "T") 24 | * 25 | * E -> D 26 | * 27 | * E -> Q -> T 28 | * 29 | * keys("D", "T") 30 | * 31 | * private void keys(Node n, LinkedList list, K lo, K hi) { 32 | if (n == null) return; 33 | int cmplo = lo.compareTo(n.k); 34 | int cmphi = n.k.compareTo(hi); 35 | if (cmplo < 0) keys(n.left, list, lo, hi); 36 | if (cmplo <= 0 && cmphi <= 0) list.add(n.k); 37 | if (cmphi < 0) keys(n.right, list, lo, hi); 38 | } 39 | 40 | E -> D -> E -> Q -> J -> J -> M -> Q -> T -> S -> S -> T 41 | 42 | */ 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_16.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_16 { 4 | public static void main(String[] args) { 5 | /* 6 | * 对 3.2.15 中的图进行计数 7 | * 8 | * 外部路径长度 : 3 + 3 + 2 + 3 + 4 + 4 + 3 + 4 + 4 = 30 9 | * 内部路径长度 : 3 * 2 + 2 * 3 + 2 * 1 + 0 * 1 = 14 10 | * 11 | * 结点总数 : 8 12 | * 13 | * 外部路径长度 = 内部路径长度 + 2 * 结点总数 14 | * 15 | * 16 | * 17 | * 18 | */ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_20.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_20 { 4 | public static void main(String[] args) { 5 | /* 6 | * rank(K lo) 方法只会自根结点向 lo 结点靠拢,访问的结点不会小于 lo 7 | * rank(K hi) 方法只会自根结点向 hi 结点靠拢,访问的结点不会大于 hi 8 | * 9 | * 因为 rank(K lo) 和 rank(K hi) 两次方法调用访问了 lo ~ hi 内的所有结点 10 | * 11 | * 同时在访问过程中,rank() 的递归调用深度最多不过树高,所以 12 | * size(K lo, K hi) 方法所需运行时间最多为树高的倍数加上查找范围内的键的数量 13 | * 14 | * 15 | */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_22.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_22 { 4 | public static void main(String[] args) { 5 | /* 6 | * 这题首先要清楚查找二叉树的线性顺序是由中序遍历得到的 7 | * 8 | * 中序遍历访问结点过程中,若访问顺序是 A B C 9 | * 那么 A 叫做 B 的直接前继,C 叫做 B 的直接后继 10 | * 11 | * 通过中序遍历的访问结点顺序来想,某个 A 结点的直接后继是不会有左子结点的 12 | * 如果有左子结点,那证明该结点还不是 A 的直接后继 13 | * 14 | * 同样,如果某个 A 结点有两个子结点,那么他的直接前继就在以他左子结点为树根的子树中 15 | * 如果该直接前继有右子结点,那证明他还不是 A 的直接前继 16 | * 17 | * 18 | * 19 | */ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_23.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_23 { 4 | public static void main(String[] args) { 5 | /* 6 | * 4 7 | / \ 8 | 3 7 9 | / 10 | 6 11 | 12 | 按照 4 3 顺序删除得到 13 | 14 | 6 15 | \ 16 | 7 17 | 18 | 按照 3 4 顺序删除得到 19 | 7 20 | / 21 | 6 22 | 所以删除操作不满足交换律 23 | */ 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_24.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_24 { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_26.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_26 { 4 | public static void main(String[] args) { 5 | /* 6 | * 用N个不同的随机键总共能构造出C(2N, N) / (N + 1)棵不同形状的二叉树 7 | * 8 | * 因此构造出任意一棵的概率为 (N + 1) / C(2N, N) 9 | * 10 | */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_27.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_27 { 4 | public static void main(String[] args) { 5 | /* 6 | * 对于 SequentialSearchST 每对键值由一个Node结点表示 7 | * 一个引用8字节,因此 N 对不同的键值总共占用 (16 + 8 + 8) * N = 32N 字节 8 | * 9 | * 对于 BinarySearchST 用一个数组表示键,一个数组表示值 10 | * 当涉及到缩容扩容时,数组的大小范围是 N ~ 4N 11 | * 因此总共占用 32 + 16N ~ 32 + 64N 字节 12 | * 13 | * 对于 BinarySearchTree 没对键值由一个Node结点表示 14 | * 每个Node结点为了维护自身的树结构,至少要由两个引用,分表表示左右孩子 15 | * 因此一个 Node 结点至少有 16 + 8 + 8 + 8 + 8 = 48字节 16 | * 因此 N 对不同的键值总共占据 48N 字节 17 | */ 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_37.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_37 { 4 | public static void main(String[] args) { 5 | /* 6 | * 请看Text_BST_Traversal.java 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_2_Binary_Search_Trees/Practise_3_2_38.java: -------------------------------------------------------------------------------- 1 | package Ch_3_2_Binary_Search_Trees; 2 | 3 | public class Practise_3_2_38 { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_01.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_01.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_02.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_02.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_03.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_03 { 4 | public static void main(String[] args) { 5 | /* 6 | * 高度为 1 的 2-3 树可以想象出 7 | * 8 | * 最大可容纳结点个数为 8 个, 形如下列图像 9 | * 10 | * xx 11 | * xx xx xx 12 | * 13 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_03.png 14 | * 从上述构造出的高度为 1 的 2-3 树可以得到 15 | * 插入序列可以是 E S A H X C M (这里仅列举一种可能的) 16 | */ 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_04.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_04 { 4 | public static void main(String[] args) { 5 | /* 6 | * 2-3树是一种向上生长的树 7 | * 8 | * 3-结点会首先出现在叶子结点,然后向树根方向分裂传递,如果树根由3-结点分裂,那么树高加1 9 | * 如果叶子结点的 2- 结点没有转化为 3- 结点并向上传递分裂过程,那么树高永远不会增加 10 | * 11 | * 我们可以得到,假如这 N 个结点恰好满足构造出一棵只有 2- 结点的树,那么此时树高为最大 12 | * 13 | * 即 floor( logN/log2 ) 14 | * 15 | * 如果这 N 个结点恰好满足构造出一棵只有 3- 结点的树,那么此时树高为最小 16 | * 17 | * 即 floor( logN/log3 ) 18 | * 19 | */ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_05.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_05 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_05.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_07.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_07 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_07.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_08.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_08 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_08.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_09.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_09 { 4 | public static void main(String[] args) { 5 | /* 6 | * 1 不是红黑树,把红色摊平将其视作2-3树就可以看出 7 | * 2 不满足中序遍历次序按照升序排列 8 | * 3, 4 都是红黑树 9 | */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_10.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_10 { 4 | public static void main(String[] args) { 5 | /* 6 | * E A S Y Q U T I O N 7 | * 8 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_10.png 9 | */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_11.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_11 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_11.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_12.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_12 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_12.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_13.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_13 { 4 | public static void main(String[] args) { 5 | /* 6 | * 真 7 | * 8 | * 每插入一个结点,树高要么保持不变,要么在叶子形成 3- 结点,首先分裂,然后将 2- 结点向上传递 9 | * 当 2- 结点传递到根结点并形成 3- 结点时,树高加1 10 | * 因此 每插入一个结点,树高要么不变,要么加 1 11 | * 12 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_13.png 13 | */ 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_14.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_14 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_14.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_15.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_15 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_15.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_16.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_16 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_16.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_17.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_17 { 4 | public static void main(String[] args) { 5 | /* 6 | * 结点较少时形成的二叉查找树高度不一定大于红黑树,但内部路径长度一定小于红黑树 7 | * 这代表随机命中查找所需的平均比较次数一定大于红黑树 8 | * 9 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_17.png 10 | */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_18.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | public class Practise_3_3_18 { 4 | public static void main(String[] args) { 5 | /* 6 | * https://github.com/YangXiaoHei/Algorithms_4/blob/master/FlowChart/Ch_3_3_Practise_3_3_18.png 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/Practise_3_3_20.java: -------------------------------------------------------------------------------- 1 | package Ch_3_3_Balanced_Search_Trees; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class Practise_3_3_20 { 6 | public static int ipl(int N) { 7 | int h = (int)(Math.log(N + 1) / Math.log(2)); 8 | int sum = 0; 9 | for (int i = 0; i < h; i++) 10 | sum += i * (1 << i); 11 | return sum; 12 | } 13 | public static void main(String[] args) { 14 | int N = 63; 15 | StdOut.printf("大小为 : %d 内部路径长度 : %d\n",N, ipl(N)); 16 | } 17 | // output 18 | /* 19 | * 大小为 : 63 内部路径长度 : 258 20 | 21 | */ 22 | } 23 | -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/doc/Construct_Red_Black_Tree.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/doc/Construct_Red_Black_Tree.pdf -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_AVL树delete()操作.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_AVL树delete()操作.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_AVL树deleteMin()过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_AVL树deleteMin()过程.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_01.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_02.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_03.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_05.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_07.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_08.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_10.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_11.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_12.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_13.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_14.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_15.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_16.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_17.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_18.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_22.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_Practise_3_3_23.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_RBTree_Put().png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_RBTree_Put().png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_RBTree_delete().png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_RBTree_delete().png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_RBTree_deleteMin()_deleteMax().png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_RBTree_deleteMin()_deleteMax().png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_二叉树迭代版中序遍历.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_二叉树迭代版中序遍历.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_二叉树迭代版先序遍历.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_二叉树迭代版先序遍历.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_从2-3树理解红黑树delete()操作.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_从2-3树理解红黑树delete()操作.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_在2-3树上理解红黑树deleteMin()操作.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_在2-3树上理解红黑树deleteMin()操作.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_在2-3树基础上理解deleteMax()操作.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_在2-3树基础上理解deleteMax()操作.png -------------------------------------------------------------------------------- /Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_用26个键构造AVL树的过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_3_3_Balanced_Search_Trees/image/Ch_3_3_用26个键构造AVL树的过程.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/C/AdjacencyListGraph/AdjacencyListGraph.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _GRAPH_H_ 3 | #define _GRAPH_H_ 4 | 5 | struct adj_vertex_t { 6 | struct adj_vertex_t *next; 7 | int v; 8 | }; 9 | 10 | struct adj { 11 | int size; 12 | struct adj_vertex_t *head; 13 | }; 14 | 15 | struct G { 16 | struct adj *adjs; 17 | int vertex_count; 18 | int edge_count; 19 | char *marked; /* 压缩过的域,1 bit 表示一个顶点 */ 20 | }; 21 | 22 | typedef void(*iterator)(int v); 23 | 24 | struct G* createGraph(int vertex_count); 25 | 26 | int hasEdge(struct G *graph, int v, int w); 27 | 28 | struct G* dupGraph(struct G *graph); 29 | 30 | struct G* createGraphWithFile(const char *file_name); 31 | 32 | int destroyGraph(struct G **graph); 33 | 34 | void adj(struct G *graph, int v, iterator it); 35 | 36 | const char *path(struct G *graph, int from, int to); 37 | 38 | void mark(struct G *graph, int v); 39 | 40 | void unmark(struct G *graph, int v); 41 | 42 | void clearAllMarked(struct G *graph); 43 | 44 | int marked(struct G *graph, int v); 45 | 46 | int addEdge(struct G *graph, int v, int w); 47 | 48 | int getEdgeCount(struct G *graph); 49 | 50 | int getVertexCount(struct G *graph); 51 | 52 | void DFS(struct G *grahp, int v, iterator it); 53 | 54 | const char *toString(struct G *graph); 55 | 56 | #endif 57 | 58 | 59 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/C/AdjacencyListGraph/complie.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | cc AdjacencyListGraph_test.c AdjacencyListGraph.c -o test 4 | if [ $? -eq 0 ] 5 | then 6 | ./test 7 | fi 8 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/C/AdjacencyListGraph/graph_file: -------------------------------------------------------------------------------- 1 | 13 2 | 0: 1 2 6 5 3 | 1: 0 4 | 2: 0 5 | 3: 5 4 6 | 4: 3 5 6 7 | 5: 0 3 4 8 | 6: 0 4 9 | 7: 8 10 | 8: 7 11 | 9: 10 11 12 12 | 10: 9 13 | 11: 9 12 14 | 12: 9 11 15 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/C/AdjacencyListGraph/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/C/AdjacencyListGraph/test -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/C/AdjacencyListGraph/tmp: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0 2 3 | 0 6 4 | 0 5 5 | 3 5 6 | 3 4 7 | 5 4 8 | 6 4 9 | 7 8 10 | 9 10 11 | 9 11 12 | 9 12 13 | 11 12 14 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/C/AdjacencyMatrixGraph/complie.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | cc AdjacencyMatrixGraph.c -o test 4 | if [ $? -eq 0 ] 5 | then 6 | ./test 7 | fi 8 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/C/AdjacencyMatrixGraph/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/C/AdjacencyMatrixGraph/test -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/EG.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | import edu.princeton.cs.algs4.*; 3 | 4 | public class EG { 5 | int V; 6 | public EG(int V) { 7 | this.V = V; 8 | } 9 | public Pair next() { 10 | return new Pair(StdRandom.uniform(0, V), 11 | StdRandom.uniform(0, V)); 12 | } 13 | public static void main(String[] args) { 14 | EG gen = new EG(13); 15 | for (int i = 0; i < 10; i++) 16 | StdOut.println(gen.next()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Pair.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Pair { 4 | int v, w; 5 | public Pair(int v, int w) { 6 | this.v = v; 7 | this.w = w; 8 | } 9 | public String toString() { 10 | return String.format("%d %d", v, w); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_01.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * V(V-1)/2 7 | * 8 | * V-1 9 | * 10 | * 见 README.md 11 | */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_02.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * 见 README.md 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_03.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_03 { 4 | public static void main(String[] args) { 5 | /* 6 | * C 实现... 见 C 文件夹 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_04.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_04 { 4 | public static void main(String[] args) { 5 | /* 6 | * 很简单,提一点小优化 7 | * 8 | * 在 Bag 中提供一个查询元素数量的接口 int size(); 9 | * 10 | * 对于查询 hasEdge(v, w),我们比较 bag[v].size() 和 bag[w].size() 谁 11 | * 比较小,选择小的那个遍历它的所有邻接点,这样可以少遍历一些点 12 | */ 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_05.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_05 { 4 | public static void main(String[] args) { 5 | /* 6 | * 很简单 7 | * 8 | * 禁止平行边存在,这意味着将禁止在背包内添加重复元素 9 | * 10 | * 禁止自环存在,只需要忽略 addEdge(1, 1) 形式的输入即可 11 | */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_07.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_07 { 4 | public static void main(String[] args) { 5 | /* 6 | * C 实现... 见 C 文件夹 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_09.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_09 { 4 | public static void main(String[] args) { 5 | /* 6 | * 见 README.md 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_11.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_11 { 4 | public static void main(String[] args) { 5 | /* 6 | * 见 README.md 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_15.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_15 { 4 | public static void main(String[] args) { 5 | /* 6 | * Java 太简单了,用 c 实现给我自己找点乐子... 请见 C 文件夹 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_18.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_18 { 4 | public static void main(String[] args) { 5 | /* 6 | * 看 README.md 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_22.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_22 { 4 | public static void main(String[] args) { 5 | /* 6 | * 和 4.1.21 一并写在一起了,见上题 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_24.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_24 { 4 | public static void main(String[] args) { 5 | /* 6 | * 写在 4.1.21 中了 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/Practise_4_1_25.java: -------------------------------------------------------------------------------- 1 | package Ch_4_1_Undirected_Graphs; 2 | 3 | public class Practise_4_1_25 { 4 | public static void main(String[] args) { 5 | /* 6 | * 只是单纯把 BFS 换成 DFS 而已.... 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_01.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_01.1.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_01.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_01.2.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_02.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_09.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_11.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_14.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_14.1.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_14.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_14.2.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_18.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_19.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/images/Practise_4_1_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_1_Undirected_Graphs/images/Practise_4_1_20.png -------------------------------------------------------------------------------- /Ch_4_1_Undirected_Graphs/slink_README.md: -------------------------------------------------------------------------------- 1 | /Users/bot/Desktop/Algorithms4/Algorithms4/src/README.md -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/EG.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | import edu.princeton.cs.algs4.*; 3 | 4 | public class EG { 5 | int V; 6 | public EG(int V) { 7 | this.V = V; 8 | } 9 | public Pair next() { 10 | return new Pair(StdRandom.uniform(0, V), 11 | StdRandom.uniform(0, V)); 12 | } 13 | public static void main(String[] args) { 14 | EG gen = new EG(13); 15 | for (int i = 0; i < 10; i++) 16 | StdOut.println(gen.next()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Pair.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Pair { 4 | int v, w; 5 | public Pair(int v, int w) { 6 | this.v = v; 7 | this.w = w; 8 | } 9 | public String toString() { 10 | return String.format("%d %d", v, w); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_01.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * V(V-1) 条边 7 | * 8 | * V-1 条边 9 | */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_02.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * 0 : 5 6 7 | * 1 : 8 | * 2 : 3 0 9 | * 3 : 6 10 10 | * 4 : 1 11 | * 5 : 2 10 12 | * 6 : 2 13 | * 7 : 11 8 14 | * 8 : 4 1 15 | * 9 : 16 | * 10 : 3 17 | * 11 : 8 18 | * 19 | * 20 | * 21 | * 22 | */ 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_04.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_04 { 4 | public static void main(String[] args) { 5 | /* 6 | * 见先前的题,都写过了 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_05.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_05 { 4 | public static void main(String[] args) { 5 | /* 6 | * 见先前的题,都写过了 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_06.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_06 { 4 | public static void main(String[] args) { 5 | /* 6 | * 那就测呗... 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_12.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_12 { 4 | public static void main(String[] args) { 5 | /* 6 | * V^2 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_14.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_14 { 4 | public static void main(String[] args) { 5 | /* 6 | * 对于 G 中的任意强连通分量 A 7 | * 8 | * 若 A 中只有一个顶点,显然,在 GR 中 A 也是一个强连通分量 9 | * 若 A 中顶点个数 >= 2,那么任取两个点 s,v,则由强连通分量定义可知, 10 | * 在 A 中存在 s -> v,也存在 v -> s 11 | * 12 | * 则在 GR 中必然存在 v -> s, 也存在 s -> v,因此强连通分量 A 中的所有顶点在 GR 中 13 | * 仍然构成一个强连通分量 14 | * 15 | * 对于 G 中的任意两个强连通分量 A, B 16 | * 在 A 中选出一个顶点 a, 在 B 中选出一个顶点 b 17 | * 由定义可知,a -> b 可能存在,也可能不存在,b -> a 亦然, 18 | * 但绝不可能同时存在 a -> b 和 b -> a 19 | * 20 | * 因此在 GR 中 b -> a 可能存在,a -> b 可能存在,但两者绝不可能同时存在, 21 | * 因此 A, B 仍然是两个独立的连通分量 22 | * 23 | */ 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_15.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_15 { 4 | public static void main(String[] args) { 5 | /* 6 | * 每个顶点都是一个强连通分量 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/Practise_4_2_16.java: -------------------------------------------------------------------------------- 1 | package Ch_4_2_Directed_Graphs; 2 | 3 | public class Practise_4_2_16 { 4 | public static void main(String[] args) { 5 | /* 6 | * 找出了强连通分量的个数, 7 | * 并且标示出了所有顶点属于哪个强连通分量 8 | */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/image/DirectedCycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_2_Directed_Graphs/image/DirectedCycle.png -------------------------------------------------------------------------------- /Ch_4_2_Directed_Graphs/image/Practise_4_3_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Ch_4_2_Directed_Graphs/image/Practise_4_3_06.png -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/EG.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | import edu.princeton.cs.algs4.*; 3 | 4 | public class EG { 5 | int V; 6 | public EG(int V) { 7 | this.V = V; 8 | } 9 | public Pair next() { 10 | return new Pair(StdRandom.uniform(0, V), 11 | StdRandom.uniform(0, V)); 12 | } 13 | public static void main(String[] args) { 14 | EG gen = new EG(13); 15 | for (int i = 0; i < 10; i++) 16 | StdOut.println(gen.next()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Edge.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Edge implements Comparable { 4 | private final int v; 5 | private final int w; 6 | private final double weight; 7 | public Edge(int v, int w, double weight) { 8 | this.v = v; 9 | this.w = w; 10 | this.weight = weight; 11 | } 12 | public double weight() { return weight; } 13 | public int either() { return v; } 14 | public int other(int ver) { 15 | if (ver == w) 16 | return v; 17 | if (ver == v) 18 | return w; 19 | throw new RuntimeException("should not reach here!"); 20 | } 21 | public int compareTo(Edge that) { 22 | return weight < that.weight ? -1 : weight > that.weight ? 1 : 0; 23 | } 24 | public String toString() { 25 | return String.format("{%d-%d %.2f}", v, w, weight); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Pair.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Pair { 4 | int v, w; 5 | public Pair(int v, int w) { 6 | this.v = v; 7 | this.w = w; 8 | } 9 | public String toString() { 10 | return String.format("%d %d", v, w); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Practise_4_3_01.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Practise_4_3_01 { 4 | public static void main(String[] args) { 5 | /* 6 | * 对权重乘以一个正常数不会改变所有边权重的大小关系 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Practise_4_3_02.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Practise_4_3_02 { 4 | public static void main(String[] args) { 5 | /* 6 | * 见 README.md 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Practise_4_3_03.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Practise_4_3_03 { 4 | public static void main(String[] args) { 5 | /* 6 | * 假设最小生成树不唯一,那么假设在 G 中有两个不同的最小生成树 T1 和 T2,再假设 G 中 7 | * 有一条最小权重的边 f,该边 f 在 T1 而不在 T2 中,把 f 添加到 T2 中,此时便形成了一个 8 | * 闭环,因为在这个闭环中 f 比所有边权重都要小,那么此时删掉其他一条边而保留 f,便形成 9 | * 了一个新的最小生成树 T3,此时 T3 == T1 10 | */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Practise_4_3_04.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Practise_4_3_04 { 4 | public static void main(String[] args) { 5 | /* 6 | * 如果加权无向图中有相同权重的边,那么假设相同权重的边在整个图中 7 | * 具有最小权重,根据 切分定理,权重最小的边必然属于最小生成树, 8 | * 那么从不同顶点出发的 Prim 算法必然会得出不同的生成树。 9 | */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Practise_4_3_05.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Practise_4_3_05 { 4 | public static void main(String[] args) { 5 | /* 6 | * 如果权重相同的边是属于同种切分,那么看如果权重相同的边不是最小,则切分定理不会选择他们 7 | * 如果是最小,那么切分定理在二者中择一,如果权重相同的边不属于同种切分,那么切分定理会选择 8 | * 他们所属切分中所有切分权重最小的边,只要黑色边的数量小于 V-1,必然还存在不会产生黑色横切边 9 | * 的切分 10 | */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Practise_4_3_06.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Practise_4_3_06 { 4 | public static void main(String[] args) { 5 | /* 6 | * 见 README.md 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Practise_4_3_07.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Practise_4_3_07 { 4 | public static void main(String[] args) { 5 | /* 6 | * 将最小堆改为最大堆即可 7 | */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/Practise_4_3_08.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | public class Practise_4_3_08 { 4 | public static void main(String[] args) { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Ch_4_3_Minimum_Spanning_Trees/WeightedQuickUnion.java: -------------------------------------------------------------------------------- 1 | package Ch_4_3_Minimum_Spanning_Trees; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class WeightedQuickUnion { 6 | private int[] ids; 7 | private int[] sz; 8 | public WeightedQuickUnion(int n) { 9 | ids = new int[n]; 10 | sz = new int[n]; 11 | for (int i = 0; i < n; i++) { 12 | ids[i] = i; 13 | sz[i] = 1; 14 | } 15 | } 16 | public int find(int v) { 17 | while (ids[v] != v) 18 | v = ids[v]; 19 | return v; 20 | } 21 | public boolean connected(int v, int w) { 22 | return find(v) == find(w); 23 | } 24 | public void union(int v, int w) { 25 | int pRoot = find(v); 26 | int qRoot = find(w); 27 | if (pRoot == qRoot) return; 28 | if (sz[pRoot] < sz[qRoot]) { 29 | /* p 是小树,将其接到大树 */ 30 | ids[pRoot] = qRoot; 31 | sz[qRoot] += sz[pRoot]; 32 | } else { 33 | /* q 是小树,将其接到大树 */ 34 | ids[qRoot] = pRoot; 35 | sz[pRoot] += sz[qRoot]; 36 | } 37 | } 38 | public static void main(String[] args) { 39 | WeightedQuickUnion uf = new WeightedQuickUnion(10); 40 | EG eg = new EG(10); 41 | int k = 10; 42 | while (k-- > 0) { 43 | Pair p = eg.next(); 44 | if (uf.connected(p.v, p.w)) 45 | StdOut.printf("{%d %d} connected!\n", p.v, p.w); 46 | else 47 | uf.union(p.v, p.w); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Ch_4_4_Shortest_Paths/CPM.java: -------------------------------------------------------------------------------- 1 | package Ch_4_4_Shortest_Paths; 2 | 3 | import edu.princeton.cs.algs4.StdIn; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class CPM { 7 | public static void main(String[] args) { 8 | int N = StdIn.readInt(); StdIn.readLine(); 9 | /* 每个顶点需要有起始和结束,再加一个开始和结束 10 | * 所以是 2N+2 */ 11 | EdgeWeightedDigraph g = new EdgeWeightedDigraph(2 * N + 2); 12 | int s = 2 * N + 1, t = 2 * N + 2; 13 | for (int i = 0; i < N; i++) { 14 | String[] a = StdIn.readLine().split("\\s+"); 15 | double duration = Double.parseDouble(a[0]); 16 | g.addEdge(new DirectedEdge(i, i + N, duration)); 17 | g.addEdge(new DirectedEdge(s, i, 0.0)); 18 | g.addEdge(new DirectedEdge(i + N, t, 0.0)); 19 | for (int j = 1; j < a.length; j++) { 20 | int succ = Integer.parseInt(a[j]); 21 | g.addEdge(new DirectedEdge(i + N, succ, 0.0)); 22 | } 23 | } 24 | AcyclicLP lp = new AcyclicLP(g, s); 25 | StdOut.println("Start times: "); 26 | for (int i = 0; i < N; i++) 27 | StdOut.printf("%4d: %5.1f\n", i, lp.disTo(i)); 28 | StdOut.printf("Finish time: %5.1f\n", lp.disTo(t)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Ch_4_4_Shortest_Paths/DirectedEdge.java: -------------------------------------------------------------------------------- 1 | package Ch_4_4_Shortest_Paths; 2 | 3 | public class DirectedEdge { 4 | private final int from; 5 | private final int to; 6 | private final double weight; 7 | public DirectedEdge(int from, int to, double weight) { 8 | this.from = from; 9 | this.to = to; 10 | this.weight = weight; 11 | } 12 | public double weight() { return weight; } 13 | public int from() { return from; } 14 | public int to() { return to; } 15 | public String toString() { 16 | return String.format("{%d->%d %.2f}", from, to, weight); 17 | } 18 | public boolean equals(Object that) { 19 | DirectedEdge t = (DirectedEdge)that; 20 | return t.to == to && t.from == from; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Ch_4_4_Shortest_Paths/EG.java: -------------------------------------------------------------------------------- 1 | package Ch_4_4_Shortest_Paths; 2 | import edu.princeton.cs.algs4.*; 3 | 4 | public class EG { 5 | int V; 6 | public EG(int V) { 7 | this.V = V; 8 | } 9 | public Pair next() { 10 | return new Pair(StdRandom.uniform(0, V), 11 | StdRandom.uniform(0, V)); 12 | } 13 | public DirectedEdge nextW() { 14 | return new DirectedEdge(StdRandom.uniform(0, V), 15 | StdRandom.uniform(0, V), 16 | StdRandom.uniform(1, 20) * 1.0); 17 | } 18 | public static void main(String[] args) { 19 | EG gen = new EG(13); 20 | for (int i = 0; i < 10; i++) 21 | StdOut.println(gen.next()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Ch_4_4_Shortest_Paths/Pair.java: -------------------------------------------------------------------------------- 1 | package Ch_4_4_Shortest_Paths; 2 | 3 | public class Pair { 4 | int v, w; 5 | public Pair(int v, int w) { 6 | this.v = v; 7 | this.w = w; 8 | } 9 | public String toString() { 10 | return String.format("%d %d", v, w); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ch_4_4_Shortest_Paths/TopologicSort.java: -------------------------------------------------------------------------------- 1 | package Ch_4_4_Shortest_Paths; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class TopologicSort { 6 | private __Stack reversePost; 7 | private boolean marked[]; 8 | private EdgeWeightedDigraph g; 9 | public TopologicSort(EdgeWeightedDigraph g, int v) { 10 | reversePost = new __Stack<>(); 11 | marked = new boolean[g.V()]; 12 | this.g = g; 13 | 14 | EdgeWeightedDigraphCycle finder = new EdgeWeightedDigraphCycle(g); 15 | if (finder.hasCycle()) { 16 | StringBuilder sb = new StringBuilder(); 17 | for (DirectedEdge e : finder.cycle()) 18 | sb.append(e + " "); 19 | throw new RuntimeException("toposort not exist in cyclic graph! \n" + sb.toString()); 20 | } 21 | 22 | dfs(v); 23 | } 24 | private void dfs(int v) { 25 | marked[v] = true; 26 | for (DirectedEdge e : g.adj(v)) 27 | if (!marked[e.to()]) 28 | dfs(e.to()); 29 | reversePost.push(v); 30 | } 31 | public Iterable sortOrder() { 32 | return reversePost; 33 | } 34 | public static void main(String[] args) { 35 | EdgeWeightedDigraph g = new EdgeWeightedDigraph(10); 36 | g.genRandom(10); 37 | StdOut.println(g); 38 | 39 | TopologicSort sort = new TopologicSort(g, 0); 40 | for (int w : sort.sortOrder()) 41 | StdOut.print(w + " "); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithms4 2 | 3 | 🔥 **算法4** 练习题的 `Java` 实现,持续更新中... 4 | 5 | 🔥 **算法4** 提供的内置库下载 [algs4.jar](https://algs4.cs.princeton.edu/code/algs4.jar) 6 | 7 | 🔥 **算法4** 测试数据下载 [algs4-data.zip](https://algs4.cs.princeton.edu/code/algs4-data.zip) 8 | 9 | 交流本书内容或者习题,请加微信 `bigrice7385` 10 | 11 | > 下面列出的链接的解答仅用于需要用图像或文档描述的习题, 12 | > 其他解答统一整合在各章节各小节目录下 13 | 14 | * **4.1 无向图** 15 | * [`4.1.1 a`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_01.1.png) | [`4.1.1 b`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_01.2.png) 16 | * [`4.1.2`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_02.png) 17 | * [`4.1.9`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_09.png) 18 | * [`4.1.11`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_11.png) 19 | * [`4.1.14.a`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_14.1.png) | [`4.1.14.b`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_14.2.png) 对比两图可以发现,用栈来实现的广搜无法达到预期目的,因为栈总是 “贪心”,在还没有处理完本轮加入的所有邻居前就又向自己内部加入新节点。由于栈先进后出的性质,加入新节点后,只能从离起点更远的地方再向前迈向征程,整个过程好比喝醉酒兜圈子,但毕竟地球是圆的,尽管摇摇晃晃,南辕北辙,但最终又能回到起点。 20 | * [`4.1.18`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_18.png) 21 | * [`4.1.19`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_19.png) 22 | * [`4.1.20`](https://github.com/YangXiaoHei/Algorithms/blob/master/Ch_4_1_Undirected_Graphs/images/Practise_4_1_20.png) -------------------------------------------------------------------------------- /Review/Graph/BellmanFordSP_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/BellmanFordSP_example_1.png -------------------------------------------------------------------------------- /Review/Graph/BellmanFordSP_example_2_negative_cycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/BellmanFordSP_example_2_negative_cycle.png -------------------------------------------------------------------------------- /Review/Graph/BellmanFordSP_test_data_negative_cycle.txt: -------------------------------------------------------------------------------- 1 | 10 2 | 20 3 | 0 1 -0.34 4 | 1 1 0.95 5 | 1 4 0.65 6 | 3 7 0.26 7 | 3 4 0.09 8 | 4 3 0.01 9 | 4 6 0.23 10 | 5 7 0.12 11 | 5 6 -0.15 12 | 6 5 0.58 13 | 6 1 -0.45 14 | 7 2 0.78 15 | 7 4 -0.28 16 | 7 8 0.08 17 | 8 9 0.32 18 | 8 9 0.24 19 | 8 6 -0.09 20 | 8 9 -0.07 21 | 9 7 0.78 22 | 9 9 0.59 23 | -------------------------------------------------------------------------------- /Review/Graph/BreadthFirstSearch.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.In; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class BreadthFirstSearch { 7 | private boolean marked[]; 8 | private Graph g; 9 | private int count; 10 | public BreadthFirstSearch(Graph g, int s) { 11 | this.g = g; 12 | marked = new boolean[g.V()]; 13 | bfs(s); 14 | } 15 | private void bfs(int v) { 16 | _Queue q = new _Queue<>(); 17 | marked[v] = true; 18 | q.enqueue(v); 19 | count++; 20 | while (!q.isEmpty()) { 21 | v = q.dequeue(); 22 | for (int w : g.adj(v)) { 23 | if (!marked[w]) { 24 | count++; 25 | marked[w] = true; 26 | q.enqueue(w); 27 | } 28 | } 29 | } 30 | } 31 | public boolean isConnectedGraph() { 32 | return count == g.V(); 33 | } 34 | public boolean areConnected(int v, int w) { 35 | return marked[v] && marked[w]; 36 | } 37 | public static void main(String[] args) { 38 | Graph g = new Graph(new In("/Users/bot/Desktop/algs4-data/tinyCG.txt")); 39 | BreadthFirstSearch dfs = new BreadthFirstSearch(g, 0); 40 | if (dfs.isConnectedGraph()) 41 | StdOut.println("连通图"); 42 | if (dfs.areConnected(0, 3)) 43 | StdOut.println("0 3 connected!"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Review/Graph/CC.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.In; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class CC { 7 | private Graph g; 8 | private int count; 9 | private int size[]; 10 | private int id[]; 11 | private boolean marked[]; 12 | public CC(Graph g) { 13 | count = 1; 14 | size = new int[g.V()]; 15 | id = new int[g.V()]; 16 | marked = new boolean[g.V()]; 17 | this.g = g; 18 | for (int i = 0; i < g.V(); i++) { 19 | if (!marked[i]) { 20 | dfs(i); 21 | count++; 22 | } 23 | } 24 | } 25 | private void dfs(int v) { 26 | marked[v] = true; 27 | id[v] = count; 28 | size[count]++; 29 | for (int w : g.adj(v)) 30 | if (!marked[w]) 31 | dfs(w); 32 | } 33 | public int size(int v) { return size[id[v]]; } 34 | public int id(int v) { return id[v]; } 35 | public int count() { return count; } 36 | public boolean areConnected(int v, int w) { return id[v] == id[w]; } 37 | public boolean isConnectedGraph() { 38 | int sum = 0; 39 | for (int i = 0; i < size.length; i++) 40 | sum += size[i]; 41 | return sum == g.V(); 42 | } 43 | public static void main(String[] args) { 44 | Graph g = new Graph(new In("/Users/bot/Desktop/algs4-data/tinyCG.txt")); 45 | CC cc = new CC(g); 46 | for (int i = 0; i < g.V(); i++) 47 | StdOut.println(cc.id(i)); 48 | if (cc.isConnectedGraph()) 49 | StdOut.println("连通图"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Review/Graph/DegreesOfSeparation.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class DegreesOfSeparation { 6 | public static void main(String[] args) { 7 | SymbolGraph sg = new SymbolGraph("/Users/bot/Desktop/algs4-data/movies.txt", "/"); 8 | Graph g = sg.graph(); 9 | BreadthFirstPath bfs = new BreadthFirstPath(g, sg.indexOf("Bacon, Kevin")); 10 | 11 | String name = "Boutsikaris, Dennis"; 12 | if (!sg.contains(name)) { 13 | StdOut.println("not in database"); 14 | return; 15 | } 16 | 17 | int to = sg.indexOf(name); 18 | StdOut.println(name); 19 | if (bfs.hasPathTo(to)) { 20 | for (int w : bfs.pathTo(to)) { 21 | StdOut.println(" " + sg.name(w)); 22 | } 23 | } else { 24 | StdOut.println("not connected!"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Review/Graph/DepthFirstOrder.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class DepthFirstOrder { 6 | private _Queue pre; 7 | private _Queue post; 8 | private _Stack postReverse; 9 | private Digraph g; 10 | private boolean marked[]; 11 | public DepthFirstOrder(Digraph g) { 12 | this.g = g; 13 | pre = new _Queue<>(); 14 | post = new _Queue<>(); 15 | postReverse = new _Stack<>(); 16 | marked = new boolean[g.V()]; 17 | for (int i = 0; i < g.V(); i++) 18 | if (!marked[i]) 19 | dfs(i); 20 | } 21 | private void dfs(int v) { 22 | marked[v] = true; 23 | pre.enqueue(v); 24 | for (int w : g.adj(v)) 25 | if (!marked[w]) 26 | dfs(w); 27 | post.enqueue(v); 28 | postReverse.push(v); 29 | } 30 | public Iterable postOrder() { return post; } 31 | public Iterable preOrder() { return pre; } 32 | public Iterable postReverseOrder() { return postReverse; } 33 | public static void main(String[] args) { 34 | Digraph g = DigraphGenerator.simple(10, 10); 35 | StdOut.println(g); 36 | DepthFirstOrder dfo = new DepthFirstOrder(g); 37 | StdOut.print("前序: "); 38 | for (int w : dfo.preOrder()) 39 | StdOut.print(w + " "); 40 | StdOut.println(); 41 | 42 | StdOut.print("后序: "); 43 | for (int w : dfo.postOrder()) 44 | StdOut.print(w + " "); 45 | StdOut.println(); 46 | 47 | StdOut.print("逆后序: "); 48 | for (int w : dfo.postReverseOrder()) 49 | StdOut.print(w + " "); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Review/Graph/DepthFirstPath.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.In; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class DepthFirstPath { 7 | private boolean marked[]; 8 | private Graph g; 9 | private int[] edgeTo; 10 | private int source; 11 | public DepthFirstPath(Graph g, int s) { 12 | this.g = g; 13 | source = s; 14 | edgeTo = new int[g.V()]; 15 | marked = new boolean[g.V()]; 16 | dfs(s); 17 | } 18 | private void dfs(int v) { 19 | marked[v] = true; 20 | for (int w : g.adj(v)) { 21 | if (!marked[w]) { 22 | edgeTo[w] = v; 23 | dfs(w); 24 | } 25 | } 26 | } 27 | public boolean hasPathTo(int v) { return marked[v]; } 28 | public Iterable pathTo(int v) { 29 | _Stack S = new _Stack<>(); 30 | for (int i = v; i != source; i = edgeTo[i]) 31 | S.push(i); 32 | S.push(source); 33 | return S; 34 | } 35 | public void printPath(int v) { 36 | if (!hasPathTo(v)) 37 | throw new IllegalArgumentException("no path to " + v); 38 | for (int w : pathTo(v)) 39 | if (w == source) 40 | StdOut.printf("%d", w); 41 | else 42 | StdOut.printf(" -> %d", w); 43 | StdOut.println(); 44 | } 45 | public static void main(String[] args) { 46 | Graph g = new Graph(new In("/Users/bot/Desktop/algs4-data/tinyCG.txt")); 47 | DepthFirstPath dfs = new DepthFirstPath(g, 0); 48 | for (int i = 0; i < g.V(); i++) 49 | if (dfs.hasPathTo(i)) 50 | dfs.printPath(i); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Review/Graph/DepthFirstSearch.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | import edu.princeton.cs.algs4.In; 5 | 6 | public class DepthFirstSearch { 7 | private int count; 8 | private boolean marked[]; 9 | private Graph g; 10 | public DepthFirstSearch(Graph g, int s) { 11 | this.g = g; 12 | checkVertex(s); 13 | marked = new boolean[g.V()]; 14 | dfs(s); 15 | } 16 | public boolean marked(int v) { checkVertex(v); return marked[v]; } 17 | public boolean isConnectedGraph() { return count == g.V(); } 18 | public boolean areConnected(int v, int w) { 19 | checkVertex(v); 20 | checkVertex(w); 21 | return marked[v] && marked[w]; 22 | } 23 | private void dfs(int v) { 24 | marked[v] = true; 25 | count++; 26 | for (int w : g.adj(v)) 27 | if (!marked[w]) 28 | dfs(w); 29 | } 30 | private void checkVertex(int v) { 31 | if (v < 0 || v >= g.V()) 32 | throw new IllegalArgumentException(); 33 | } 34 | 35 | public static void main(String[] args) { 36 | Graph g = new Graph(new In("/Users/bot/Desktop/algs4-data/tinyCG.txt")); 37 | DepthFirstSearch dfs = new DepthFirstSearch(g, 0); 38 | if (dfs.isConnectedGraph()) 39 | StdOut.println("连通图"); 40 | if (dfs.areConnected(0, 3)) 41 | StdOut.println("0 3 connected!"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Review/Graph/DijkstraAllPairSP.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class DijkstraAllPairSP { 6 | private DijkstraSP sp[]; 7 | public DijkstraAllPairSP(EdgeWeightedDigraph g) { 8 | sp = new DijkstraSP[g.V()]; 9 | for (int i = 0; i < g.V(); i++) 10 | sp[i] = new DijkstraSP(g, i); 11 | } 12 | public boolean hasPath(int v, int w) { return sp[v].hasPathTo(w); } 13 | public Iterable pathBetween(int v, int w) { 14 | if (!sp[v].hasPathTo(w)) 15 | throw new RuntimeException("no path!"); 16 | return sp[v].pathTo(w); 17 | } 18 | public double dis(int v, int w) { return sp[v].disTo(w); } 19 | public static void main(String[] args) { 20 | EdgeWeightedDigraph g = new EdgeWeightedDigraph(10, 30); 21 | StdOut.println(g); 22 | 23 | DijkstraAllPairSP dj = new DijkstraAllPairSP(g); 24 | for (int i = 0; i < g.V(); i++) 25 | for (int j = 0; j < g.V(); j++) { 26 | if (dj.hasPath(i, j)) { 27 | StdOut.printf("%d to %d [%.2f]: ", i, j, dj.dis(i, j)); 28 | for (DirectedEdge e : dj.pathBetween(i, j)) 29 | StdOut.printf("%s ", e); 30 | StdOut.println(); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Review/Graph/DijkstraSP_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/DijkstraSP_example_1.png -------------------------------------------------------------------------------- /Review/Graph/DijkstraSP_test_data.txt: -------------------------------------------------------------------------------- 1 | 10 2 | 20 3 | 0 0 0.80 4 | 0 1 0.72 5 | 1 9 0.31 6 | 2 0 0.77 7 | 4 8 0.48 8 | 5 1 0.64 9 | 5 1 0.69 10 | 5 4 0.05 11 | 6 9 0.73 12 | 6 9 0.99 13 | 6 5 0.74 14 | 7 0 0.71 15 | 7 1 0.08 16 | 7 2 0.27 17 | 7 5 0.03 18 | 8 3 0.86 19 | 8 8 0.08 20 | 9 7 0.08 21 | 9 3 0.67 22 | 9 0 0.92 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Review/Graph/DirectedEdge.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | public class DirectedEdge { 4 | private final int v; 5 | private final int w; 6 | private final double weight; 7 | public DirectedEdge(int v, int w, double weight) { this.v = v; this.w = w; this.weight = weight; } 8 | public String toString() { 9 | return String.format("{ %d -> %d %.2f }", v, w, weight); 10 | } 11 | public double weight() { return weight; } 12 | public int from() { return v; } 13 | public int to() { return w; } 14 | } 15 | -------------------------------------------------------------------------------- /Review/Graph/DirectedGraphDFS.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.In; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class DirectedGraphDFS { 7 | private Digraph g; 8 | private boolean marked[]; 9 | private int count; 10 | public DirectedGraphDFS(Digraph g, int s) { 11 | this.g = g; 12 | marked = new boolean[g.V()]; 13 | dfs(s); 14 | } 15 | private void dfs(int v) { 16 | marked[v] = true; 17 | for (int w : g.adj(v)) { 18 | if (!marked[w]) { 19 | count++; 20 | dfs(w); 21 | } 22 | } 23 | } 24 | public boolean reachable(int v) { return marked[v]; } 25 | public int count() { return count; } 26 | public static void main(String[] args) { 27 | Digraph g = new Digraph(new In("/Users/bot/Desktop/algs4-data/mediumDG.txt")); 28 | DirectedGraphDFS dfs = new DirectedGraphDFS(g, 0); 29 | StdOut.printf("可达顶点数目 : %d\n", dfs.count()); 30 | for (int i = 0; i < g.V(); i++) 31 | if (dfs.reachable(i)) 32 | StdOut.printf("%d 可达\n", i); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Review/Graph/Edge.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | public class Edge implements Comparable { 4 | private final int v; 5 | private final int w; 6 | private final double weight; 7 | public Edge(int v, int w, double weight) { 8 | this.v = v; 9 | this.w = w; 10 | this.weight = weight; 11 | } 12 | public double weight() { return weight; } 13 | public int compareTo(Edge that) { 14 | return weight < that.weight ? -1 : weight > that.weight ? 1 : 0; 15 | } 16 | public boolean isSelfLoop() { return v == w; } 17 | public int either() { return v; } 18 | public int other(int t) { 19 | if (t == w) return v; 20 | if (t == v) return w; 21 | throw new IllegalArgumentException(String.format("v must be value either %d or %d\n", v, w)); 22 | } 23 | public String toString() { return String.format("{ %d %d %.0f }", v, w, weight); } 24 | } 25 | -------------------------------------------------------------------------------- /Review/Graph/NonrecursiveDirectedGraphDFS.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.In; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class NonrecursiveDirectedGraphDFS { 7 | private Digraph g; 8 | private boolean marked[]; 9 | private int count; 10 | public NonrecursiveDirectedGraphDFS(Digraph g, int s) { 11 | marked = new boolean[g.V()]; 12 | this.g = g; 13 | dfs(s); 14 | } 15 | private void dfs(int v) { 16 | marked[v] = true; 17 | _Stack S = new _Stack<>(); 18 | S.push(v); 19 | boolean allMarked = true; 20 | while (!S.isEmpty()) { 21 | v = S.top(); 22 | allMarked = true; 23 | for (int w : g.adj(v)) { 24 | if (!marked[w]) { 25 | count++; 26 | marked[w] = true; 27 | allMarked = false; 28 | S.push(w); 29 | break; 30 | } 31 | } 32 | if (allMarked) 33 | S.pop(); 34 | } 35 | } 36 | public int count() { return count; } 37 | public boolean reachable(int v) { return marked[v]; } 38 | public static void main(String[] args) { 39 | Digraph g = new Digraph(new In("/Users/bot/Desktop/algs4-data/mediumDG.txt")); 40 | DirectedGraphDFS dfs = new DirectedGraphDFS(g, 0); 41 | StdOut.printf("可达顶点数目 : %d\n", dfs.count()); 42 | for (int i = 0; i < g.V(); i++) 43 | if (dfs.reachable(i)) 44 | StdOut.printf("%d 可达\n", i); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Review/Graph/Solution2.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class Solution2 { 6 | public static int countAndSay(int n) { 7 | String[] arr = new String[n]; 8 | arr[0] = "1"; 9 | for (int i = 1; i < n; i++) { 10 | arr[i] = computeNext(arr[i - 1]); 11 | for (int j = i - 1; j >= 0 && arr[j] != null; j--) 12 | arr[j] = null; 13 | System.gc(); 14 | } 15 | return arr[n - 1].length(); 16 | } 17 | public static String computeNext(String s) { 18 | StringBuilder sb = new StringBuilder(); 19 | int i = 0, j = 0, count = 0; 20 | while (j < s.length()) { 21 | if (s.charAt(i) == s.charAt(j)) { 22 | j++; 23 | count++; 24 | } else { 25 | sb.append(count + "" + s.charAt(i)); 26 | i = j; 27 | count = 0; 28 | } 29 | } 30 | sb.append(count + "" + s.charAt(i)); 31 | return sb.toString(); 32 | } 33 | public static void main(String[] args) { 34 | int k = 1; 35 | while (true) { 36 | int len = countAndSay(k); 37 | StdOut.printf("n = %d length = %d\n", k++, len); 38 | System.gc(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Review/Graph/TarjanSCC_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/TarjanSCC_example_1.png -------------------------------------------------------------------------------- /Review/Graph/TarjanSCC_example_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/TarjanSCC_example_2.png -------------------------------------------------------------------------------- /Review/Graph/TarjanSCC_example_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/TarjanSCC_example_3.png -------------------------------------------------------------------------------- /Review/Graph/Topological.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import java.util.*; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class Topological { 7 | private Iterable order; 8 | private int[] rank; 9 | private Digraph g; 10 | public Topological(Digraph g) { 11 | this.g = g; 12 | DirectedCycleX d = new DirectedCycleX(g); 13 | if (!d.hasCycle()) { 14 | rank = new int[g.V()]; 15 | DepthFirstOrder o = new DepthFirstOrder(g); 16 | order = o.postReverseOrder(); 17 | int i = 0; 18 | for (int w : order) 19 | rank[w] = i++; 20 | } 21 | } 22 | public Iterable order() { 23 | if (!hasOrder()) 24 | throw new RuntimeException("cycle exist, no sort!"); 25 | return order; 26 | } 27 | public boolean hasOrder() { return order != null; } 28 | public int rank(int v) { 29 | checkVertex(v); 30 | return rank[v]; 31 | } 32 | private void checkVertex(int v) { 33 | if (v < 0 || v >= g.V()) 34 | throw new IllegalArgumentException(v + " is invalid"); 35 | } 36 | public static void main(String[] args) { 37 | Digraph g = DigraphGenerator.DAG(10, 20); 38 | StdOut.println(g); 39 | Topological tp = new Topological(g); 40 | if (tp.hasOrder()) 41 | for (int w : tp.order()) 42 | StdOut.print(w + " "); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Review/Graph/TransitiveClosure.java: -------------------------------------------------------------------------------- 1 | package Review.Graph; 2 | 3 | import edu.princeton.cs.algs4.In; 4 | import edu.princeton.cs.algs4.StdOut; 5 | 6 | public class TransitiveClosure { 7 | private DepthFirstDirectedPath[] dc; 8 | public TransitiveClosure(Digraph g) { 9 | dc = new DepthFirstDirectedPath[g.V()]; 10 | for (int i = 0; i < g.V(); i++) 11 | dc[i] = new DepthFirstDirectedPath(g, i); 12 | } 13 | public boolean reachable(int v, int w) { return dc[v].hasPathTo(w); } 14 | public Iterable pathBetween(int v, int w) { 15 | if (!reachable(v, w)) 16 | throw new RuntimeException("no path between " + v + " and " + w); 17 | return dc[v].pathTo(w); 18 | } 19 | public static void main(String[] args) { 20 | Digraph g = new Digraph(new In("/Users/bot/Desktop/algs4-data/mediumDG.txt")); 21 | TransitiveClosure t = new TransitiveClosure(g); 22 | for (int i = 0; i < g.V(); i++) { 23 | for (int j = 0; j < g.V(); j++) 24 | StdOut.printf("%-2c", t.reachable(i, j) ? 'T' : ' '); 25 | StdOut.println(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Review/Graph/寻找有向图中的环_优化方案_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/寻找有向图中的环_优化方案_example_1.png -------------------------------------------------------------------------------- /Review/Graph/寻找有向图中的环_优化方案_example_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/寻找有向图中的环_优化方案_example_2.png -------------------------------------------------------------------------------- /Review/Graph/寻找欧拉环_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/寻找欧拉环_example_1.png -------------------------------------------------------------------------------- /Review/Graph/寻找欧拉环_example_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/寻找欧拉环_example_2.png -------------------------------------------------------------------------------- /Review/Graph/拓扑排序_exapmle_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YangXiaoHei/Algorithms/56d8a25f37a4150b9c44f7233ddaa6b260d9e671/Review/Graph/拓扑排序_exapmle_1.png -------------------------------------------------------------------------------- /Review/README.md: -------------------------------------------------------------------------------- 1 | ### 图复习目录 2 | 3 | * 数据结构 4 | * 无向图、有向图、加权图,有向加权图 5 | * 邻接表 6 | * 邻接矩阵 7 | * 缺点:无法表示平行边和自环 8 | * 符号图、有向符号图 9 | 10 | * 图结构生成 11 | * 生成欧拉环 12 | * 生成欧拉路径 13 | 14 | * 深搜、广搜 15 | * 无向图、加权图 16 | * 有向图、加权有向图 17 | * 深搜、广搜的区别 18 | 19 | * 非递归深搜 20 | * 无向图、加权图 21 | * 有向图、加权有向图 22 | 23 | * 计算连通分量 24 | * 并查集 25 | * `quick-find` 26 | * `quick-union` 27 | * 加权 `quick-union` 28 | * 路径压缩的加权 `quick-union` 29 | * 深搜 or 广搜 30 | 31 | * 识别二分图 32 | * 深搜 33 | * 广搜 : 是识别二分图的优化方案 34 | 35 | * 寻找环 36 | * 在无向图中寻找环 37 | * 在有向图中寻找环 38 | * 普通方案 39 | * 优化方案 40 | 41 | * 寻找欧拉环、欧拉路径 42 | * 在无向图中寻找欧拉环 43 | * 在有向图中寻找欧拉环 44 | 45 | * 拓扑排序 46 | * 普通方案 : 深搜的逆后序 47 | * 优化方案 : 逐个删除入度为 0 的顶点 48 | 49 | * 计算强连通分量 50 | * `KosarajuSCC` 51 | * 实现 52 | * 证明 53 | * `TarjanSCC` 54 | * 实现 55 | * 原理 56 | 57 | * 最小生成树算法 58 | * 切分定理 59 | * 最小生成树的贪心算法 60 | * 延时 `Prim` 算法 61 | * 时间复杂度 `O(ElogE)` 62 | * 空间复杂度 `O(E)` 63 | * 即时 Prim 算法 64 | * 时间复杂度 `O(ElogV)` 65 | * 空间复杂度 `O(V)` 66 | * Kruskal 算法 67 | * 时间复杂度 `O(ElogE)` 68 | * 空间复杂度 `O(E)` 69 | * `Prim` 算法和 `Dijkstra` 算法的区别 70 | 71 | * 最短路径 72 | * 最短路径的最优性条件 73 | * 通用最短路径算法 74 | * `Dijkstra` 算法 : 适用于没有负权重的边 75 | * `Acyclic` 算法 : 适用于无环图 76 | * `BellmanFord` 算法 : 适用于没有负权重环的图 77 | * `Dijkstra` 算法和 `BellmanFord` 算法的区别 78 | 79 | 80 | 81 | 82 | 83 | --------------------------------------------------------------------------------