博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【数据结构java篇】- 链表
阅读量:4146 次
发布时间:2019-05-25

本文共 21669 字,大约阅读时间需要 72 分钟。

文章目录

1 链表(LinkedList)介绍

链表是有序的列表,但是它在内存中是存储如下

在这里插入图片描述
小结上图:

  1. 链表是以节点的方式来存储,是链式存储
  2. 每个节点包含data域,next域:指向下一个节点
  3. 如图:发现链表的各个节点不一定是连续存储
  4. 链表分带头节点的链表没有头节点的链表,根据实际的需求来确定
    单链表(带头结点)逻辑结构示意图如下
    在这里插入图片描述

2 单链表的应用实例

使用带head头的单向链表实现–水浒英雄排行榜管理完成对英雄人物的增删改查操作,注:删除和修改,查找可以考虑学员独立完成,也可带学员完成

  1. 第一种方法在添加英雄时,直接添加到链表的尾部
    思路分析示意图:
    在这里插入图片描述
  2. 第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)思路的分析示意图:
    在这里插入图片描述
  3. 修改节点功能
    思路(1)先找到该节点,通过遍历,(2)temp.name = newHeroNode.name;temp.nickname=newHeroNode.nickname
  4. 删除节点
    思路分析的示意图:
    在这里插入图片描述
  5. 完成的代码演示:
package com.sukang.linkedlist;import java.util.Stack;/** * @description: 单链表模拟水浒英雄案例 * @author: sukang * @date: 2019-12-30 10:43 */public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode heroNode1 = new HeroNode(1, "张三", "zs"); HeroNode heroNode2 = new HeroNode(2, "李四", "ls"); HeroNode heroNode3 = new HeroNode(3, "王五", "ww"); HeroNode heroNode4 = new HeroNode(4, "刘六", "ln"); SingleLinkedList singleLinkedList = new SingleLinkedList(); //增加在尾部 /* singleLinkedList.addHeroNode(heroNode3); singleLinkedList.addHeroNode(heroNode1); singleLinkedList.addHeroNode(heroNode2); singleLinkedList.addHeroNode(heroNode4);*/ //按照顺序添加 singleLinkedList.addHeroNodeByOrder(heroNode3); singleLinkedList.addHeroNodeByOrder(heroNode1); singleLinkedList.addHeroNodeByOrder(heroNode2); singleLinkedList.addHeroNodeByOrder(heroNode4); singleLinkedList.list(); //删除一个节点 singleLinkedList.delHeroNode(1); System.out.println("删除节点之后遍历"); singleLinkedList.list(); //修改一个节点 HeroNode heroNode5 = new HeroNode(2, "马七", "mq"); singleLinkedList.updateHeroNode(heroNode5); System.out.println("修改节点之后遍历"); singleLinkedList.list(); //测试一下单链表中有效结点 System.out.println("单链表中有效结点个数为:" + SingleLinkedListDemo.getEffective(singleLinkedList.getHead())); //查看链表的倒数第1个元素 System.out.println("查看链表的倒数第1个元素为:" + SingleLinkedListDemo.getHeroNode(singleLinkedList.getHead(), 1)); //测试链表反转 System.out.println("反转前链表遍历"); singleLinkedList.list(); SingleLinkedListDemo.linkedReversal(singleLinkedList.getHead()); System.out.println("反转后链表遍历"); singleLinkedList.list(); //测试链表反向打印 System.out.println("反向打印前链表遍历"); singleLinkedList.list(); System.out.println("反向打印链表"); SingleLinkedListDemo.linkedReversalPrint(singleLinkedList.getHead()); } /** * @description: 面试题,求一个链表中有效数据个数 * @param head * @return: int * @author: sukang * @date: 2020/1/2 14:25 */ public static int getEffective(HeroNode head){
//判断是否为空链表 if(head.next == null){
return 0; } int count = 0; HeroNode temp = head.next; while (true){
if(temp == null){
break; } count ++; temp = temp.next; } return count; } /** * @description: 面试题:单链表中倒数第k个节点 * @param head * @param k * @return: * @author: sukang * @date: 2020/1/2 14:36 */ public static HeroNode getHeroNode(HeroNode head, int k){
//空链表 if(head.next == null){
return null; } //获取单链表中有效数据 int count = getEffective(head); if(!(k > 0 && k < count)){
throw new RuntimeException("k传值超过有效范围"); } HeroNode temp = head.next; //从头遍历单链表遍历到(count - k),也就是倒数第k个节点 for (int i = 0; i < count - k ; i++) {
temp = temp.next; } return temp; } /** * @description: 面试题链表反转 * @param * @return: void * @author: sukang * @date: 2020/1/3 8:37 */ public static void linkedReversal(HeroNode head){
//思路:首先申明一个新链表的头节点,然后遍历旧链表,按顺序插入新链表头节点之后 if(head.next == null || head.next.next == null){
System.out.println("链表为空或则链表的有效长度为1,不需要进行反转"); return; } //声明一个辅助节点,遍历单链表来用 HeroNode temp = head.next; //声明一个当前节点指向temp节点 HeroNode cur = null; //声明新链表的头节点 HeroNode newHead = new HeroNode(0,"",""); while (true){
//链表遍历到了最后一个节点 if(temp == null){
break; } cur = temp; //将当前节点指向单链表的辅助节点 temp = temp.next; //将辅助节点后移一个节点 cur.next = newHead.next;//然后将当前节点的后一个节点指向新链表的后一个节点 newHead.next = cur;//新链表的头结点的后一个节点指向当前节点 } head.next = newHead.next; } /** * @description: 面试题:单链表反向打印 * @param head * @return: void * @author: sukang * @date: 2020/1/3 9:38 */ public static void linkedReversalPrint(HeroNode head){
//思路:将单链表压入栈中,然后从栈中取出打印,利用了栈的新进后出的特性 if(head.next == null){
return; } Stack
stack = new Stack<>(); HeroNode temp = head; while (true){
if(temp.next == null){
break; } stack.add(temp.next); temp = temp.next; } while (stack.size() > 0){
System.out.println(stack.pop()); } }}//链表类class SingleLinkedList{
//声明一个头结点 private HeroNode head = new HeroNode(0,"","") ; /** * @description: 返回头结点 * @param * @return: * @author: sukang * @date: 2020/1/2 14:28 */ public HeroNode getHead(){
return head; } /** * @description: 从链表尾处添加节点 * @param heroNode * @return: void * @author: sukang * @date: 2019/12/30 14:18 */ public void addHeroNode(HeroNode heroNode){
/* 思路:用一个辅助节点遍历链表,找到节点next为空及最后一个节点, 将其next赋给新节点*/ //申明一个过渡节点,因为head节点不能后移 HeroNode temp = head; while (true){
//如果下一个节点为空的话,那么就在这个节点上添加新节点 if(temp.next == null){
break; } //如果没有到最后一个节点,那么节点往后移 temp = temp.next; } //把最后一个节点的下一个节点赋给新节点 temp.next = heroNode; } /** * @description: 按照节点的顺序添加节点 * @param heroNode * @return: void * @author: sukang * @date: 2019/12/30 14:31 */ public void addHeroNodeByOrder(HeroNode heroNode){
/* 思路:同样因为head节点不能移动,所以我们也是先声明一个辅助节点temp, 那么辅助节点temp就应该为插入节点的上一个节点,另外如果链表中存在相同 大小的节点,那么将插入失败*/ //声明一个辅助节点 HeroNode temp = head; while (true){
//链表已经遍历到最后 if(temp.next == null){
break; } if(temp.next.id == heroNode.id){
System.out.printf("编号为%d的节点已经存在,不能添加", heroNode.id); return; }else if(temp.next.id > heroNode.id){
break; } temp = temp.next; } heroNode.next = temp.next; temp.next = heroNode; } /** * @description: 删除节点 * @param id * @return: void * @author: sukang * @date: 2019/12/30 15:19 */ public void delHeroNode(int id){
/*思路:同样因为head节点不能移动,所以我们也是先声明一个辅助节点temp, 那么如果辅助节点的下一个节点的id存在,那么就删除这个节点*/ HeroNode temp = head; boolean flag = false;//是否找到删除节点标志 while (true){
//链表已经遍历到最后 if(temp.next == null){
break; } if(temp.next.id == id){
flag = true; break; } temp = temp.next; } if(flag){
temp.next = temp.next.next; }else{
System.out.printf("要删除的节点%d,不存在", id); } } /** * @description: 更新节点 * @param heroNode * @return: void * @author: sukang * @date: 2019/12/30 16:04 */ public void updateHeroNode(HeroNode heroNode){
//思路:同样是通过辅助节点temp遍历找到和更新节点相同id的节点,然后进行更新 //声明辅助节点 HeroNode temp = head; boolean flag = false; //判断是否找到更新的节点,默认为false while (true){
if(temp == null){
break; } if(temp.next.id == heroNode.id){
flag = true; break; } temp = temp.next; } if(flag){
temp.next.name = heroNode.name; temp.next.nickName = heroNode.nickName; }else{
System.out.printf("没有找到编号为 %d 的节点, 不能更新", heroNode.id); } } /** * @description: 遍历链表 * @param * @return: void * @author: sukang * @date: 2019/12/30 16:15 */ public void list(){
HeroNode temp = head; if(temp.next == null){
System.out.println("链表为空!"); return; } while (true){
if(temp.next == null){
break; } System.out.println(temp.next); temp = temp.next; } }}//链表节点class HeroNode{
public int id; //唯一标志 public String name; //名字 public String nickName; //昵称 HeroNode next; //下一个节点 public HeroNode(int id, String name, String nickName) {
this.id = id; this.name = name; this.nickName = nickName; } @Override public String toString() {
return "HeroNode{id: "+ id+ ",name: "+ name +", nickName: "+ nickName +"}"; }}

3 单链表面试题(新浪、百度、腾讯)

单链表的常见面试题有如下:

  1. 求单链表中有效节点的个数
    代码如下:
//方法:获取到单链表的节点的个数(如果是带头结点的链表,需求不统计头节点)/** *  * @param head 链表的头节点 * @return 返回的就是有效节点的个数 */public static int getLength(HeroNode head) {
if(head.next == null) {
//空链表 return 0; } int length = 0; //定义一个辅助的变量, 这里我们没有统计头节点 HeroNode cur = head.next; while(cur != null) {
length++; cur = cur.next; //遍历 } return length;}
  1. 查找单链表中的倒数第k个结点【新浪面试题】
    代码演示:
//查找单链表中的倒数第k个结点 【新浪面试题】//思路//1. 编写一个方法,接收head节点,同时接收一个index //2. index 表示是倒数第index个节点//3. 先把链表从头到尾遍历,得到链表的总的长度 getLength//4. 得到size 后,我们从链表的第一个开始遍历 (size-index)个,就可以得到//5. 如果找到了,则返回该节点,否则返回nulllpublic static HeroNode findLastIndexNode(HeroNode head, int index) {
//判断如果链表为空,返回null if(head.next == null) {
return null;//没有找到 } //第一个遍历得到链表的长度(节点个数) int size = getLength(head); //第二次遍历 size-index 位置,就是我们倒数的第K个节点 //先做一个index的校验 if(index <=0 || index > size) {
return null; } //定义给辅助变量, for 循环定位到倒数的index HeroNode cur = head.next; //3 // 3 - 1 = 2 for(int i =0; i< size - index; i++) {
cur = cur.next; } return cur; }
  1. 单链表的反转【腾讯面试题,有点难度】
    思路分析图解
    在这里插入图片描述
    在这里插入图片描述
    代码实现
//将单链表反转public static void reversetList(HeroNode head) {
//如果当前链表为空,或者只有一个节点,无需反转,直接返回 if(head.next == null || head.next.next == null) {
return ; } //定义一个辅助的指针(变量),帮助我们遍历原来的链表 HeroNode cur = head.next; HeroNode next = null;// 指向当前节点[cur]的下一个节点 HeroNode reverseHead = new HeroNode(0, "", ""); //遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead 的最前端 //动脑筋 while(cur != null) {
next = cur.next;//先暂时保存当前节点的下一个节点,因为后面需要使用 cur.next = reverseHead.next;//将cur的下一个节点指向新的链表的最前端 reverseHead.next = cur; //将cur 连接到新的链表上 cur = next;//让cur后移 } //将head.next 指向 reverseHead.next , 实现单链表的反转 head.next = reverseHead.next;}
  1. 从尾到头打印单链表【百度,要求方式1:反向遍历。方式2:Stack栈】
    思路分析图解
    在这里插入图片描述
    代码实现
    写了一个小程序,测试Stack的使用
import java.util.Stack;//演示栈Stack的基本使用public class TestStack {
public static void main(String[] args) {
Stack
stack = new Stack(); // 入栈 stack.add("jack"); stack.add("tom"); stack.add("smith"); // 出栈 // smith, tom , jack while (stack.size() > 0) {
System.out.println(stack.pop());//pop就是将栈顶的数据取出 } }}

单链表的逆序打印代码:

//方式2://可以利用栈这个数据结构,将各个节点压入到栈中,然后利用栈的先进后出的特点,就实现了逆序打印的效果public static void reversePrint(HeroNode head) {
if(head.next == null) {
return;//空链表,不能打印 } //创建要给一个栈,将各个节点压入栈 Stack
stack = new Stack
(); HeroNode cur = head.next; //将链表的所有节点压入栈 while(cur != null) {
stack.push(cur); cur = cur.next; //cur后移,这样就可以压入下一个节点 } //将栈中的节点进行打印,pop 出栈 while (stack.size() > 0) {
System.out.println(stack.pop()); //stack的特点是先进后出 }}

5 双向链表应用实例

5.1 双向链表的操作分析和实现

使用带head头的双向链表实现 – 水浒英雄排行榜

管理单向链表的缺点分析:

  1. 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。
  2. 单向链表不能自我删除,需要靠辅助节点,而双向链表,则可以自我删除,所以前面我们单链表删除时节点,总是找到temp,temp是待删除节点的前一个节点(认真体会).
  3. 分析了双向链表如何完成遍历,添加,修改和删除的思路
    在这里插入图片描述
    对上图的说明:
    分析双向链表的遍历,添加,修改,删除的操作思路===》代码实现
  4. 遍历方和单链表一样,只是可以向前,也可以向后查找
  5. 添加(默认添加到双向链表的最后)
    (1) 先找到双向链表的最后这个节点
    (2) temp.next=newHeroNode
    (3) newHeroNode.pre=temp;
  6. 修改思路和原来的单向链表一样.
    4)删除
    (1) 因为是双向链表,因此,我们可以实现自我删除某个节点
    (2) 直接找到要删除的这个节点,比如temp
    (3) temp.pre.next=temp.next
    (4) temp.next.pre=temp.pre;

双向链表的代码实现

package com.sukang.linkedlist;/** * @description: * @author: sukang * @date: 2020-01-03 10:43 */public class DoubleLinkedListDemo {
public static void main(String[] args) {
HeroNode2 heroNode1 = new HeroNode2(1, "张三", "zs"); HeroNode2 heroNode2 = new HeroNode2(2, "李四", "ls"); HeroNode2 heroNode3 = new HeroNode2(3, "王五", "ww"); HeroNode2 heroNode4 = new HeroNode2(4, "刘六", "ln"); DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); //增加在尾部 /* doubleLinkedList.addHeroNode(heroNode3); doubleLinkedList.addHeroNode(heroNode1); doubleLinkedList.addHeroNode(heroNode2); doubleLinkedList.addHeroNode(heroNode4); doubleLinkedList.list();*/ //按照顺序添加 doubleLinkedList.addHeroNodeByOrder(heroNode3); doubleLinkedList.addHeroNodeByOrder(heroNode1); doubleLinkedList.addHeroNodeByOrder(heroNode2); doubleLinkedList.addHeroNodeByOrder(heroNode4); doubleLinkedList.list(); //删除一个节点 doubleLinkedList.delHeroNode(1); System.out.println("删除节点之后遍历"); doubleLinkedList.list(); //修改一个节点 HeroNode heroNode5 = new HeroNode(2, "马七", "mq"); doubleLinkedList.updateHeroNode(heroNode5); System.out.println("修改节点之后遍历"); doubleLinkedList.list(); }}//双链表类链表类class DoubleLinkedList{
//声明一个头结点 private HeroNode2 head = new HeroNode2(0,"",""); /** * @description: 返回头结点 * @param * @return: * @author: sukang * @date: 2020/1/2 14:28 */ public HeroNode2 getHead(){
return head; } /** * @description: 从链表尾处添加节点 * @param heroNode * @return: void * @author: sukang * @date: 2019/12/30 14:18 */ public void addHeroNode(HeroNode2 heroNode){
/* 思路:用一个辅助节点遍历链表,找到节点next为空及最后一个节点, 将其next赋给新节点*/ //申明一个过渡节点,因为head节点不能后移 HeroNode2 temp = head; while (true){
//如果下一个节点为空的话,那么就在这个节点上添加新节点 if(temp.next == null){
break; } //如果没有到最后一个节点,那么节点往后移 temp = temp.next; } //把最后一个节点的下一个节点赋给新节点 temp.next = heroNode; heroNode.pre = temp; } /** * @description: 按照节点的顺序添加节点 * @param heroNode * @return: void * @author: sukang * @date: 2019/12/30 14:31 */ public void addHeroNodeByOrder(HeroNode2 heroNode){
/* 思路:同样因为head节点不能移动,所以我们也是先声明一个辅助节点temp, 那么辅助节点temp就应该为插入节点的上一个节点,另外如果链表中存在相同 大小的节点,那么将插入失败*/ //声明一个辅助节点 HeroNode2 temp = head; while (true){
//链表已经遍历到最后 if(temp.next == null){
break; } if(temp.next.id == heroNode.id){
System.out.printf("编号为%d的节点已经存在,不能添加", heroNode.id); return; }else if(temp.next.id > heroNode.id){
break; } temp = temp.next; } heroNode.next = temp.next; temp.next = heroNode; if(heroNode.next != null){
heroNode.next.pre = heroNode; } heroNode.pre = temp; } /** * @description: 删除节点 * @param id * @return: void * @author: sukang * @date: 2019/12/30 15:19 */ public void delHeroNode(int id){
/*思路:同样因为head节点不能移动,所以我们也是先声明一个辅助节点temp, 那么如果辅助节点的下一个节点的id存在,那么就删除这个节点*/ HeroNode2 temp = head.next; boolean flag = false;//是否找到删除节点标志 while (true){
//链表已经遍历到最后 if(temp.next == null){
break; } if(temp.id == id){
flag = true; break; } temp = temp.next; } if(flag){
temp.pre.next = temp.next; temp.next = temp.pre; }else{
System.out.printf("要删除的节点%d,不存在", id); } } /** * @description: 更新节点 * @param heroNode * @return: void * @author: sukang * @date: 2019/12/30 16:04 */ public void updateHeroNode(HeroNode heroNode){
//思路:同样是通过辅助节点temp遍历找到和更新节点相同id的节点,然后进行更新 //声明辅助节点 HeroNode2 temp = head; boolean flag = false; //判断是否找到更新的节点,默认为false while (true){
if(temp == null){
break; } if(temp.next.id == heroNode.id){
flag = true; break; } temp = temp.next; } if(flag){
temp.next.name = heroNode.name; if(temp.next != null){
temp.next.nickName = heroNode.nickName; } }else{
System.out.printf("没有找到编号为 %d 的节点, 不能更新", heroNode.id); } } /** * @description: 遍历链表 * @param * @return: void * @author: sukang * @date: 2019/12/30 16:15 */ public void list(){
HeroNode2 temp = head; if(temp.next == null){
System.out.println("链表为空!"); return; } while (true){
if(temp.next == null){
break; } System.out.println(temp.next); temp = temp.next; } }}//双向链表节点class HeroNode2{
public int id; //唯一标志 public String name; //名字 public String nickName; //昵称 HeroNode2 next; //下一个节点 HeroNode2 pre; //上一个节点 public HeroNode2(int id, String name, String nickName) {
this.id = id; this.name = name; this.nickName = nickName; } @Override public String toString() {
return "HeroNode2{id: "+ id+ ",name: "+ name +", nickName: "+ nickName +"}"; }}

6 单向环形链表应用场景

Josephu(约瑟夫、约瑟夫环)问题

Josephu问题为:设编号为1,2,…n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
提示:用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
在这里插入图片描述

6.1 单向环形链表介绍

在这里插入图片描述

6.2 Josephu问题

约瑟夫问题的示意图

在这里插入图片描述
Josephu问题
Josephu问题为:设编号为1,2,…n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

提示

用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。

约瑟夫问题-创建环形链表的思路图解

在这里插入图片描述
约瑟夫问题-小孩出圈的思路分析图
在这里插入图片描述
Josephu问题的代码实现

package com.sukang.linkedlist;/** * @description: 约瑟夫问题(丢手帕) * @author: sukang * @date: 2020-01-04 13:48 */public class Josephu {
public static void main(String[] args) {
CircleLinkedList circleLinkedList = new CircleLinkedList(); circleLinkedList.create(5); circleLinkedList.list(); circleLinkedList.outCircle(1,2,5); }}//环形单链表class CircleLinkedList{
//申明一个开始节点 Boy first = null; /** * @description: 根据传递的数量创建环形单链表 * @param num * @return: void * @author: sukang * @date: 2020/1/4 14:41 */ public void create(int num){
if(num < 1){
System.out.println("数量小于1,没法创建"); return; } Boy temp = null; for (int i = 0; i < num; i++) {
Boy boy = new Boy(i+1); if(i == 0){
first = boy; temp = first; }else{
temp.setNext(boy); temp = boy; } } temp.setNext(first); } /** * @description: 遍历环形单链表 * @param * @return: void * @author: sukang * @date: 2020/1/4 14:40 */ public void list(){
if(first == null){
System.out.println("环形单链表为空"); return; } Boy temp = first; while (true){
System.out.println(temp); if(temp.getNext() == first){
System.out.println("遍历到最后了"); break; } temp = temp.getNext(); } } /** * @description: * @param startNo * 表示从第几个小孩开始数 * @param countNum * 表示数了几个数字 * @param nums * 表示圈内一共有几个 * @return: void * @author: sukang * @date: 2020/1/4 15:32 */ public void outCircle(int startNo, int countNum, int nums){
if(first == null || startNo < 1 || startNo > nums){
System.out.println("传入的数据有问题"); return; } //声明一个辅助节点,让其指向环形单链表的最后一个孩子节点 Boy temp = first; while (true){
if(temp.getNext() == first){
break; } temp = temp.getNext(); } //从第startNo元素开始数 for (int i = 0; i < startNo -1 ; i++) {
temp = temp.getNext(); first = first.getNext(); } while (true){
if(temp == first){
break; } for (int i = 0; i < countNum -1 ; i++) {
temp = temp.getNext(); first = first.getNext(); } System.out.println(first); temp.setNext(first.getNext()); first = first.getNext(); } System.out.println(first); }}//孩子节点class Boy{
private int index; private Boy next; public Boy(int index) {
this.index = index; } public int getIndex() {
return index; } public void setIndex(int index) {
this.index = index; } public Boy getNext() {
return next; } public void setNext(Boy next) {
this.next = next; } @Override public String toString() {
return "Boy[index:"+index+"]"; }}

转载地址:http://eanti.baihongyu.com/

你可能感兴趣的文章
九度:题目1027:欧拉回路
查看>>
九度:题目1012:畅通工程
查看>>
九度:题目1017:还是畅通工程
查看>>
九度:题目1034:寻找大富翁
查看>>
第六章 背包问题——01背包
查看>>
51nod 分类
查看>>
1136 . 欧拉函数
查看>>
面试题:强制类型转换
查看>>
Decorator模式
查看>>
Template模式
查看>>
Observer模式
查看>>
高性能服务器设计
查看>>
性能扩展问题要趁早
查看>>
MySQL-数据库、数据表结构操作(SQL)
查看>>
OpenLDAP for Windows 安装手册(2.4.26版)
查看>>
图文介绍openLDAP在windows上的安装配置
查看>>
Pentaho BI开源报表系统
查看>>
Pentaho 开发: 在eclipse中构建Pentaho BI Server工程
查看>>
JSP的内置对象及方法
查看>>
android中SharedPreferences的简单例子
查看>>