版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、红黑树深入剖析及Java实现在理想的情况下,二叉查找树增删查改的时间复杂度为O(logN)(其中N为节点数),最坏的情况下为O(N)。当它的高度为logN+1时,我们就说二叉查找树是平衡的。作者:振兴来源:振兴|2016-12-08 11:01 收藏 分享 红黑树是平衡二叉查找树的一种。为了深入理解红黑树,我们需要从二叉查找树开始讲起。BST二叉查找树(Binary Search Tree,简称BST)是一棵二叉树,它的左子节点的值比父节点的值要小,右节点的值要比父节点的值大。它的高度决定了它的查找效率。在理想的情况下,二叉查找树增删查改的时间复杂
2、度为O(logN)(其中N为节点数),最坏的情况下为O(N)。当它的高度为logN+1时,我们就说二叉查找树是平衡的。BST的查找操作1. T key = a search key 2. Node root = point to the root of a BST 3. 4. while(true) 5. if(root=null) 6.
3、60; break; 7. 8. if(root.value.equals(key) 9. return root; 10. 11. else if(par
4、eTo(root.value)<0) 12. root = root.left; 13. 14. else 15. root = root.right; 16.
5、160;17. 18. return null; 从程序中可以看出,当BST查找的时候,先与当前节点进行比较:· 如果相等的话就返回当前节点;· 如果少于当前节点则继续查找当前节点的左节点;· 如果大于当前节点则继续查找当前节点的右节点。直到当前节点指针为空或者查找到对应的节点,程序查找结束。BST的插入操作1. Node node = create a new node with specify value 2. Node
6、;root = point the root node of a BST 3. Node parent = null; 4. 5. /find the parent node to append the new node 6. while(true) 7. if(root=null)break; 8.
7、0; parent = root; 9. if(pareTo(root.value)<=0) 10. root = root.left; 11. else 12. root = root.right; 13.
8、 14. 15. if(parent!=null) 16. if(pareTo(parent.value)<=0)/append to left 17. parent.left = node; 18. else/append to right 19.
9、160; parent.right = node; 20. 21. 插入操作先通过循环查找到待插入的节点的父节点,和查找父节点的逻辑一样,都是比大小,小的往左,大的往右。找到父节点后,对比父节点,小的就插入到父节点的左节点,大就插入到父节点的右节点上。BST的删除操作删除操作的步骤如下:1. 查找到要删除的节点。2. 如果待删除的节点是叶子节点,则直接删除。3. 如果待删除的节点不是叶子节点,则先找到待删除节点的中序遍历的后继节点,用该后继节点的值替换待删除的节点的值,然后删除后继节
10、点。BST存在的问题BST存在的主要问题是,数在插入的时候会导致树倾斜,不同的插入顺序会导致树的高度不一样,而树的高度直接的影响了树的查找效率。理想的高度是logN,最坏的情况是所有的节点都在一条斜线上,这样的树的高度为N。RBTree基于BST存在的问题,一种新的树平衡二叉查找树(Balanced BST)产生了。平衡树在插入和删除的时候,会通过旋转操作将高度保持在logN。其中两款具有代表性的平衡树分别为AVL树和红黑树。AVL树由于实现比较复杂,而且插入和删除性能差,在实际环境下的应用不如红黑树。红黑树(Red-Black Tree,以下简称RBTree)的实际应用非常广泛,比如Linu
11、x内核中的完全公平调度器、高精度计时器、ext3文件系统等等,各种语言的函数库如Java的TreeMap和TreeSet,C+ STL的map、multimap、multiset等。RBTree也是函数式语言中最常用的持久数据结构之一,在计算几何中也有重要作用。值得一提的是,Java 8中HashMap的实现也因为用RBTree取代链表,性能有所提升。RBTree的定义RBTree的定义如下:1. 任何一个节点都有颜色,黑色或者红色2. 根节点是黑色的3. 父子节点之间不能出现两个连续的红节点4. 任何一个节点向下遍历到其子孙的叶子节点,所经过的黑节点个数必须相等5. 空节点被认为是黑色的数据
12、结构表示如下:1. class Node<T> 2. public T value; 3. public Node<T> parent; 4. public boolean isRed; 5. public Node
13、<T> left; 6. public Node<T> right; 7. RBTree在理论上还是一棵BST树,但是它在对BST的插入和删除操作时会维持树的平衡,即保证树的高度在logN,logN+1(理论上,极端的情况下可以出现RBTree的高度达到2*logN,但实际上很难遇到)。这样RBTree的查找时间复杂度始终保持在O(logN)从而接近于理想的BST。RBTree的删除和插入操作的时间复杂度也是O(logN)。RBTree的查找操作就是
14、BST的查找操作。RBTree的旋转操作旋转操作(Rotate)的目的是使节点颜色符合定义,让RBTree的高度达到平衡。Rotate分为left-rotate(左旋)和right-rotate(右旋),区分左旋和右旋的方法是:待旋转的节点从左边上升到父节点就是右旋,待旋转的节点从右边上升到父节点就是左旋。RBTree的查找操作RBTree的查找操作和BST的查找操作是一样的。请参考BST的查找操作代码。RBTree的插入操作RBTree的插入与BST的插入方式是一致的,只不过是在插入过后,可能会导致树的不平衡,这时就需要对树进行旋转操作和颜色修复(在这里简称插入修复),使得它符合RBTree
15、的定义。新插入的节点是红色的,插入修复操作如果遇到父节点的颜色为黑则修复操作结束。也就是说,只有在父节点为红色节点的时候是需要插入修复操作的。插入修复操作分为以下的三种情况,而且新插入的节点的父节点都是红色的:1. 叔叔节点也为红色。2. 叔叔节点为空,且祖父节点、父节点和新节点处于一条斜线上。3. 叔叔节点为空,且祖父节点、父节点和新节点不处于一条斜线上。插入操作-case 1case 1的操作是将父节点和叔叔节点与祖父节点的颜色互换,这样就符合了RBTRee的定义。即维持了高度的平衡,修复后颜色也符合RBTree定义的第三条和第四条。下图中,操作完成后A节点变成了新的节点。如果A节点的父节
16、点不是黑色的话,则继续做修复操作。插入操作-case 2case 2的操作是将B节点进行右旋操作,并且和父节点A互换颜色。通过该修复操作RBTRee的高度和颜色都符合红黑树的定义。如果B和C节点都是右节点的话,只要将操作变成左旋就可以了。插入操作-case 3case 3的操作是将C节点进行左旋,这样就从case 3转换成case 2了,然后针对case 2进行操作处理就行了。case 2操作做了一个右旋操作和颜色互换来达到目的。如果树的结构是下图的镜像结构,则只需要将对应的左旋变成右旋,右旋变成左旋即可。插入操作的总结插入后的修复操作是一个向root节点回溯的操作,一旦牵涉的节点都符合了红黑
17、树的定义,修复操作结束。之所以会向上回溯是由于case 1操作会将父节点,叔叔节点和祖父节点进行换颜色,有可能会导致祖父节点不平衡(红黑树定义3)。这个时候需要对祖父节点为起点进行调节(向上回溯)。祖父节点调节后如果还是遇到它的祖父颜色问题,操作就会继续向上回溯,直到root节点为止,根据定义root节点永远是黑色的。在向上的追溯的过程中,针对插入的3中情况进行调节。直到符合红黑树的定义为止。直到牵涉的节点都符合了红黑树的定义,修复操作结束。如果上面的3中情况如果对应的操作是在右子树上,做对应的镜像操作就是了。RBTree的删除操作删除操作首先需要做的也是BST的删除操作,删除操作会删除对应的
18、节点,如果是叶子节点就直接删除,如果是非叶子节点,会用对应的中序遍历的后继节点来顶替要删除节点的位置。删除后就需要做删除修复操作,使的树符合红黑树的定义,符合定义的红黑树高度是平衡的。删除修复操作在遇到被删除的节点是红色节点或者到达root节点时,修复操作完毕。删除修复操作是针对删除黑色节点才有的,当黑色节点被删除后会让整个树不符合RBTree的定义的第四条。需要做的处理是从兄弟节点上借调黑色的节点过来,如果兄弟节点没有黑节点可以借调的话,就只能往上追溯,将每一级的黑节点数减去一个,使得整棵树符合红黑树的定义。删除操作的总体思想是从兄弟节点借调黑色节点使树保持局部的平衡,如果局部的平衡达到了,
19、就看整体的树是否是平衡的,如果不平衡就接着向上追溯调整。删除修复操作分为四种情况(删除黑节点后):1. 待删除的节点的兄弟节点是红色的节点。2. 待删除的节点的兄弟节点是黑色的节点,且兄弟节点的子节点都是黑色的。3. 待调整的节点的兄弟节点是黑色的节点,且兄弟节点的左子节点是红色的,右节点是黑色的(兄弟节点在右边),如果兄弟节点在左边的话,就是兄弟节点的右子节点是红色的,左节点是黑色的。4. 待调整的节点的兄弟节点是黑色的节点,且右子节点是是红色的(兄弟节点在右边),如果兄弟节点在左边,则就是对应的就是左节点是红色的。删除操作-case 1由于兄弟节点是红色节点的时候,无法借调黑节点,所以需要
20、将兄弟节点提升到父节点,由于兄弟节点是红色的,根据RBTree的定义,兄弟节点的子节点是黑色的,就可以从它的子节点借调了。case 1这样转换之后就会变成后面的case 2,case 3,或者case 4进行处理了。上升操作需要对C做一个左旋操作,如果是镜像结构的树只需要做对应的右旋操作即可。之所以要做case 1操作是因为兄弟节点是红色的,无法借到一个黑节点来填补删除的黑节点。删除操作-case 2case 2的删除操作是由于兄弟节点可以消除一个黑色节点,因为兄弟节点和兄弟节点的子节点都是黑色的,所以可以将兄弟节点变红,这样就可以保证树的局部的颜色符合定义了。这个时候需要将父节点A变成新的节
21、点,继续向上调整,直到整颗树的颜色符合RBTree的定义为止。case 2这种情况下之所以要将兄弟节点变红,是因为如果把兄弟节点借调过来,会导致兄弟的结构不符合RBTree的定义,这样的情况下只能是将兄弟节点也变成红色来达到颜色的平衡。当将兄弟节点也变红之后,达到了局部的平衡了,但是对于祖父节点来说是不符合定义4的。这样就需要回溯到父节点,接着进行修复操作。删除操作-case 3case 3的删除操作是一个中间步骤,它的目的是将左边的红色节点借调过来,这样就可以转换成case 4状态了,在case 4状态下可以将D,E节点都阶段过来,通过将两个节点变成黑色来保证红黑树的整体平衡。之所以说cas
22、e-3是一个中间状态,是因为根据红黑树的定义来说,下图并不是平衡的,他是通过case 2操作完后向上回溯出现的状态。之所以会出现case 3和后面的case 4的情况,是因为可以通过借用侄子节点的红色,变成黑色来符合红黑树定义4.删除操作-case 4Case 4的操作是真正的节点借调操作,通过将兄弟节点以及兄弟节点的右节点借调过来,并将兄弟节点的右子节点变成红色来达到借调两个黑节点的目的,这样的话,整棵树还是符合RBTree的定义的。Case 4这种情况的发生只有在待删除的节点的兄弟节点为黑,且子节点不全部为黑,才有可能借调到两个节点来做黑节点使用,从而保持整棵树都符合红黑树的定义。删除操作
23、的总结红黑树的删除操作是最复杂的操作,复杂的地方就在于当删除了黑色节点的时候,如何从兄弟节点去借调节点,以保证树的颜色符合定义。由于红色的兄弟节点是没法借调出黑节点的,这样只能通过选择操作让他上升到父节点,而由于它是红节点,所以它的子节点就是黑的,可以借调。对于兄弟节点是黑色节点的可以分成3种情况来处理,当所以的兄弟节点的子节点都是黑色节点时,可以直接将兄弟节点变红,这样局部的红黑树颜色是符合定义的。但是整颗树不一定是符合红黑树定义的,需要往上追溯继续调整。对于兄弟节点的子节点为左红右黑或者 (全部为红,右红左黑)这两种情况,可以先将前面的情况通过选择转换为后一种情况,在后一种情况下,因为兄弟
24、节点为黑,兄弟节点的右节点为红,可以借调出两个节点出来做黑节点,这样就可以保证删除了黑节点,整棵树还是符合红黑树的定义的,因为黑色节点的个数没有改变。红黑树的删除操作是遇到删除的节点为红色,或者追溯调整到了root节点,这时删除的修复操作完毕。RBTree的Java实现1. public class RBTreeNode<T extends Comparable<T>> 2. private T value;/node value&
25、#160;3. private RBTreeNode<T> left;/left child pointer 4. private RBTreeNode<T> right;/right child pointer 5. private RBTreeNode<T> parent;/parent
26、0;pointer 6. private boolean red;/color is red or not red 7. 8. public RBTreeNode() 9. public RBTreeNode(T value)this.value=value; 10.
27、; public RBTreeNode(T value,boolean isRed)this.value=value;this.red = isRed; 11. 12. public T getValue() 13. return value; 14.
28、;15. void setValue(T value) 16. this.value = value; 17. 18. RBTreeNode<T> getLeft() 19.
29、0; return left; 20. 21. void setLeft(RBTreeNode<T> left) 22. this.left = left; 23. 24.
30、 RBTreeNode<T> getRight() 25. return right; 26. 27. void setRight(RBTreeNode<T> right) 28. &
31、#160; this.right = right; 29. 30. RBTreeNode<T> getParent() 31. return parent; 32. 33. void&
32、#160;setParent(RBTreeNode<T> parent) 34. this.parent = parent; 35. 36. boolean isRed() 37. return
33、 red; 38. 39. boolean isBlack() 40. return !red; 41. 42. /* 43. * is leaf
34、160;node 44. */ 45. boolean isLeaf() 46. return left=null && right=null; 47. 48. 49. void s
35、etRed(boolean red) 50. this.red = red; 51. 52. 53. void makeRed() 54. red=true; 55.
36、160; 56. void makeBlack() 57. red=false; 58. 59. Override 60. public String toString() 61. &
37、#160; return value.toString(); 62. 63. 64. 65. public class RBTree<T extends Comparable<T>> 66. private final RBTreeNode<T> root;
38、160;67. /node number 68. private java.util.concurrent.atomic.AtomicLong size = 69. new java
39、.util.concurrent.atomic.AtomicLong(0); 70. 71. /in overwrite mode,all node's value can not has same value 72. /in non-overwrite mode,node can h
40、ave same value, suggest don't use non-overwrite mode. 73. private volatile boolean overrideMode=true; 74. 75. public RBTree() 76.
41、 this.root = new RBTreeNode<T>(); 77. 78. 79. public RBTree(boolean overrideMode) 80. this(); 81. &
42、#160;this.overrideMode=overrideMode; 82. 83. 84. public boolean isOverrideMode() 85. return overrideMode; 86. 87. 88.
43、160; public void setOverrideMode(boolean overrideMode) 89. this.overrideMode = overrideMode; 90. 91. 92. /* 93.
44、; * number of tree number 94. * return 95. */ 96. public long getSize() 97. return size.get
45、(); 98. 99. /* 100. * get the root node 101. * return 102. */ 103. private RB
46、TreeNode<T> getRoot() 104. return root.getLeft(); 105. 106. 107. /* 108. * add value to a new node,if
47、 this value exist in this tree, 109. * if value exist,it will return the exist value.otherwise return null 110. * if override mode
48、;is true,if value exist in the tree, 111. * it will override the old value in the tree 112. * 113. * param
49、60;value 114. * return 115. */ 116. public T addNode(T value) 117. RBTreeNode<T> t = new RBTreeNode<
50、;T>(value); 118. return addNode(t); 119. 120. /* 121. * find the value by give value(include key,key used
51、 for search, 122. * other field is not used,see compare method).if this value not exist return null 123. * param value 124.
52、0; * return 125. */ 126. public T find(T value) 127. RBTreeNode<T> dataRoot = getRoot(); 128.
53、160; while(dataRoot!=null) 129. int cmp = dataRoot.getValue().compareTo(value); 130. if(cmp<0) 131.
54、 dataRoot = dataRoot.getRight(); 132. else if(cmp>0) 133.
55、; dataRoot = dataRoot.getLeft(); 134. else 135. return dataRoot.getValue
56、(); 136. 137. 138. return null; 139. 140. /* 1
57、41. * remove the node by give value,if this value not exists in tree return null 142. * param value include search key 143.
58、; * return the value contain in the removed node 144. */ 145. public T remove(T value) 146. RBTreeNode<T>
59、 dataRoot = getRoot(); 147. RBTreeNode<T> parent = root; 148. 149. while(dataRoot!=null) 150.
60、; int cmp = dataRoot.getValue().compareTo(value); 151. if(cmp<0) 152. parent =
61、0;dataRoot; 153. dataRoot = dataRoot.getRight(); 154. else if(cmp>0) 155. &
62、#160; parent = dataRoot; 156. dataRoot = dataRoot.getLeft(); 157. &
63、#160; else 158. if(dataRoot.getRight()!=null) 159.
64、RBTreeNode<T> min = removeMin(dataRoot.getRight(); 160. /x used for fix color balance 161.
65、60; RBTreeNode<T> x = min.getRight()=null ? min.getParent() : min.getRight(); 162.
66、0; boolean isParent = min.getRight()=null; 163. 164. min.setLeft(dataRoot.getLeft(); 165.
67、 setParent(dataRoot.getLeft(),min); 166. if(parent.getLeft()=dataRoot) 167.
68、; parent.setLeft(min); 168. else
69、169. parent.setRight(min); 170.
70、; 171. setParent(min,parent); 172. 173. bool
71、ean curMinIsBlack = min.isBlack(); 174. /inherit dataRoot's color 175.
72、0; min.setRed(dataRoot.isRed(); 176. 177. if(min!=dataRoot.getRight() 178.
73、 min.setRight(dataRoot.getRight(); 179. setParent(
74、dataRoot.getRight(),min); 180. 181. /remove
75、a black node,need fix color 182. if(curMinIsBlack) 183.
76、0; if(min!=dataRoot.getRight() 184. fixRemove(x,isParent); 185.
77、; else if(min.getRight()!=null) 186.
78、160; fixRemove(min.getRight(),false); 187. else 188.
79、0; fixRemove(min,true); 189. 190
80、. 191. else 192.
81、160; setParent(dataRoot.getLeft(),parent); 193. if(parent.getLeft()=dataRoot) 194.
82、0; parent.setLeft(dataRoot.getLeft(); 195. else 196.
83、0; parent.setRight(dataRoot.getLeft(); 197.
84、 198. /current node is black and tree is not empty 199.
85、160; if(dataRoot.isBlack() && !(root.getLeft()=null) 200. RBTreeNode<T> x
86、160;= dataRoot.getLeft()=null 201.
87、60; ? parent :dataRoot.getLeft(); 202. boolean isParent = dataRoot.getLeft()=null; 203.
88、0; fixRemove(x,isParent); 204. 205.
89、160; 206. setParent(dataRoot,null); 207.
90、60; dataRoot.setLeft(null); 208. dataRoot.setRight(null); 209. if(getRoot()!=null
91、) 210. getRoot().setRed(false); 211. getRoot().set
92、Parent(null); 212. 213. size.decrementAndGet(); 214.
93、60; return dataRoot.getValue(); 215. 216. 217. return
94、0;null; 218. 219. /* 220. * fix remove action 221. * param node 222. * param isParent 223.
95、; */ 224. private void fixRemove(RBTreeNode<T> node,boolean isParent) 225. RBTreeNode<T> cur = isParent ? null : node; 226.
96、 boolean isRed = isParent ? false : node.isRed(); 227. RBTreeNode<T> parent = isParent ? node : node.getParent(); 228.
97、 229. while(!isRed && !isRoot(cur) 230. RBTreeNode<T> sibling = getSibling(cur,parent); 231.
98、160; /sibling is not null,due to before remove tree color is balance 232. 233. /if cur is a left node
99、234. boolean isLeft = parent.getRight()=sibling; 235. if(sibling.isRed() && !isLeft)/case 1 236.
100、; /cur in right 237. parent.makeRed(); 238.
101、60; sibling.makeBlack(); 239. rotateRight(parent); 240. else if(sibling.isRed()
102、60;&& isLeft) 241. /cur in left 242. parent.makeRed(); 243.
103、0; sibling.makeBlack(); 244. rotateLeft(parent); 245.
104、60; else if(isBlack(sibling.getLeft() && isBlack(sibling.getRight()/case 2 246. sibling.makeRed(); 247.
105、60; cur = parent; 248. isRed = cur.isRed(); 249.
106、 parent=parent.getParent(); 250. else if(isLeft && !isBlack(sibling.getLeft() 251.
107、; && isBlack(sibling.getRight()/case 3 252. sibling.makeRed();
108、 253. sibling.getLeft().makeBlack(); 254. rotateRight(sibling); 255.
109、 else if(!isLeft && !isBlack(sibling.getRight() 256.
110、0; && isBlack(sibling.getLeft() ) 257. sibling.makeRed(); 258.
111、 sibling.getRight().makeBlack(); 259. rotateLeft(sibling); 260.
112、; else if(isLeft && !isBlack(sibling.getRight()/case 4 261. sibling.setRed(parent.isRed(); 262.
113、; parent.makeBlack(); 263. sibling.getRight().makeBlack(); 264.
114、; rotateLeft(parent); 265. cur=getRoot(); 266. else if(!isLeft && !isBlack(sibling.getLeft()
115、160;267. sibling.setRed(parent.isRed(); 268. parent.makeBlack(); 269.
116、0; sibling.getLeft().makeBlack(); 270. rotateRight(parent); 271.
117、0; cur=getRoot(); 272. 273. 274. if(isRed) 275.
118、60; cur.makeBlack(); 276. 277. if(getRoot()!=null) 278. getRoot().setRed(false);&
119、#160;279. getRoot().setParent(null); 280. 281. 282. 283. /get sibling node 284.
120、160; private RBTreeNode<T> getSibling(RBTreeNode<T> node,RBTreeNode<T> parent) 285. parent = node=null ? parent : node.getParent(); 286.
121、160; if(node=null) 287. return parent.getLeft()=null ? parent.getRight() : parent.getLeft(); 288. 289. &
122、#160; if(node=parent.getLeft() 290. return parent.getRight(); 291. else 292.
123、 return parent.getLeft(); 293. 294. 295. 296. private boolean isBlack(RBTreeNode<T> node) 297. re
124、turn node=null | node.isBlack(); 298. 299. private boolean isRoot(RBTreeNode<T> node) 300. return root.getLeft() = node &&
125、160;node.getParent()=null; 301. 302. /* 303. * find the successor node 304. * param node current node's right node
126、60;305. * return 306. */ 307. private RBTreeNode<T> removeMin(RBTreeNode<T> node) 308. /find the min node&
127、#160;309. RBTreeNode<T> parent = node; 310. while(node!=null && node.getLeft()!=null) 311. parent = node; 312. node = node.getLeft(); 313. 314. /remove min no
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年西宁晚报数字报刊内容版权保护与许可合同3篇
- 建设工程消防查验合同(2篇)
- 重点领域政策力度持续加强 债券市场信用风险趋于缓和-2024年债券市场信用风险分析及2025年展望 -新世纪
- 初三中考备考指导模板
- 2025年销售薪资结构优化合同规范2篇
- 九年级自我介绍综评范文(4篇)
- 益阳双面铣床施工方案
- 雨刷器机械原理课程设计
- 二零二五民法典合同编电子书制作合同4篇
- 2025年度电影院日常保洁与观众安全服务合同4篇
- 物业民法典知识培训课件
- 2023年初中毕业生信息技术中考知识点详解
- 《万方数据资源介绍》课件
- 第一章-地震工程学概论
- 2024年浙江省中考数学试题及答案
- 2025届江苏省南京高考历史一模试卷含解析
- 浙江省金华市金东区2022-2024年中考二模英语试题汇编:任务型阅读
- 青岛版(五四制)四年级数学下册全册课件
- 大健康行业研究课件
- 租赁汽车可行性报告
- 计算机辅助设计AutoCAD绘图-课程教案
评论
0/150
提交评论