1.常用的数据结构

  • 1.数组(Array)
    数组可以说是最基本的数据结构。它是将相同类型的一些数据有序的集合在一起。
    一个数组可以包含多个同类型的数据元素。
    可以按照数据类型分为整型数组、字符型数组、浮点型数组、对象数组等。
    可以按照维度分为一维数组、二维数组、多维数组等。
  • 2.队列(Queue)
    队列也是一种特殊的线性表。只允许在一端(队尾)进行插入,在另一端(队头)进行删除。
    线性表就是各个数据元素之间具有线性关系。就像一条线一样。有头有尾,中间一个结点连着一个结点,不可间断。
    队列就像水管一样,水只能从一端流入,从另一端流出。
  • 3.链表(Linked List)
    链表的元素是按照链式存储的。也是线性结构中的一种。线性结构包括顺序结构和链表结构两种。
    这种存储在物理上并非连续的,而是每个元素包括两个部分,一部分是自己的数据,另一部分是引用域,指向下一个元素所在的地址。
    链表的逻辑关系是通过引用域串联起来的。
    线性结构中的顺序表结构在进行插入或者删除的时候,需要移动大量的数据。而链表结构最多只需要修改关联的前后两个结点的引用域即可。
    链表包含单向链表和双向链表,单向链的引用域只指向下一个元素的地址,双向链表的引用域既包含指向下一个的地址,也有指向上一个的地址。
  • 4.树(Tree)
    典型的非线性结构,有且仅有一个根结点,根结点会有一个或多个子结点。
    然后子结点也可能会有一个或多个子结点。但是,每个子结点都只会有一个父结点。
    终结点没有子结点。
    每个节点后面的所有节点组成的树称为这个结点的子树。
    二叉树是一种比较特殊的树,每一个结点最多都只有两个子结点。称为左结点和右结点。
    二叉树又包括完全二叉树(有子结点的结点都有两个子结点),和非完全二叉树(有些结点只有一个子结点)。
  • 5.堆(Heap)
    堆是一种特殊的树形结构,我们一般讨论的堆都是二叉堆。
    堆的特点是根结点的值是所有结点中最小的或者最大的。并且根结点的子树也是一个堆结构。
  • 6.栈(Stack)
    栈是一种特殊的线性表,只能在表的一端(栈顶)进行插入(入栈)和删除(出栈)操作。
    第一个插入的数据会被后面插入的不断的压入栈底。要想操作栈底的数据,只能先将其推到栈顶。
  • 7.图(Graph)
    图是另外一种非线性结构,例如通信网络、交通网络、人机关系网络,都可以归为图结构
    图可以分为无向图和有向图,
    无向图没有方向,从A到B和从B到A一样,
    有向图具有方向,就像单行道,只能从A到B,不可以逆向从B到A
    连接图的某个定点到其他所有定点的边的数量称为该顶点的度。
  • 8.散列表(Hash)
    源自散列函数(Hash function),其思想是如果在结构中存在关键字和T相等的记录,那么必定在F(T)的存储位置可以找到该记录,这样就可以不用进行比较而直接取得所查记录

2.链表结构

常用的数据结构 - 图1

  1. /**
  2. * 定义数据结构中的元素
  3. */
  4. static class DataElement {
  5. String key;
  6. String other_messages;
  7. public DataElement(String key, String other_messages) {
  8. this.key = key;
  9. this.other_messages = other_messages;
  10. }
  11. }
  12. /**
  13. * 定义链表结构
  14. * 链表包含单向链表和双向链表,单向链的引用域只指向下一个元素的地址,双向链表的引用域既有指向下一个的,也有指向上一个的
  15. */
  16. static class DataLinkedList {
  17. DataElement dataElement;
  18. DataLinkedList nextNode;
  19. //我们这里只做查找算法的示例,省去添加节点,删除节点等其他方法,只做查找
  20. /**
  21. * 在链表的尾部追加数据
  22. *
  23. * @param head 链表的表头
  24. * @param data 要添加的数据
  25. * @return 添加后的链表元素(数据+引用域)
  26. */
  27. static DataLinkedList addData(DataLinkedList head, DataElement data) {
  28. DataLinkedList node = new DataLinkedList();//新追加的结点是在结尾追加
  29. node.dataElement = data;//保存数据
  30. node.nextNode = null;//表尾引用域为null,
  31. DataLinkedList element = head;
  32. if (element == null) {//链表的表头为null,是个空链表,直接将head指向新节点
  33. head = node;
  34. return head;
  35. }
  36. while (element.nextNode != null) {//找到链表的尾部,如果已知链表尾部,则可以直接用,不用再从表头查找
  37. element = element.nextNode;
  38. }
  39. element.nextNode = node;//将链表的尾部指向新追加的结点
  40. return node;
  41. }
  42. /**
  43. * 在表头追加数据
  44. *
  45. * @param head 表头
  46. * @param data 要添加的数据
  47. * @return 添加后的链表元素(数据+引用域)
  48. */
  49. static DataLinkedList addHeadData(DataLinkedList head, DataElement data) {
  50. DataLinkedList node = new DataLinkedList();//新追加的结点是在链表头部追加
  51. node.dataElement = data;//保存数据
  52. node.nextNode = head;//指向下一个元素是之前的表头
  53. head = node;//表头变成新增的这个元素
  54. return head;
  55. }
  56. /**
  57. * 在指定的key后面追加数据
  58. *
  59. * @param head 表头
  60. * @param key 元素数据的key
  61. * @param data 要插入的新数据
  62. * @return 插入的新元素(数据+引用)
  63. */
  64. static DataLinkedList insertData(DataLinkedList head, String key, DataElement data) {
  65. DataLinkedList keyData = null;
  66. //查找key所在的位置
  67. DataLinkedList temp = head;
  68. while (temp != null) {
  69. DataElement date = temp.dataElement;
  70. if (date.key.equals(key)) {//节点的关键字与传入的关键字相同
  71. keyData = temp;//找到key的位置
  72. break;
  73. }
  74. temp = temp.nextNode;//处理下一节点
  75. }
  76. if (keyData != null) {
  77. DataLinkedList node = new DataLinkedList();//新追加的结点是在链表头部追加
  78. node.dataElement = data;//保存数据
  79. node.nextNode = keyData.nextNode;//新元素指向key所指向的下一个元素
  80. //如果是双向链表,keyData.nextNode的元素的previousNode也要指向新添加的元素node,
  81. //而新添加的node的previousNode也要指向keyData
  82. keyData.nextNode = node;//key指向新添加的元素
  83. return node;
  84. }
  85. return null;//未找到指定key所在的位置
  86. }
  87. /**
  88. * 链表结构中的查找算法
  89. * 一般来说可以通过关键字查询,从表头依次查找
  90. *
  91. * @param head 链表表头
  92. * @param key 查找的关键字
  93. */
  94. static DataLinkedList findData(DataLinkedList head, String key) {
  95. DataLinkedList temp = head;//保存表头指针
  96. while (temp != null) {//节点有效,进行查找
  97. DataElement date = temp.dataElement;
  98. if (date != null && date.key != null) {
  99. if (date.key.equals(key)) {//节点的关键字与传入的关键字相同
  100. return temp;//返回该节点指针
  101. }
  102. }
  103. temp = temp.nextNode;//处理下一节点
  104. }
  105. return null;//未找到,返回空指针
  106. }
  107. /**
  108. * 删除key对应的元素
  109. *
  110. * @param head 表头
  111. * @param key 数据的关键字
  112. * @return 删除成功还是失败
  113. */
  114. static boolean deleteNode(DataLinkedList head, String key) {
  115. DataLinkedList previousData = null;
  116. DataLinkedList temp = head;
  117. while (temp != null) {//节点有效,进行查找
  118. DataElement date = temp.dataElement;
  119. if (date != null && date.key != null) {
  120. if (date.key.equals(key)) {//节点的关键字与传入的关键字相同
  121. if (previousData != null) {
  122. previousData.nextNode = temp.nextNode;//将上一个节点的nextNode指向当前节点的下一个结点
  123. temp = null;//删除当前节点释放内存
  124. return true;
  125. }
  126. }
  127. }
  128. previousData = temp;
  129. temp = temp.nextNode;//处理下一节点
  130. }
  131. return false;//没有找到key对应的结点
  132. }
  133. /**
  134. * 获取链表长度
  135. *
  136. * @param head 表头
  137. * @return 链表长度
  138. */
  139. static int size(DataLinkedList head) {
  140. DataLinkedList temp = head;
  141. int size = 0;
  142. while (temp != null) {
  143. size++;//当前结点非空,数量+1
  144. temp = temp.nextNode;//处理下一节点
  145. }
  146. return size;
  147. }
  148. /**
  149. * 输出所有结点数据
  150. *
  151. * @param head 表头
  152. */
  153. static void showAllNode(DataLinkedList head) {
  154. DataLinkedList temp = head;
  155. while (temp != null) {
  156. //输出当前结点的数据
  157. DataElement date = temp.dataElement;
  158. if (date != null && date.key != null) {
  159. System.out.printf("data:{key:%s,otherMessage:%s}%n",
  160. date.key, date.other_messages);
  161. }
  162. temp = temp.nextNode;//处理下一节点
  163. }
  164. }
  165. }

调用:

  1. DataLinkedList head = new DataLinkedList();
  2. head.dataElement = new DataElement("key1", "otherMessage1");
  3. head.nextNode = null;
  4. System.out.printf("开始在头部追加结点keyHead.%n");
  5. head = DataLinkedList.addHeadData(head, new DataElement("keyHead", "otherMessageHead"));
  6. if (head != null) {
  7. System.out.printf("链表头部追加结点成功!%n");
  8. }
  9. System.out.printf("开始在尾部追加结点key2.%n");
  10. DataLinkedList node = DataLinkedList.addData(head, new DataElement("key2", "otherMessage2"));
  11. if (node != null) {
  12. System.out.printf("链表尾部追加结点成功!%n");
  13. }
  14. System.out.printf("开始在key1后插入结点key3.%n");
  15. node = DataLinkedList.insertData(head, "key1", new DataElement("key3", "otherMessage3"));
  16. if (node != null) {
  17. System.out.printf("在key1后插入结点成功!%n");
  18. }
  19. System.out.printf("开始查找key2所在的结点,%n");
  20. node = DataLinkedList.findData(head, "key2");
  21. if (node != null) {
  22. System.out.printf("key2所在的结点:data:{key:%s,otherMessage:%s},nextNodeAddress:{%s}%n",
  23. node.dataElement.key, node.dataElement.other_messages, node.nextNode);
  24. }
  25. int size = DataLinkedList.size(head);
  26. System.out.printf("链表中总长度为:%d%n", size);
  27. System.out.printf("链表中的所有元素:%n");
  28. DataLinkedList.showAllNode(head);
  29. boolean delete = DataLinkedList.deleteNode(head, "key2");
  30. System.out.printf("链表中删除key2元素的结果:%b%n", delete);

输出:

  1. 开始在头部追加结点keyHead.
  2. 链表头部追加结点成功!
  3. 开始在尾部追加结点key2.
  4. 链表尾部追加结点成功!
  5. 开始在key1后插入结点key3.
  6. key1后插入结点成功!
  7. 开始查找key2所在的结点,
  8. key2所在的结点:data:{key:key2,otherMessage:otherMessage2},nextNodeAddress:{null}
  9. 链表中总长度为:4
  10. 链表中的所有元素:
  11. data:{key:keyHead,otherMessage:otherMessageHead}
  12. data:{key:key1,otherMessage:otherMessage1}
  13. data:{key:key3,otherMessage:otherMessage3}
  14. data:{key:key2,otherMessage:otherMessage2}
  15. 链表中删除key2元素的结果:true

3.队列结构

常用的数据结构 - 图2

由于队列结构比较简单,就不做详细的示例,代码可以参考下面的栈结构,将栈顶作为队头,并增加队尾标记,以及对队头、队尾的相关操作即可。

4.树结构

常用的数据结构 - 图3

常用的数据结构 - 图4

常用的数据结构 - 图5

常用的数据结构 - 图6

  1. /**
  2. * 定义二叉树结构
  3. */
  4. static class TreeDate {
  5. String data;
  6. TreeDate leftData;
  7. TreeDate rightData;
  8. /**
  9. * 初始化二叉树
  10. *
  11. * @param rootData 根结点的数据
  12. * @return TreeDate二叉树的树根
  13. */
  14. static TreeDate initTree(String rootData) {
  15. TreeDate treeRoot = new TreeDate();
  16. treeRoot.data = rootData;
  17. treeRoot.leftData = null;
  18. treeRoot.rightData = null;
  19. return treeRoot;
  20. }
  21. /**
  22. * 添加树结点
  23. *
  24. * @param treeRoot 树的跟结点
  25. * @param parentData 要添加的结点位于哪个父结点下
  26. * @param leftOrRight 作为父结点的左子树(1)还是右子树(2)
  27. * @param nodeData 要添加的结点数据
  28. */
  29. static void addNode(TreeDate treeRoot, String parentData, int leftOrRight, String nodeData) {
  30. TreeDate parentNode = findData(treeRoot, parentData);//根据key找到父结点
  31. if (parentNode != null) {
  32. TreeDate node = new TreeDate();
  33. node.data = nodeData;
  34. node.leftData = null;
  35. node.rightData = null;
  36. switch (leftOrRight) {
  37. case 1:
  38. if (parentNode.leftData != null) {
  39. System.out.printf("父节点的左子树不为空!");
  40. } else {
  41. parentNode.leftData = node;
  42. }
  43. break;
  44. case 2:
  45. if (parentNode.rightData != null) {
  46. System.out.printf("父节点的右子树不为空!");
  47. } else {
  48. parentNode.rightData = node;
  49. }
  50. break;
  51. }
  52. } else {
  53. System.out.printf("父节点[%s]未找到!", parentData);
  54. }
  55. }
  56. /**
  57. * 二叉树查找算法
  58. * 遍历二叉树中的每一个结点,逐个比较数据。
  59. *
  60. * @param treeNode 树结点,首次调用传入树的根结点
  61. * @param data 要查找的结点
  62. * @return TreeDate 查找结果
  63. */
  64. static TreeDate findData(TreeDate treeNode, String data) {
  65. if (treeNode == null) {
  66. return null;
  67. } else {
  68. if (treeNode.data.equals(data)) {
  69. return treeNode;
  70. }
  71. if (findData(treeNode.leftData, data) != null) {//递归查找左结点
  72. return findData(treeNode.leftData, data);
  73. }
  74. if (findData(treeNode.rightData, data) != null) {//递归查找右结点
  75. return findData(treeNode.rightData, data);
  76. }
  77. }
  78. return null;
  79. }
  80. /**
  81. * 获取左子树
  82. *
  83. * @param treeNode 树的一个结点
  84. * @return 左子树
  85. */
  86. static TreeDate leftNode(TreeDate treeNode) {
  87. if (treeNode != null) {
  88. return treeNode.leftData;
  89. }
  90. return null;
  91. }
  92. /**
  93. * 获取右子树
  94. *
  95. * @param treeNode 树的一个结点
  96. * @return 右子树
  97. */
  98. static TreeDate rightNode(TreeDate treeNode) {
  99. if (treeNode != null) {
  100. return treeNode.rightData;
  101. }
  102. return null;
  103. }
  104. /**
  105. * 判断空树
  106. *
  107. * @param treeRoot 根结点
  108. * @return true空树,false不是空树
  109. */
  110. static boolean isEmpty(TreeDate treeRoot) {
  111. return treeRoot == null;
  112. }
  113. /**
  114. * 计算二叉树的深度,计算二叉树的最大层数
  115. *
  116. * @param treeNode 从根结点开始
  117. * @return 二叉树的最大层数int
  118. */
  119. static int depth(TreeDate treeNode) {
  120. int depthLeft = 0, depthRight = 0;
  121. if (treeNode == null) {
  122. return 0;
  123. }
  124. if (treeNode.leftData != null) {
  125. depthLeft = depth(treeNode.leftData);
  126. }
  127. if (treeNode.rightData != null) {
  128. depthRight = depth(treeNode.rightData);
  129. }
  130. if (depthLeft > depthRight) {
  131. return depthLeft + 1;
  132. }
  133. return depthRight + 1;
  134. }
  135. /**
  136. * 清空二叉树
  137. * 对于JVM,这个clearTree,是unnecessary的,不必要的
  138. *
  139. * @param treeNode 根结点
  140. */
  141. static void clearTree(TreeDate treeNode) {
  142. if (treeNode != null) {
  143. clearTree(treeNode.leftData);
  144. clearTree(treeNode.rightData);
  145. treeNode = null;//释放内存
  146. }
  147. }
  148. /**
  149. * 显示当前结点的数据
  150. *
  151. * @param treeNode 当前结点
  152. */
  153. static void nodeData(TreeDate treeNode) {
  154. System.out.printf(" %s->", treeNode.data);
  155. }
  156. /**
  157. * 遍历二叉树(按层遍历)
  158. *
  159. * @param treeRoot 根结点
  160. */
  161. static void traverseTreeAccordingToLevel(TreeDate treeRoot) {
  162. int head = 0, tail = 0;
  163. final int MAX_LENGTH = 100;//树的最大结点数
  164. TreeDate p;
  165. TreeDate[] q = new TreeDate[MAX_LENGTH];//定义一个顺序栈
  166. if (treeRoot != null) {//如果队首引用不为空
  167. tail = (tail + 1) % MAX_LENGTH;//计算循环队列队尾序号
  168. q[tail] = treeRoot;//将二叉树根引用进队
  169. }
  170. while (head != tail) {//队列不为空,进行循环
  171. head = (head + 1) % MAX_LENGTH;//计算循环队列的队首序号
  172. p = q[head];//获取队首元素
  173. nodeData(p);//处理队首元素
  174. if (p.leftData != null) {//存在左子树
  175. tail = (tail + 1) % MAX_LENGTH;//计算循环队列的队尾序号
  176. q[tail] = p.leftData;//将左子树引用进队
  177. }
  178. if (p.rightData != null) {
  179. tail = (tail + 1) % MAX_LENGTH;
  180. q[tail] = p.rightData;
  181. }
  182. }
  183. }
  184. /**
  185. * 遍历二叉树(先序遍历算法)
  186. * 先按照中序遍历左子树,再访问根结点,最后按中序遍历右子树
  187. *
  188. * @param treeRoot 根结点
  189. */
  190. static void traverseTreeAccordingToPerorder(TreeDate treeRoot) {
  191. if (treeRoot != null) {
  192. nodeData(treeRoot);//显示结点数据
  193. traverseTreeAccordingToPerorder(treeRoot.leftData);
  194. traverseTreeAccordingToPerorder(treeRoot.rightData);
  195. }
  196. }
  197. /**
  198. * 遍历二叉树(中序遍历算法)
  199. * 先访问根结点,再按照先序遍历左子树,最后按先序遍历右子树
  200. *
  201. * @param treeRoot 根结点
  202. */
  203. static void traverseTreeAccordingToInorder(TreeDate treeRoot) {
  204. if (treeRoot != null) {
  205. traverseTreeAccordingToInorder(treeRoot.leftData);
  206. nodeData(treeRoot);//显示结点数据
  207. traverseTreeAccordingToInorder(treeRoot.rightData);
  208. }
  209. }
  210. /**
  211. * 遍历二叉树(后序遍历算法)
  212. * 先按照后序遍历左子树,再按后序遍历右子树,最后访问根结点
  213. *
  214. * @param treeRoot 根结点
  215. */
  216. static void traverseTreeAccordingToPostorder(TreeDate treeRoot) {
  217. if (treeRoot != null) {
  218. traverseTreeAccordingToPostorder(treeRoot.leftData);
  219. traverseTreeAccordingToPostorder(treeRoot.rightData);
  220. nodeData(treeRoot);//显示结点数据
  221. }
  222. }
  223. }

调用:

  1. TreeDate rootNode = TreeDate.initTree("根结点");
  2. TreeDate.addNode(rootNode, "根结点", 1, "左结点1");
  3. TreeDate.addNode(rootNode, "根结点", 2, "右结点2");
  4. TreeDate.addNode(rootNode, "左结点1", 1, "左结点1.1");
  5. TreeDate.addNode(rootNode, "左结点1", 2, "右结点1.2");
  6. TreeDate.addNode(rootNode, "右结点2", 1, "左结点2.1");
  7. TreeDate.addNode(rootNode, "左结点2.1", 1, "左结点2.1.1");
  8. TreeDate node = TreeDate.findData(rootNode, "右结点2");
  9. if (node != null) {
  10. System.out.printf("找到右结点2,");
  11. TreeDate leftNode = TreeDate.leftNode(node);
  12. TreeDate rightNode = TreeDate.rightNode(node);
  13. if (leftNode != null) {
  14. System.out.printf("其左子树为:%s\t", leftNode.data);
  15. }
  16. if (rightNode != null) {
  17. System.out.printf("右子树为:%s", rightNode.data);
  18. }
  19. System.out.printf("%n");
  20. }
  21. int depth = TreeDate.depth(rootNode);
  22. System.out.printf("树深度:%d%n", depth);
  23. System.out.printf("按层遍历算法:%n");
  24. TreeDate.traverseTreeAccordingToLevel(rootNode);
  25. System.out.printf("%n先序遍历算法:%n");
  26. TreeDate.traverseTreeAccordingToPerorder(rootNode);
  27. System.out.printf("%n中序遍历算法:%n");
  28. TreeDate.traverseTreeAccordingToInorder(rootNode);
  29. System.out.printf("%n后序遍历算法:%n");
  30. TreeDate.traverseTreeAccordingToPostorder(rootNode);
  31. System.out.printf("%n");
  32. boolean isEmpty = TreeDate.isEmpty(rootNode);
  33. System.out.printf("是否是空树:%b%n", isEmpty);
  34. System.out.printf("清空树%n");
  35. TreeDate.clearTree(rootNode);

输出:

  1. 找到右结点2,其左子树为:左结点2.1
  2. 树深度:4
  3. 按层遍历算法:
  4. 根结点-> 左结点1-> 右结点2-> 左结点1.1-> 右结点1.2-> 左结点2.1-> 左结点2.1.1->
  5. 先序遍历算法:
  6. 根结点-> 左结点1-> 左结点1.1-> 右结点1.2-> 右结点2-> 左结点2.1-> 左结点2.1.1->
  7. 中序遍历算法:
  8. 左结点1.1-> 左结点1-> 右结点1.2-> 根结点-> 左结点2.1.1-> 左结点2.1-> 右结点2->
  9. 后序遍历算法:
  10. 左结点1.1-> 右结点1.2-> 左结点1-> 左结点2.1.1-> 左结点2.1-> 右结点2-> 根结点->
  11. 是否是空树:false
  12. 清空树

5.栈结构

常用的数据结构 - 图7

  1. /**
  2. * 定义数据结构中的元素
  3. */
  4. static class DataElement {
  5. String key;
  6. String other_messages;
  7. public DataElement(String key, String other_messages) {
  8. this.key = key;
  9. this.other_messages = other_messages;
  10. }
  11. }
  12. /**
  13. * 定义栈结构
  14. */
  15. static class Stack {
  16. static final int MAX_LENGTH = 10;//当前栈表的最大长度
  17. DataElement[] stackData = new DataElement[MAX_LENGTH];//栈表数据
  18. int top;//栈顶
  19. /**
  20. * 初始化栈
  21. */
  22. static Stack initStack() {
  23. Stack s = new Stack();
  24. s.top = 0;
  25. return s;
  26. }
  27. /**
  28. * 判断栈是否为空
  29. *
  30. * @param stack Stack
  31. * @return true是空栈,false栈不为空
  32. */
  33. static boolean isEmpty(Stack stack) {
  34. return stack.top == 0;
  35. }
  36. /**
  37. * 栈是不是已满
  38. *
  39. * @param stack Stack
  40. * @return true栈已满,false栈未满
  41. */
  42. static boolean isFull(Stack stack) {
  43. return stack.top == MAX_LENGTH;
  44. }
  45. /**
  46. * 清空栈
  47. *
  48. * @param stack Stack
  49. */
  50. static void clear(Stack stack) {
  51. stack.top = 0;
  52. }
  53. /**
  54. * 释放栈所占空间
  55. *
  56. * @param stack Stack
  57. */
  58. static void free(Stack stack) {
  59. if (stack != null) {
  60. stack = null;
  61. }
  62. }
  63. /**
  64. * 入栈
  65. *
  66. * @param stack Stack
  67. * @param element DataElement
  68. * @return 0入栈失败,1入栈成功
  69. */
  70. static int push(Stack stack, DataElement element) {
  71. if (stack.top + 1 > MAX_LENGTH) {
  72. System.out.printf("栈溢出!");
  73. return 0;
  74. }
  75. stack.stackData[++stack.top] = element;//将element入栈,入栈后栈顶(top)+1
  76. return 1;
  77. }
  78. /**
  79. * 出栈
  80. *
  81. * @param stack Stack
  82. * @return 栈顶的DataElement
  83. */
  84. static DataElement pop(Stack stack) {
  85. if (stack.top == 0) {
  86. System.out.print("栈已空!");
  87. return null;
  88. }
  89. return stack.stackData[stack.top--];//将栈顶元素出栈,出栈后栈顶(top)-1
  90. }
  91. /**
  92. * 查看栈数据,由于栈只能操作栈顶数据,所以查看栈的数据只能看栈顶的元素
  93. *
  94. * @param stack Stack
  95. * @return 栈顶的DataElement
  96. */
  97. static DataElement peek(Stack stack) {
  98. if (stack.top == 0) {
  99. System.out.print("栈已空!");
  100. return null;
  101. }
  102. return stack.stackData[stack.top];
  103. }
  104. }

调用:

  1. Stack stack = Stack.initStack();
  2. System.out.printf("栈是不是空栈:%b%n", Stack.isEmpty(stack));
  3. DataElement element = new DataElement("s1", "s1_other");
  4. int push = Stack.push(stack, element);
  5. System.out.printf("入栈结果:%d%n", push);
  6. element = new DataElement("s2", "s2_other");
  7. push = Stack.push(stack, element);
  8. System.out.printf("入栈结果:%d%n", push);
  9. element = new DataElement("s3", "s3_other");
  10. push = Stack.push(stack, element);
  11. System.out.printf("入栈结果:%d%n", push);
  12. System.out.printf("栈是不是空栈:%b%n", Stack.isEmpty(stack));
  13. System.out.printf("栈是不是满栈:%b%n", Stack.isFull(stack));
  14. DataElement dataElement = Stack.peek(stack);
  15. assert dataElement != null;
  16. System.out.printf("查看栈:{%s,%s}%n", dataElement.key, dataElement.other_messages);
  17. dataElement = Stack.pop(stack);
  18. assert dataElement != null;
  19. System.out.printf("出栈:{%s,%s}%n", dataElement.key, dataElement.other_messages);
  20. dataElement = Stack.pop(stack);
  21. assert dataElement != null;
  22. System.out.printf("出栈:{%s,%s}%n", dataElement.key, dataElement.other_messages);
  23. Stack.clear(stack);
  24. System.out.printf("清空栈后栈是不是空栈:%b%n", Stack.isEmpty(stack));
  25. Stack.free(stack);//释放栈空间

输出:

  1. 栈是不是空栈:true
  2. 入栈结果:1
  3. 入栈结果:1
  4. 入栈结果:1
  5. 栈是不是空栈:false
  6. 栈是不是满栈:false
  7. 查看栈:{s3,s3_other}
  8. 出栈:{s3,s3_other}
  9. 出栈:{s2,s2_other}
  10. 清空栈后栈是不是空栈:true

6.图结构

常用的数据结构 - 图8

常用的数据结构 - 图9

常用的数据结构 - 图10

图结构的代码参考 常用算法指南(三)查找算法 :5. 图结构中的查找算法