tbwshc

tbw

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  95 Posts :: 8 Stories :: 3 Comments :: 0 Trackbacks

常用链接

留言簿(4)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

#

什么是约瑟夫环呢?
  约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
  我们用程序说话,实现约瑟夫环:

import java.util.Scanner;
public class Josephus{
 private static class Node{
  public int no;//编号
  public Node next;//下一个节点

 public Node(int no){
  this. no=no
 }
 }
public static void main(String[]args)  {
      SCanner scanner=new Scanner(System.in);
      System.out.print('out. print("请输入总人数:");
      int totalNum=scanner. nextInt);
      System.out.print("请输入报数的大小:");
      int cycleNum=canner. nextInt();
      Node heade==new Node(1);
      Node pointer=heade;
      for(int i=2;i<=totalNum;i++){
           pointer.next=new Node(i);
           pointer=pointer.next;
 }


pointer=pointer. next;
pointer. next=header;
//初始化环形链表结束
System.out.p:Intln("out. println("以下是出列tb的顺序:‘)‘
while (pointer!,pointer. next)  {
for (int i=1;:<cycleNum; i++)
    pointer=pointer. next;
    }
    System.out.prlntln(pointer.next.no)out. println(pointer. next.no);
    pointer. next=pointer. next. next;
}
System. out. println(pointer.next.no);
}
}



posted @ 2012-09-26 12:04 tbwshc 阅读(946) | 评论 (-1)编辑 收藏

  在JAVA平台,实现异步调用的角色有如下三个角色:调用者 提货单 真实数据一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单.然后在过一断时间后凭提货单来获取真正的数据.去蛋糕店买蛋糕,不需要等蛋糕做出来(假设现做要很长时间),只需要领个提货单就可以了(去干别的事情),等到蛋糕做好了,再拿提货单取蛋糕就可以了。public class Main { public static void main(String[] args) {

  System.out.println("main BEGIN");

  Host host = new Host();

  Data data1 = host.request(10, 'A');

  Data data2 = host.request(20, 'B');

  Data data3 = host.request(30, 'C');

  System.out.println("main otherJob BEGIN");

  try {

  Thread.sleep(200);

  } catch (InterruptedException e) {

  }

  System.out.println("main otherJob END");

  System.out.println("data1 = " + data1.getContent());

  System.out.println("data2 = " + data2.getContent());

  System.out.println("data3 = " + data3.getContent());

  System.out.println("main END");

  }

  }

  这里的main类就相当于“顾客”,host就相当于“蛋糕店”,顾客向“蛋糕店”定蛋糕就相当于“发请求request”,返回的数据data是FutureData的实例,就相当于提货单,而不是真正的“蛋糕”。在过一段时间后(sleep一段时间后),调用data1.getContent(),也就是tb拿提货单获取执行结果。

  下面来看一下,顾客定蛋糕后,蛋糕店做了什么:

  public class Host {

  public Data request(final int count, final char c) {

  System.out.println("request(" + count + ", " + c + ") BEGIN");

  // (1) 建立FutureData的实体

  final FutureData future = new FutureData();

  // (2) 为了建立RealData的实体,启动新的线程

  new Thread() {

  public void run() {

  //在匿名内部类中使用count、future、c。

  RealData realdata = new RealData(count, c);

  future.setRealData(realdata);

  }

  }.start();

  System.out.println("request(" + count + ", " + c + ") END");

  // (3) 取回FutureData实体,作为传回值

  return future;

  }

  }

  host("蛋糕店")在接到请求后,先生成了“提货单”FutureData的实例future,然后命令“蛋糕师傅”RealData去做蛋糕,realdata相当于起个线程去做蛋糕了。然后host返回给顾客的仅仅是“提货单”future,而不是蛋糕。当蛋糕做好后,蛋糕师傅才能给对应的“提货单”蛋糕,也就是future.setRealData(realdata)。

下面来看看蛋糕师傅是怎么做蛋糕的:

  建立一个字符串,包含count个c字符,为了表现出犯法需要花费一些时间,使用了sleep。

  public class RealData implements Data { private final String content;

  public RealData(int count, char c) {

  System.out.println("making RealData(" + count + ", " + c + ") BEGIN");

  char[] buffer = new char[count];

  for (int i = 0; i < count; i++) {

  buffer[i] = c;

  try {

  Thread.sleep(1000);

  } catch (InterruptedException e) {

  }

  }

  System.out.println("making RealData(" + count + ", " + c + ") END");

  this.content = new String(buffer);

  }

  public String getContent() {

  return content;

  }

  }

  现在来看看“提货单”future是怎么与蛋糕"content"对应的:

  public class FutureData implements Data { private RealData realdata = null;

  private boolean ready = false;

  public synchronized void setRealData(RealData realdata) {

  if (ready) {

  return; // 防止setRealData被调用两次以上。

  }

  this.realdata = realdata;

  this.ready = true;

  notifyAll();

  }

  public synchronized String getContent() {

  while (!ready) {

  try {

  wait();

  } catch (InterruptedException e) {

  }

  }

  return realdata.getContent();

  }

  }

  顾客做完自己的事情后,会拿着自己的“提货单”来取蛋糕:

  System.out.println("data1 = " + data1.getContent());

  这时候如果蛋糕没做好,就只好等了:

  while (!ready) { try {

  wait();

  } catch (InterruptedException e) {

  }

  //等做好后才能取到

  return realdata.getContent();

  程序分析

  对于每个请求,host都会生成一个线程,这个线程负责生成顾客需要的“蛋糕”。在等待一段时间以后,如果蛋糕还没有做好,顾客还必须等待。直到“蛋糕被做好”,也就是

  future.setRealData(realdata); 执行以后,顾客才能拿走蛋糕。

  每个线程只是专门负责制作特定顾客所需要的“蛋糕”。也就是顾客A对应着蛋糕师傅A,tb顾客B对应着蛋糕师傅B。即使顾客B的蛋糕被先做好了,顾客A也只能等待蛋糕师傅A把蛋糕做好。换句话说,顾客之间没有竞争关系。

  类FutureData的两个方法被设置为synchronized,实际上蛋糕师傅A与顾客A之间的互斥关系,也就是顾客A必须等待蛋糕师傅A把蛋糕做好后,才能拿走,而与蛋糕师傅B是否做好了蛋糕没有关系。

 

posted @ 2012-09-26 11:55 tbwshc 阅读(684) | 评论 (0)编辑 收藏

如果我们使用Oracle的oerr程序看看ORA-04068的定义,我们会得到下面的信息:
  $oerr ora 04068
  04068, 00000, "existing state of packages has been discarded"
  // *Cause: One of errors 4060 - 4067 when attempt to execute a stored procedure.
  // *Action: Try again after proper re-initialization of any
  // application's state.

  这个错误显示执行包的现有状态被另一个会话的一个动作无效化了。这个“状态”涉及包在规范或体中定义的任何全局变量(包括常量)。引起这个错误的动作一般是(但不局限于此)在得到了发生错误的会话所使用的连接之后包的重新编译。Oracle 建议的动作是重新初始化应用程序状态以调整包的新状态后重新尝试。

 

出现原因:

  一般是系统运行过程中,对Package重新编译,tbw会导致系统对于这个Session的Package失效。

解决办法:

  重启业务系统,重新获得Oracle Session。

避免方案:

  不要在系统运行过程中,对Package重新编译。



传说中的04068啊,这个错误在开发中比较容易见到,简单说,就是你与数据库建立链接后,这个package被编译过,然后你再去调用这个包,会报这个错误,但只会报一次。
所以比较常见的做法,就是程序catch捕获异常后,判断错误是否是04068,如果是,重新调用一次,第二次调用就没问题了。
posted @ 2012-09-24 15:47 tbwshc 阅读(1174) | 评论 (0)编辑 收藏

C语言宏定义技巧(常用宏定义)
   
    写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等。下面列举一些成熟软件中常用得宏定义……
   
    CODE:
   
    1,防止一个头文件被重复包含
   
    #ifndef COMDEF_H
   
    #define COMDEF_H
   
    //头文件内容
   
    #endif
   
    2,重新定义一些类型,防止由于各种平台和编译器的不同tb ,而产生的类型字节数差异,方便移植。
   
    typedef unsigned char     boolean;   /* Boolean value type. */
   
    typedef unsigned long int uint32;     /* Unsigned 32 bit value */
   
    typedef unsigned short   uint16;     /* Unsigned 16 bit value */
   
    typedef unsigned char     uint8;     /* Unsigned 8 bit value */
   
    typedef signed long int   int32;     /* Signed 32 bit value */
   
    typedef signed short     int16;     /* Signed 16 bit value */
   
    typedef signed char     int8;     /* Signed 8 bit value */
   
    //下面的不建议使用
   
    typedef unsigned char   byte;       /* Unsigned 8 bit value type. */
   
    typedef unsigned short   word;       /* Unsinged 16 bit value type. */
   
    typedef unsigned long   dword;     /* Unsigned 32 bit value type. */
   
    typedef unsigned char   uint1;     /* Unsigned 8 bit value type. */
   
    typedef unsigned short   uint2;     /* Unsigned 16 bit value type. */
   
    typedef unsigned long   uint4;     /* Unsigned 32 bit value type. */
   
    typedef signed char     int1;       /* Signed 8 bit value type. */
   
    typedef signed short     int2;       /* Signed 16 bit value type. */
   
    typedef long int       int4;       /* Signed 32 bit value type. */
   
    typedef signed long     sint31;     /* Signed 32 bit value */
   
    typedef signed short     sint15;     /* Signed 16 bit value */
   
    typedef signed char     sint7;     /* Signed 8 bit value */
   
    3,得到指定地址上的一个字节或字
   
    #define MEM_B( x ) ( *( (byte *) (x) ) )
   
    #define MEM_W( x ) ( *( (word *) (x) ) )
   
    4,求最大值和最小值
   
    #define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
   
    #define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
   
    5,得到一个field在结构体(struct)中的偏移量
   
    #define FPOS( type, field ) \
   
    /*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */
   
    6,得到一个结构体中field所占用的字节数
   
    #define FSIZ( type, field ) sizeof( ((type *) 0)->field )
   
    7,按照LSB格式把两个字节转化为一个Word
   
    #define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )
   
    8,按照LSB格式把一个Word转化为两个字节
   
    #define FLOPW( ray, val ) \
   
    (ray)[0] = ((val) / 256); \
   
    (ray)[1] = ((val) & 0xFF)
   
    9,得到一个变量的地址(word宽度)
   
    #define B_PTR( var ) ( (byte *) (void *) &(var) )
   
    #define W_PTR( var ) ( (word *) (void *) &(var) )
   
    10,得到一个字的高位和低位字节
   
    #define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))
   
    #define WORD_HI(xxx) ((byte) ((word)(xxx) 》 8))
   
    11,返回一个比X大的最接近的8的倍数
   
    #define RND8( x )     ((((x) + 7) / 8 ) * 8 )
   
    12,将一个字母转换为大写
   
    #define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z‘) ? ((c) - 0x20) : (c) )
   
    13,判断字符是不是10进值的数字
   
    #define DECCHK( c ) ((c) >= '0' && (c) <= '9’)
   
    14,判断字符是不是16进值的数字
   
    #define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9‘) ||\
   
    ((c) >= 'A' && (c) <= 'F’) ||\
   
    ((c) >= 'a' && (c) <= 'f‘) )
   
    15,防止溢出的一个方法
   
    #define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
   
    16,返回数组元素的个数
   
    #define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
   
    17,返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)
   
    #define MOD_BY_POWER_OF_TWO( val, mod_by ) \
   
    ( (dword)(val) & (dword)((mod_by)-1) )
   
    18,对于IO空间映射在存储空间的结构,输入输出处理
   
    #define inp(port)       (*((volatile byte *) (port)))
   
    #define inpw(port)     (*((volatile word *) (port)))
   
    #define inpdw(port)     (*((volatile dword *)(port)))
   
    #define outp(port, val)   (*((volatile byte *) (port)) = ((byte) (val)))
   
    #define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))
   
    #define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
   
    [2005-9-9添加]
   
    19,使用一些宏跟踪调试
   
    A N S I标准说明了五个预定义的宏名。它们是:
   
    _ L I N E _
   
    _ F I L E _
   
    _ D A T E _
   
    _ T I M E _
   
    _ S T D C _
如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序
   
    也许还提供其它预定义的宏名。
   
    _ L I N E _及_ F I L E _宏指令在有关# l i n e的部分中已讨论,这里讨论其余的宏名。
   
    _ D AT E _宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。
   
    源代码翻译到目标代码的时间作为串包含在_ T I M E _中。串形式为时:分:秒。
   
    如果实现是标准的,则宏_ S T D C _含有十进制常量1.如果它含有任何其它数,则实现是
   
    非标准的。
   
    可以定义宏,例如:
   
    当定义了_DEBUG,输出数据信息和所在文件所在行
   
    #ifdef _DEBUG
   
    #define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
   
    #else
   
    #define DEBUGMSG(msg,date)
   
    #endif
   
    20,宏定义防止使用是错误
   
    用小括号包含。
   
    例如:#define ADD(a,b) (a+b)
   
    用do{}while(0)语句包含多语句防止错误
   
    例如:#difne DO(a,b) a+b;\
   
    a++;
   
    应用时:if(…)
   
    DO(a,b); //产生错误
   
    else
   
    解决方法: #difne DO(a,b) do{a+b;\
   
    a++;}while(0)
   
    宏中“#”和“##”的用法
   
    一、一般用法
   
    我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起。
   
    用法:
   
    #include<cstdio>
   
    #include<climits>
   
    using namespace std;
   
    #define STR(s)   #s
   
    #define CONS(a,b) int(a##e##b)
   
    int main()
   
    {
   
    printf(STR(vck));       // 输出字符串“vck”
   
    printf(“%d\n”, CONS(2,3)); // 2e3 输出:2000
   
    return 0;
   
    }
   
    二、当宏参数是另一个宏的时候
   
    需要注意的是凡宏定义里有用'#’或‘##’的地方宏参数是不会再展开。
   
    1, 非‘#’和‘##’的情况
   
    #define TOW     (2)
   
    #define MUL(a,b) (a*b)
   
    printf(“%d*%d=%d\n”, TOW, TOW, MUL(TOW,TOW));
   
    这行的宏会被展开为:
   
    printf(“%d*%d=%d\n”, (2), (2), ((2)*(2)));
   
    MUL里的参数TOW会被展开为(2)。
   
    2, 当有‘#’或‘##’的时候
   
    #define A       (2)
   
    #define STR(s)   #s
   
    #define CONS(a,b) int(a##e##b)
   
    printf(“int max: %s\n”, STR(INT_MAX));   // INT_MAX #include<climits>
   
    这行会被展开为:
   
    printf(“int max: %s\n”, “INT_MAX”);
   
    printf(“%s\n”, CONS(A, A));           // compile error
   
    这一行则是:
   
    printf(“%s\n”, int(AeA));
   
    INT_MAX和A都不会再被展开, 然而解决这个问题的方法很简单。 加多一层中间转换宏。
   
    加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数。
   
    #define A       (2)
   
    #define _STR(s)   #s
   
    #define STR(s)     _STR(s)       // 转换宏
   
    #define _CONS(a,b) int(a##e##b)
   
    #define CONS(a,b)   _CONS(a,b)     // 转换宏
   
    printf(“int max: %s\n”, STR(INT_MAX));       // INT_MAX,int型的最大值,为一个变量 #include<climits>
   
    输出为: int max: 0x7fffffff
   
    STR(INT_MAX) --> _STR(0x7fffffff) 然后再转换成字符串;
   
    printf(“%d\n”, CONS(A, A));
   
    输出为:200
   
    CONS(A, A) --> _CONS((2), (2)) --> int((2)e(2))
   
    三、‘#’和‘##’的一些应用特例
   
    1、合并匿名变量名
   
    #define ___ANONYMOUS1(type, var, line) type var##line
   
    #define __ANONYMOUS0(type, line) ___ANONYMOUS1(type, _anonymous, line)
   
    #define ANONYMOUS(type) __ANONYMOUS0(type, __LINE__)
   
    例:ANONYMOUS(static int); 即: static int _anonymous70; 70表示该行行号;
   
    第一层:ANONYMOUS(static int); --> __ANONYMOUS0(static int, __LINE__);
   
    第二层:                 --> ___ANONYMOUS1(static int, _anonymous, 70);
   
    第三层:                 --> static int _anonymous70;
   
    即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;
   
    2、填充结构
   
    #define FILL(a)   {a, #a}
   
    enum IDD{OPEN, CLOSE};
   
    typedef struct MSG{
   
    IDD id;
   
    const char * msg;
   
    }MSG;
   
    MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};
   
    相当于:
   
    MSG _msg[] = {{OPEN, “OPEN”},
   
    {CLOSE, “CLOSE”}};
   
    3、记录文件名
   
    #define _GET_FILE_NAME(f)   #f
   
    #define GET_FILE_NAME(f)   _GET_FILE_NAME(f)
   
    static char FILE_NAME[] = GET_FILE_NAME(__FILE__);
   
    4、得到一个数值类型所对应的字符串缓冲大小
   
    #define _TYPE_BUF_SIZE(type) sizeof #type
   
    #define TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type)
   
    char buf[TYPE_BUF_SIZE(INT_MAX)];
   
    --> char buf[_TYPE_BUF_SIZE(0x7fffffff)];
   
    --> char buf[sizeof “0x7fffffff”];
   
    这里相当于:
   
posted @ 2012-09-22 17:59 tbwshc 阅读(212) | 评论 (0)编辑 收藏

 二叉堆的实现数据结构中如何使用,我任务主要是在操作系统中的任务优先级调度问题,当然也可以用于实现堆排序问题,比如找出数组中的第K个最小值问题,采用二叉堆能够快速的实现,今天我就采用C语言实现了一个简单的二叉堆操作,完成这些数据结构我并不知道能干什么,我就当自己在练习C语言的功底吧。逐步完成自己的代码,希望自己在知识的理解力上有一定的提高。

    二叉堆是非常有特点的数据结构,可以采用简单的数组就能实现,当然链表的实现也是没有问题的,毕竟是一个二叉树问题,当然可以采用链表实现。采用数组实现时,可以找到两个特别明显的规律:

    左儿子:L_Son = Parent * 2;

    右儿子:R_Son = Parent * 2 + 1;

    二叉堆是一颗完全填满的树,可能例外的是在底层,底层上的元素是从左到右填入,当然二叉堆可以是基于大值的排序,也可以是基于小值的排列形式,本文采用简单的基于小值的形式。主要完成的操作:1、最小值的删除操作,该操作会删除根节点,然后提升儿子节点来代替根节点,具体的实现过程中通过提升左右儿子中较小的作为父结点,依此提升直到到达最底层,这种实现方式叫做下虑法。2、数据的插入操作,插入操作可能会破坏二叉堆的结构,一般在最底层创建一个空穴,然后比较插入值与空穴父结点的值,如果大于父结点的值,那么直接插入到空穴中,如果小于父结点,则将父结点的值插入到刚创建的空穴中,在父结点所在位置上形成新的父结点,这时候再和父结点的父结点比较,具体操作如上所述,直到找到具体的插入地址。当结点个数为偶数时,在删除操作中需要注意节点是否有右儿子的情况。具体的可以参考代码中的说明。

    具体的实现如下:

    结构体:

    #ifndef __BINARYHEAP_H_H_

    #define __BINARYHEAP_H_H_

    #include <stdlib.h>

    #include <assert.h>

    #define bool int

    #define true 1

    #define false 0

    /*打算采用数组的方式实现完全二叉堆*/

    typedef struct _binaryheap

    {

    /*因为需要动态扩展,

    *采用静态数组不方便*/

    int * parray;

    /*目前存在的结点*/

    int currentSize;

    /*树的实际容量*/

    int capacity;

    }BinaryHeap_t, *BinaryHeap_handle_t;

    #ifdef __cplusplus

    extern "C"

    {

    #endif

    bool init_BinaryHeap(BinaryHeap_handle_t heap, int capacity);

    bool alloc_BinaryHeap(BinaryHeap_handle_t *heap, int capacity);

    void delete_BinaryHeap(BinaryHeap_handle_t heap);

    void free_BinaryHeap(BinaryHeap_handle_t *heap);

    bool insert(BinaryHeap_handle_t heap,int value);

    int deleteMin(BinaryHeap_handle_t heap);

    bool isEmpty(BinaryHeap_handle_t heap);

    #ifdef __cplusplus

    }

    #endif

    #endif

    实现的接口函数如下:

    #include "binaryheap.h"

    bool isEmpty(BinaryHeap_handle_t heap)

    {

    assert(heap != NULL);

    return heap->currentSize == 0;

    }

    bool init_BinaryHeap(BinaryHeap_handle_t heap, int capacity)

    {

    int *parray = NULL;

    if(heap == NULL)

    return false;

    parray = (int *)calloc(capacity+1,sizeof(int));

    if(parray == NULL)

    return false;

    heap->parray = parray;

    heap->capacity = capacity;

    heap->currentSize = 0;

    return true;

    }

    void delete_BinaryHeap(BinaryHeap_handle_t heap)

    {

    assert(heap != NULL && heap->parray != NULL);

    heap->capacity = 0;

    heap->currentSize = 0;

    free(heap->parray);

    heap->parray = NULL;

    }

    void free_BinaryHeap(BinaryHeap_handle_t *heap)

    {

    assert(*heap != NULL);

    (*heap)->capacity = 0;

    (*heap)->currentSize = 0;

    free((*heap)->parray);

    (*heap)->parray = NULL;

    free(*heap);

    *heap = NULL;

    }

    bool alloc_BinaryHeap(BinaryHeap_handle_t *heap, int capacity)

    {

    int *parray = NULL;

    if(*heap != NULL)

    return false;

    *heap = (int *)calloc(1, sizeof(BinaryHeap_t));

    if(*heap == NULL)

    return false;

    /*其中的1,主要是为了使得数组从下标1开始计算*/

    parray =(int *)calloc(capacity + 1, sizeof(int));

    if(parray == NULL)

    return false;

    (*heap)->parray = parray;

    (*heap)->capacity = capacity;

    (*heap)->currentSize = 0;

    return true;

    }

    /**************************************************

    * 采用上虑法实现数据的插入操作

    * 上虑法的实现方式比较简单,首先创建一个空节点

    * 然后将需要插入的值与当前空穴的父结点进行比较

    * 如果大于父结点,直接插入空穴中

    * 如果小于父结点的值,则将父结点的值下拉到空穴中

    * 之前父结点的位置就是空穴,接着与上层比较

    * 直到找到父结点大于当前插入值的情况

    **************************************************/

    bool insert(BinaryHeap_handle_t heap, int value)

    {

    int index = 0;

    if(heap == NULL || heap->parray == NULL)

    return false;

    /*得到一个新的空穴下标*/

    index = ++heap->currentSize;

    /*条件是不是第一个下标和插入值比对应父结点小*/

    while(index > 1 && value < heap->parray[index/2])

    {

    /*将父结点保存到当前结点处*/

    heap->parray[index] = heap->parray[index/2];

    /*得到父结点的空穴位置*/

    index /= 2;

    }

    /*将插入的值保存到剩余的空穴中*/

    heap->parray[index] = value;

    return true;

    }

    /***********************************************************

    * 下虑法实现数据的重排序操作

    * 实现的方式,将子结点的两个儿子进行比较,将小的提升

    * 需要注意的是如何让判断节点是否一定存在右儿子

    * 实现的方式主要是利用了二叉堆的特性:

    * 2*pare = L_child

    * 2*pare + 1 = R_child;

    ***********************************************************/

    static void presort_BinaryHeap(BinaryHeap_handle_t heap,int hole)

    {

    /*这是二叉堆的特性*/

    int child = hole * 2;

    /*保存当前数据操作*/

    int tmp = 0;

    assert(heap != NULL && heap->parray != NULL);

    tmp = heap->parray[hole];

    /*hold * 2 <= heap->currentSize 判断了当前结点是否为最低层*/

    for(; hole * 2 <= heap->currentSize; hole = child)

    {

    child = hole * 2;

    /*******************************

    *这句代码解决是否存在右结点的问题

    *并确定了那个子结点提升的问题

    *******************************/

    if((child != heap->currentSize)

    && (heap->parray[child + 1] < heap->parray[child]))

    child ++;

    if(heap->parray[child] < tmp)

    {

    /*将子结点提升为父结点*/

    heap->parray[hole] = heap->parray[child];

    }

    }

    /*到达了最低的层,也就是树叶*/

    heap->parray[hole] = tmp;

    }

    /*实现数据的下虑法实现数据的删除操作*/

    int deleteMin(BinaryHeap_handle_t heap)

    {

    int ret = 0;

    int index = 0;

    assert(!isEmpty(heap));

    /*需要返回的值*/

    ret = heap->parray[1];

    /*将最后需要释放内存空间的值保存到第一个内存空间中*/

    heap->parray[1] = heap->parray[heap->currentSize --];

    /*从表头开始将新的二叉树进行重新排序*/

    presort_BinaryHeap(heap, 1);

    return ret;

    }

    测试代码:

    #include "binaryheap.h"

    #include <stdio.h>

    #include <time.h>

    void print_binaryheap(BinaryHeap_handle_t heap)[nettpage]

    {

    int i = 0;

    assert(heap != NULL && heap->parray != NULL);

    for(i = 1; i <= heap->currentSize; ++ i)

    {

    if(i %6)

    printf("%d\t",heap->parray[i]);

    else

    printf("\n%d\t",heap->parray[i]);

    }

    printf("\n");

    }

    int main()

    {

    int i = 0;

    int value = 0;

    srand((int)time(0));

    printf("********Test Binaryheap**************\n");

    BinaryHeap_t bheap;

    BinaryHeap_handle_t *pheap = NULL;

    printf("init and alloc test:\n");

    if(init_BinaryHeap(&bheap,10))

    {

    printf("init_BinaryHeap() successed!\n");

    }

    if (alloc_BinaryHeap(&pheap,15));

    {

    printf("alloc_BInaryHeap() successed!\n");

    }

    printf("***insert test*****\n");

    for(; i < 10; ++ i)

    {

    if(!insert(&bheap,5 * i - rand()%20))

    {

    printf("i = %d:insert failed !!\n",i);

    }

    }

    for(i = 0; i < 15; ++ i)

    {

    if(!insert(pheap,i * 8 - rand()%20))

    {

    printf("i = %d:insert failed!!\n",i);

    }

    }

    print_binaryheap(&bheap);

    print_binaryheap(pheap);

    printf("****deleteMin test****\n");

    for(i = 0; i < 5; ++ i)

    {

    value = deleteMin(&bheap);

    printf("bheap deleted:%d\n",value);

    value = deleteMin(pheap);

    printf("pheap deleted:%d\n",value);

    }

    print_binaryheap(&bheap);

    print_binaryheap(pheap);

    printf("deleteMin test successed\n");

    printf("****delete and free test:*******\n");

    delete_BinaryHeap(&bheap);

    printf("Is the bheap empty ? %s\n",

    isEmpty(&bheap)?"Yes":"No");

    free_BinaryHeap(&pheap);

    printf("*********Test successed!***********\n");

    pheap = NULL;

    return 0;

    }

    测试结果:

    [gong@Gong-Computer c_binaryheap]$ ./testbinaryheap

    ********Test Binaryheap**************

    init and alloc test:

    init_BinaryHeap()

    alloc_BInaryHeap()

    ***insert test*****

    -11    -9    -9    14    15

    10    21    23    40    26

    -16    2    14    20    13

    21    33    49    61    67    76

    86    83    95    109

    ****deleteMin test****

    bheap deleted:-11

    pheap deleted:-16

    bheap deleted:-9

    pheap deleted:2

    bheap deleted:-9

    pheap deleted:13

    bheap deleted:10

    pheap deleted:14

    bheap deleted:14

    pheap deleted:20

    15    23    21    40    26

    21    49    21    61    67

    76    33    95    83    109

    deleteMin test successed

    ****delete and free test:*******

    Is the bheap empty ? Yes

    *********Test

    从上面的测试结果可知,基本上实现了二叉堆的基本插入、删除操作。代码的关键点在于删除中的下虑和插入过程中的上虑操作。以及如何判断代码是否存在右儿子,如何充分运用二叉堆的特性。    二叉堆的实现数据结构中如何使用,我任务主要是在操作系统中的任务优先级调度问题,当然也可以用于实现堆排序问题,比如找出数组中的第K个最小值问题,采用二叉堆能够快速的实现,今天我就采用C语言实现了一个简单的二叉堆操作,完成这些数据结构我并不知道能干什么,我就当自己在练习C语言的功底吧。逐步完成自己的代码,希望自己在知识的理解力上有一定的提高。

    二叉堆是非常有特点的数据结构,可以采用简单的数组就能实现,当然链表的实现也是没有问题的,毕竟是一个二叉树问题,当然可以采用链表实现。采用数组实现时,可以找到两个特别明显的规律:

    左儿子:L_Son = Parent * 2;

    右儿子:R_Son = Parent * 2 + 1;

    二叉堆是一颗完全填满的树,可能例外的是在底层,底层上的元素是从左到右填入,当然二叉堆可以是基于大值的排序,也可以是基于小值的排列形式,本文采用简单的基于小值的形式。主要完成的操作:1、最小值的删除操作,该操作会删除根节点,然后提升儿子节点来代替根节点,具体的实现过程中通过提升左右儿子中较小的作为父结点,依此提升直到到达最底层,这种实现方式叫做下虑法。2、数据的插入操作,插入操作可能会破坏二叉堆的结构,一般在最底层创建一个空穴,然后比较插入值与空穴父结点的值,如果大于父结点的值,那么直接插入到空穴中,如果小于父结点,则将父结点的值插入到刚创建的空穴中,在父结点所在位置上形成新的父结点,这时候再和父结点的父结点比较,具体操作如上所述,直到找到具体的插入地址。当结点个数为偶数时,在删除操作中需要注意节点是否有右儿子的情况。具体的可以参考代码中的说明。

    具体的实现如下:

    结构体:

    #ifndef __BINARYHEAP_H_H_

    #define __BINARYHEAP_H_H_

    #include <stdlib.h>

    #include <assert.h>

    #define bool int

    #define true 1

    #define false 0

    /*打算采用数组的方式实现完全二叉堆*/

    typedef struct _binaryheap

    {

    /*因为需要动态扩展,

    *采用静态数组不方便*/

    int * parray;

    /*目前存在的结点*/

    int currentSize;

    /*树的实际容量*/

    int capacity;

    }BinaryHeap_t, *BinaryHeap_handle_t;

    #ifdef __cplusplus

    extern "C"

    {

    #endif

    bool init_BinaryHeap(BinaryHeap_handle_t heap, int capacity);

    bool alloc_BinaryHeap(BinaryHeap_handle_t *heap, int capacity);

    void delete_BinaryHeap(BinaryHeap_handle_t heap);

    void free_BinaryHeap(BinaryHeap_handle_t *heap);

    bool insert(BinaryHeap_handle_t heap,int value);

    int deleteMin(BinaryHeap_handle_t heap);

    bool isEmpty(BinaryHeap_handle_t heap);

    #ifdef __cplusplus

    }

    #endif

    #endif

    实现的接口函数如下:

    #include "binaryheap.h"

    bool isEmpty(BinaryHeap_handle_t heap)

    {

    assert(heap != NULL);

    return heap->currentSize == 0;

    }

    bool init_BinaryHeap(BinaryHeap_handle_t heap, int capacity)

    {

    int *parray = NULL;

    if(heap == NULL)

    return false;

    parray = (int *)calloc(capacity+1,sizeof(int));

    if(parray == NULL)

    return false;

    heap->parray = parray;

    heap->capacity = capacity;

    heap->currentSize = 0;

    return true;

    }

    void delete_BinaryHeap(BinaryHeap_handle_t heap)

    {

    assert(heap != NULL && heap->parray != NULL);

    heap->capacity = 0;

    heap->currentSize = 0;

    free(heap->parray);

    heap->parray = NULL;

    }

    void free_BinaryHeap(BinaryHeap_handle_t *heap)

    {

    assert(*heap != NULL);

    (*heap)->capacity = 0;

    (*heap)->currentSize = 0;

    free((*heap)->parray);

    (*heap)->parray = NULL;

    free(*heap);

    *heap = NULL;

    }

    bool alloc_BinaryHeap(BinaryHeap_handle_t *heap, int capacity)

    {

    int *parray = NULL;

    if(*heap != NULL)

    return false;

    *heap = (int *)calloc(1, sizeof(BinaryHeap_t));

    if(*heap == NULL)

    return false;

    /*其中的1,主要是为了使得数组从下标1开始计算*/

    parray =(int *)calloc(capacity + 1, sizeof(int));

    if(parray == NULL)

    return false;

    (*heap)->parray = parray;

    (*heap)->capacity = capacity;

    (*heap)->currentSize = 0;

    return true;

    }

    /**************************************************

    * 采用上虑法实现数据的插入操作

    * 上虑法的实现方式比较简单,首先创建一个空节点

    * 然后将需要插入的值与当前空穴的父结点进行比较

    * 如果大于父结点,直接插入空穴中

    * 如果小于父结点的值,则将父结点的值下拉到空穴中

    * 之前父结点的位置就是空穴,接着与上层比较

    * 直到找到父结点大于当前插入值的情况

    **************************************************/

    bool insert(BinaryHeap_handle_t heap, int value)

    {

    int index = 0;

    if(heap == NULL || heap->parray == NULL)

    return false;

    /*得到一个新的空穴下标*/

    index = ++heap->currentSize;

    /*条件是不是第一个下标和插入值比对应父结点小*/


while(index > 1 && value < heap->parray[index/2])

    {

    /*将父结点保存到当前结点处*/

    heap->parray[index] = heap->parray[index/2];

    /*得到父结点的空穴位置*/

    index /= 2;

    }

    /*将插入的值保存到剩余的空穴中*/

    heap->parray[index] = value;

    return true;

    }

    /***********************************************************

    * 下虑法实现数据的重排序操作

    * 实现的方式,将子结点的两个儿子进行比较tbw,将小的提升

    * 需要注意的是如何让判断节点是否一定存在右儿子

    * 实现的方式主要是利用了二叉堆的特性:

    * 2*pare = L_child

    * 2*pare + 1 = R_child;

    ***********************************************************/

    static void presort_BinaryHeap(BinaryHeap_handle_t heap,int hole)

    {

    /*这是二叉堆的特性*/

    int child = hole * 2;

    /*保存当前数据操作*/

    int tmp = 0;

    assert(heap != NULL && heap->parray != NULL);

    tmp = heap->parray[hole];

    /*hold * 2 <= heap->currentSize 判断了当前结点是否为最低层*/

    for(; hole * 2 <= heap->currentSize; hole = child)

    {

    child = hole * 2;

    /*******************************

    *这句代码解决是否存在右结点的问题

    *并确定了那个子结点提升的问题

    *******************************/

    if((child != heap->currentSize)

    && (heap->parray[child + 1] < heap->parray[child]))

    child ++;

    if(heap->parray[child] < tmp)

    {

    /*将子结点提升为父结点*/

    heap->parray[hole] = heap->parray[child];

    }

    }

    /*到达了最低的层,也就是树叶*/

    heap->parray[hole] = tmp;

    }

    /*实现数据的下虑法实现数据的删除操作*/

    int deleteMin(BinaryHeap_handle_t heap)

    {

    int ret = 0;

    int index = 0;

    assert(!isEmpty(heap));

    /*需要返回的值*/

    ret = heap->parray[1];

    /*将最后需要释放内存空间的值保存到第一个内存空间中*/

    heap->parray[1] = heap->parray[heap->currentSize --];

    /*从表头开始将新的二叉树进行重新排序*/

    presort_BinaryHeap(heap, 1);

    return ret;

    }

    测试代码:

    #include "binaryheap.h"

    #include <stdio.h>

    #include <time.h>

    void print_binaryheap(BinaryHeap_handle_t heap)

    {

    int i = 0;

    assert(heap != NULL && heap->parray != NULL);

    for(i = 1; i <= heap->currentSize; ++ i)

    {

    if(i %6)

    printf("%d\t",heap->parray[i]);

    else

    printf("\n%d\t",heap->parray[i]);

    }

    printf("\n");

    }

    int main()

    {

    int i = 0;

    int value = 0;

    srand((int)time(0));

    printf("********Test Binaryheap**************\n");

    BinaryHeap_t bheap;

    BinaryHeap_handle_t *pheap = NULL;

    printf("init and alloc test:\n");

    if(init_BinaryHeap(&bheap,10))

    {

    printf("init_BinaryHeap() successed!\n");

    }

    if (alloc_BinaryHeap(&pheap,15));

    {

    printf("alloc_BInaryHeap() successed!\n");

    }

    printf("***insert test*****\n");

    for(; i < 10; ++ i)

    {

    if(!insert(&bheap,5 * i - rand()%20))

    {

    printf("i = %d:insert failed !!\n",i);

    }

    }

    for(i = 0; i < 15; ++ i)

    {

    if(!insert(pheap,i * 8 - rand()%20))

    {

    printf("i = %d:insert failed!!\n",i);

    }

    }

    print_binaryheap(&bheap);

    print_binaryheap(pheap);

    printf("****deleteMin test****\n");

    for(i = 0; i < 5; ++ i)

    {

    value = deleteMin(&bheap);

    printf("bheap deleted:%d\n",value);

    value = deleteMin(pheap);

    printf("pheap deleted:%d\n",value);

    }

    print_binaryheap(&bheap);

    print_binaryheap(pheap);

    printf("deleteMin test successed\n");

    printf("****delete and free test:*******\n");

    delete_BinaryHeap(&bheap);

    printf("Is the bheap empty ? %s\n",

    isEmpty(&bheap)?"Yes":"No");

    free_BinaryHeap(&pheap);

    printf("*********Test successed!***********\n");

    pheap = NULL;

    return 0;

    }

    测试结果:

    [gong@Gong-Computer c_binaryheap]$ ./testbinaryheap

    ********Test Binaryheap**************

    init and alloc test:

    init_BinaryHeap()

    alloc_BInaryHeap()

    ***insert test*****

    -11    -9    -9    14    15

    10    21    23    40    26

    -16    2    14    20    13

    21    33    49    61    67    76

    86    83    95    109

    ****deleteMin test****

    bheap deleted:-11

    pheap deleted:-16

    bheap deleted:-9

    pheap deleted:2

    bheap deleted:-9

    pheap deleted:13

    bheap deleted:10

    pheap deleted:14

    bheap deleted:14

    pheap deleted:20

    15    23    21    40    26

    21    49    21    61    67

    76    33    95    83    109

    deleteMin test successed

    ****delete and free test:*******

    Is the bheap empty ? Yes

    *********Test

    从上面的测试结果可知,基本上实现了二叉堆的基本插入、删除操作。tbw代码的关键点在于删除中的下虑和插入过程中的上虑操作。以及如何判断代码是否存在右儿子,如何充分运用二叉堆的特性。

posted @ 2012-09-22 17:58 tbwshc 阅读(339) | 评论 (0)编辑 收藏

 一,static和extern:
   
    大工程下我们会碰到很多源文档。
   
    文档a.c
   
    static int i; //只在a文档中用
   
    int j;    //在工程里用
   
    static void init()         //只在a文档中用
   
    {
   
    }
   
    void callme()          //在工程中用
   
    {
   
    static int sum;
   
    }
   
    上面的全局i变量和init()函数只能用在a.c文档中,全局变量sum的作用域只在callme里。变量j和函数callme()的全局限扩充到整个工程文档。所以能够在下面的b.c中用extern关键字调用。extern告诉编译器这个变量或函数在其他文档里已被定义了。
   
    文档b.c
   
    extern int j;     //调用a文档里的
   
    extern void callme();  //调用a文档里的
   
    int main()
   
    {
   
    …
   
    }
   
    extern的另外用法是当C和C++混合编程时假如c++调用的是c源文档定义的函数或变量,那么要加extern来告诉编译器用c方式命名函数:
   
    文档A.cpp调用a.c里面的变量i和函数callme()
   
    extern “C”  //在c++文档里调用c文档中的变量
   
    {
   
    int j;
   
    void callme();
   
    }
   
    int main()
   
    {
   
    callme();
   
    }
   
    二,static法则:
   
    A、若全局变量仅在单个C文档中访问,则能够将这个变量修改为静态全局变量,tbw以降低模块间的耦合度;
   
    B、若全局变量仅由单个函数访问,则能够将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
   
    C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;
posted @ 2012-09-22 17:56 tbwshc 阅读(1415) | 评论 (0)编辑 收藏

    1、malloc函数:向系统申请分配指定size个字节的内存空间,分配成功后得到的是一个内存块,即连续的空间
   
    2、malloc分配不一定成功,所以最好验证一下:
   
    char *mallo;
   
    if ((mallo=(char *)malloc(36*sizeof(char)))==NULL)
   
    printf(“error in mallo!\n”);
   
    3、传指针参数的原理在谭浩强书上已经讲过,这里只是做传指针后实际的赋值方式探讨
   
    传递过来的参数:char *mallo
   
    3.1:mallo=“bag”;/*直接=不成功,调用后mallo只能在这个函数中打印出,调用这个函数的函数却不能在调用后得到相应的赋值结果*/
   
    3.2:for(;i<36;i++)
   
    {
   
    *(mallo++)='a'+rand()%26;
   
    //mallo[i]='a'+rand()%26;/*这句和上句的效果相同*/
   
    }/*for循环可以成功:依次赋值随进字母*/
   
    3.3:char *test=mallo;
   
    for(;i<36;i++)
   
    {
   
    *(test++)='a'+rand()%26;
   
    //test[i]='a'+rand()%26;
   
    }/*效果和3.2基本相同,只是让思路更清晰的一种做法*/
   
    3.4:strcpy(mallo,“bag”);/*strcpy可以成功:strcpy会把“bag”中的三个字符和‘\0’一个一个的拷贝到mallo中,和上面的for循环类似*/
   
    一开始在Linux下这种方式并没成功,在windows下添加#includes<string.h>后成功了(windows下没有这个include会报错),再回到Linux下也能赋值成功,估计可能是没有#includes<string.h>的缘故,但
   
    奇怪的是,我再去掉#includes<string.h>,还是成功,原因便无从知晓了。
   
    4、源码
   
    #include <stdio.h>
   
    #include <stdlib.h>
   
    #include <string.h>
   
    #include <memory.h>
   
    /*接受传过来的指针,并通过几种方式赋值*/
   
    void memtest(char *mallo)
   
    {
   
    int i=0;
   
    //char *test=mallo;
   
    printf(“===============================================================”);
   
    //printf(“\n*mallo:%s\n”,*mallo);
   
    printf(“\nmallo: %s\n”,mallo);
   
    /*for(;i<36;i++)
   
    {
   
    *(mallo++)='a'+rand()%26;
   
    mallo[i]='a'+rand()%26;
   
    }*//*for循环可以成功*/
   
    strcpy(mallo,“bag”);/*strcpy可以成功*/
   
    //mallo=“bag”;/*直接=不成功*/
   
    //printf(“test:%s\n”,test);
   
    printf(“\n\”bug\“ ->mallo: %s\n”,mallo);
   
    }
   
    void main()
   
    {
   
    char *mallo;
   
    if ((mallo=(char *)malloc(36*sizeof(char)))==NULL)/*申请空间*/
   
    printf(“error in mallo!\n”);
   
    //memset(mallo,1,sizeof(mallo));
   
    //mallo=“shanghaimizhuan”;
   
    printf(“mallo_main: %s\n”,mallo);/*打印申请空间内容,在windows下为乱码,而Linux下不显示*/
   
    /*以下打印数据在Linux和windows下数据不同,在赋值成功前windows已经会检测上面分配的空间大小,Linux则不会:strlen(mallo)可以看出*/
   
    printf(“sizeof(mallo):%d--分割线--sizeof(*mallo):%d--分割线--strlen(mallo):%d\n”,sizeof(mallo),sizeof(*mallo),strlen(mallo));
   
    memtest(mallo);/*调用赋值函数*/
   
    printf(“===============================================================”);
   
    printf(“\nmallo_aftersetparam:%s\n”,mallo);/*tbw调用后输出*/
   
    printf(“sizeof(mallo):%d--分割线--sizeof(*mallo):%d--分割线--strlen(mallo):%d\n”,sizeof(mallo),sizeof(*mallo),strlen(mallo));
   
    free(mallo);
   
    }
posted @ 2012-09-16 14:10 tbwshc 阅读(1588) | 评论 (1)编辑 收藏

    最近的几次文章的评论中不少读者提到文章的更新速度的更新量的问题,浅墨会逐渐重视起来,尽量在保证质量的基础上,每周都拿出够分量的内容。本周的文章算是近几次更新量的一个弥补,这篇文章的字数达到了近一万字。
   
    一、DirectX11的现有组件
   
    DirectX的API被分为颇多组件,每一组件都展现了系统不同方面的功能。其中的每一套API都能被独立的使用,因此我们可以按照所需有选择地自由添加我们游戏中需要的功能。在最新版本的DirectX中,不少组件迎来了更新,如Direct3D.其他的组件保持着现有的功能,当然,也有一些被弃用的组件面临着被移除的命运。值得一提的是,DirectX中的各个内部组件可以独立进行新功能的升级。
   
    下面进行分别介绍:
   
    1.Direct2D
   
    Direct2D用于Win32应用程序中2D图形的绘制。Direct2D善于高性能矢量图形的渲染。
   
    2. DirectWrite
   
    DirectWrite用于Direct2D应用程序中的字体和文字渲染。
   
    3 . DXGI
   
    DXGI(DirectX Graphics Infrastructure)即DirectX图形基础,用于
   
    Direct3D交换链(swap chains)和枚举设备适配器(enumeration of deviceadapters)的创建。
   
    4 .Direct3D
   
    Direct3D用于DirectX中所有的与3D图形相关的操作。Direct3D可谓DirectX中的大牌级API,受到了微软最多的关怀与多次针对性的更新,它也最多被世人所熟知。这个专栏后续内容的大部分的篇幅将集中于讲解Direct3D上。
   
    5. XAudio2
   
    XAudio2 是一款底层的音频处理API,以前为XDK(Xbox Development Kit)的一部分,目前,隶属于DIRECTXSDK.XAudio2替换了DirectSound.初始版本的XAudio用于的第一代Xbox游戏机。
   
    6. XACT3
   
    XACT3是一款建立在XAudio2之上的更高级别的音频处理API.XACT3允许开发者在他们的应用中使用跨平台音频创作工具。若开发者希望从底层控制音频系统或者希望创建自己的类型于XACT3的更高级别的音频系统,可以运用XAdio2来完成各项功能。tbwXACT3,我们已经在附录B中讨论过,作为“DIRECTX中的声音”从配套网站,是一款非常容易上手的游戏音频制作工具。
   
    7. XInput
   
    XInput是XDK和DirectX SDK的负责输入功能的 API,用于处理Xbox 360控制器输入。基本上任何可以在Xbox 360上可以使用的命令,都可以在PC上使用,而XInput就是帮助我们在这些设备上进行输入相关操作的API.这些设备不仅包含Xbox手柄,也包含了其他很多设备。需要说明的是,XInput 替换了之前版本的DirectInput.
   
    注:XAudio是只能用于Xbox游戏机的音效API. XAudio2,其继任者,可用于Xbox游戏机和基于Windows的PC.
   
    8 . XNAMath
   
    新出现的XNA Math 不是一款API,而是是一个数学库,进行电子游戏中常见运算的优化工作。XNA Math采用了SIMD (Single Instruction Multiple Data单指令多数据)来执行多个操作的单指令调用。XNA Math库适用于基于Windows的PC以及Xbox 360.相关内容我们将在后续内容继续讲解。
   
    注:XNA GameStudio为一款基于DirectX的游戏开发工具,可供我们使用C#和。NET编程语言来为Xbox360与Windows PC平台编写游戏。而XNA Math是一款DirectX SDK中数学库的名字,可独立于XNA Game Studio单独使用。我们使用XNA Math不必下载XNA Game Studio SDK.


    
    9 . DirectCompute
   
    DirectCompute是一款DIRECTX 11中新加入的API,作用为支持GPU的通用多线程计算(general purpose multi threading computing)。GPU具有并行处理多任务的能力,如物理,视频压缩与视频解压,音频处理等。并非所有的任务都适合GPU来完成,但是对于这些,由GPU来完成的可能性是巨大的(but for those that are, the possibilities are tremendous)。想了解DirectCompute的更多信息,可以查阅相关资料。
   
    10. DirectSetup
   
    当我们完成游戏开发的时候,我们理所当然地需要把完成品呈现给用户。DirectSetup给我们提供了在用户的电脑上安装最新版本的DirectX的功能。DirectSetup也具有检查已经安装了的DirectX版本号的功能。
   
    11.Windows Games Explorer
   
    WindowsGames Explorer(游戏资源管理器)是Windows Vista与Windows 7中的新特性,可供游戏开发者在他们的操作系统上展示(测试)他们的游戏。比如游戏的显示,标题,评级,描述,特定区域的风格框,评分内容(如M为成人,T为青少年等),游戏数据统计和通知,家长控制等。DirectX SDK中提供了大量如何使用自己的游戏的游戏资源管理器的教程,这对于发行一款游戏是非常有用的。下面的图1是浅墨电脑上的Windows7游戏资源管理器的界面截图

posted @ 2012-09-16 14:09 tbwshc 阅读(1827) | 评论 (1)编辑 收藏

这里我们提出一种游戏循环的概念,游戏循环是将原先程序中的消息循环加以修改,方法是判断其中的内容目前是否有要处理的消息,如果有则进行处理,否则按照设定的时间间隔来重绘画面。下面是接下来一段游戏循环的程序代码:
   
    //游戏循环
   
    while( msg.message!=WM_QUIT )               //注释点1(详细内容见下)
   
    {
   
    if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )       //注释点2(详细内容见下)
   
    {
   
    TranslateMessage( &msg );
   
    DispatchMessage( &msg );
   
    }
   
    else
   
    {
   
    tNow = GetTickCount();                        //注释点3
   
    if(tNow-tPre >= 100)                   //注释点4
   
    MyPaint(hdc);
   
    }
   
    }
   
    我们来讲解一下游戏循环片段中的几个重点。
   
    <1>注释点1:当收到的msg.message不是窗口结束消息WM_QUIT,则继续运行循环,其中msg是一个MSG的消息结构,其结构成员message则是一个消息类型的代号。
   
    <2>注释点2:使用PeekMessage()函数来检测目前是否有需要处理的消息,若检测到消息(包含WM_QUIT消息)则会返回一个非“0”值,否则返回“0”.因此在游戏循环中,若检测到消息便进行消息的处理,否则运行else叙述之后的程序代码。这里我们要注意的是,PeekMessage()函数不能用原先消息循环的条件GetMessage()取代,因为GetMessage()函数只有在取得WM_QUIT消息时才会返回“0”,其他时候则是返回非“0”值或“-1”(发生错误时)
   
    <3>注释点3:GetTickCount()函数会取得系统开始运行到目前所经过的时间,单位是毫秒(milliseconds)。  之前我理解错了,在这里感谢worldy的指出我的错误。
   
    DWORD GetTickCount()    //取得系统开始到目前经过的时间
   
    这里取得时间的目的主要是可以搭配接下来的判断式,用来调整游戏运行的速度,使得游戏不会因为运行计算机速度的不同而跑得太快或者太慢。

    
    <4>注释点4:if条件式中,“tPre”记录前次绘图的时间,而“tNow-tRre”则是计算上次绘图到这次循环运行之间相差多少时间。这里设置为若相差40个单位时间以上则再次进行绘图的操作,通过这个数值的控制可以调整游戏运行的速度。这里设定40个单位时间(微秒)的原因是,因为每隔40个单位进行一次绘图的操作,那么1秒钟大约重绘窗口1000/40=25次刚好可以达到期望值。
   
    由于循环的运行速度远比定时器发出时间信号来得快,因此使用游戏循环可以更精准地控制程序运行速度并提高每秒钟画面重绘的次数。
   
    了解了游戏循环使用的基本概念之后,接下来的范例将以游戏循环的方法进行窗口的连续贴图,更精确地制作游戏动画效果。
   
    #include “stdafx.h”
   
    #include <stdio.h>
   
    //全局变量声明
   
    HINSTANCE hInst;
   
    HBITMAP man[7];
   
    HDC  hdc,mdc;
   
    HWND    hWnd;
   
    DWORD   tPre,tNow,tCheck;                 //声明三个函数来记录时间,tPre记录上一次绘图的时间,tNow记录此次准备绘图的时间,tCheck记录每秒开始的时间
   
    int  num,frame,fps;                    //num用来记录图号,frame用来累加每次画面更新的次数,fps(frame per second)用来记录每秒画面更新的次数
   
    //全局函数的声明
   
    ATOM     MyRegisterClass
   
    (HINSTANCE hInstance);
   
    BOOL     InitInstance
   
    (HINSTANCE, int);
   
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM,
   
    LPARAM);
   
    void     MyPaint(HDC hdc);
   
    //***WinMain函数,程序入口点函数**************************************
   
    int APIENTRY WinMain(HINSTANCE hInstance,
   
    HINSTANCE hPrevInstance,
   
    LPSTR     lpCmdLine,
   
    int       nCmdShow)
   
    {
   
    MSG msg;
   
    MyRegisterClass(hInstance);
   
    //运行初始化函数
   
    if (!InitInstance (hInstance, nCmdShow))
   
    {
   
    return FALSE;
   
    }
   
    GetMessage(&msg,NULL,NULL,NULL);   //感谢xiaoxiangp的提醒,需要在进入消息循环之前初始化msg,避免了死循环发生的可能性。
   
    //游戏循环
   
    while( msg.message!=WM_QUIT )
   
    {
   
    if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )
   
    {
   
    TranslateMessage( &msg );
   
    DispatchMessage( &msg );
   
    }
   
    else
   
    {
   
    tNow = GetTickCount();
   
    if(tNow-tPre >= 100)        //当此次循环运行与上次绘图时间相差0.1秒时再进行重绘操作
   
    MyPaint(hdc);
   
    }
   
    }
   
    return msg.wParam;
   
    }
   
    //****设计一个窗口类,类似填空题,使用窗口结构体*************************
   
    ATOM MyRegisterClass(HINSTANCE hInstance)
   
    {
   
    WNDCLASSEX wcex;
   
    wcex.cbSize = sizeof(WNDCLASSEX);
   
    wcex.style   = CS_HREDRAW |
   
    CS_VREDRAW;
   
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
   
    wcex.cbClsExtra  = 0;
   
    wcex.cbWndExtra  = 0;
   
    wcex.hInstance   = hInstance;
   
    wcex.hIcon   = NULL;
   
    wcex.hCursor     = NULL;
   
    wcex.hCursor     = LoadCursor(NULL,
   
    IDC_ARROW);
   
    wcex.hbrBackground  = (HBRUSH)
   
    (COLOR_WINDOW+1);
   
    wcex.lpszMenuName   = NULL;
   
    wcex.lpszClassName  = “canvas”;
   
    wcex.hIconSm     = NULL;
   
    return RegisterClassEx(&wcex);
   
    }
   
    //****初始化函数*************************************
   
    // 从文件加载位图
   
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
   
    {
   
    char filename[20] = “”;
   
    int i;
   
    hInst = hInstance;
   
    hWnd = CreateWindow(“canvas”, “动画演示” ,
   
    WS_OVERLAPPEDWINDOW,
   
    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
   
    NULL, NULL, hInstance, NULL);
   
    if (!hWnd)
   
    {
   
    return FALSE;
   
    }
   
    MoveWindow(hWnd,10,10,600,450,true);
   
    ShowWindow(hWnd, nCmdShow);
   
    UpdateWindow(hWnd);
   
    hdc = GetDC(hWnd);
   
    mdc = CreateCompatibleDC(hdc);
   
    //载入各个人物位图
   
    for(i=0;i<7;i++)
   
    {
   
    sprintf(filename,“man%d.bmp”,i);
   
    man[i] = (HBITMAP)LoadImage
   
    (NULL,filename,IMAGE_BITMAP,640,480,LR_LOADFROMFILE);
   
    }
   
    num = 0;
   
    frame = 0;
   
    MyPaint(hdc);
   
    return TRUE;
   
    }
   
    //****自定义绘图函数*********************************
   
    // 1.计算与显示每秒画面更新次数
   
    // 2.按照图号顺序进行窗口贴图
   
    void MyPaint(HDC hdc)
   
    {
   
    char str[40] = “”;
   
    if(num == 7)
   
    num = 0;
   
    frame++;            //画面更新次数加1
   
    if(tNow - tCheck >= 1000)               //tbw判断此次绘图时间由前一秒算起是否已经达到1秒钟的时间间隔。若是,则将目前的‘frame’值赋给“fps”,表示这一秒内所更新的画面次数,然后将“frame”值回0,并重设下次计算每秒画面数的起始时间“iCheck”.
   
    {
   
    fps = frame;
   
    frame = 0;
   
    tCheck = tNow;
   
    }
   
    SelectObject(mdc,man[num]);         //选用要更新的图案到mdc中,再输出显示每秒画面更新次数的字符串到mdc上,最后将mdc的内容贴到窗口中。
   
    sprintf(str,“每秒显示 %d个画面”,fps);
   
    TextOut(mdc,0,0,str,strlen(str));
   
    BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);
   
    tPre = GetTickCount();     //记录此次绘图时间,供下次游戏循环中判断是否已经达到画面更新操作设定的时间间隔。
   
    num++;
   
    }
   
    //******消息处理函数*********************************
   
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
   
    WPARAM wParam, LPARAM lParam)
   
    {
   
    int i;
   
    switch (message)
   
    {
   
    case WM_DESTROY:     //窗口结束消息
   
    DeleteDC(mdc);
   
    for(i=0;i<7;i++)
   
    DeleteObject(man[i]);
   
    ReleaseDC(hWnd,hdc);
   
    PostQuitMessage(0);
   
    break;
   
    default:     //其他消息
   
    return DefWindowProc(hWnd,
   
    message, wParam, lParam);
   
    }
   
    return 0;
   
    }
   
    程序的运行结果如下图:
posted @ 2012-09-16 14:07 tbwshc 阅读(114) | 评论 (0)编辑 收藏

PB9开发的程序,用PB11.5打开过后,再用PB9就打不开了
PB9开发的程序,用PB11.5打开过后,再用PB9就打不开了,添加目标时提示 could not add target because of a bad application library in "g:\11\tv_prg.pbt",怎办才能用PB9重新打开呢?

------解决方案--------------------------------------------------------
这个恐怕不行了。
那个项目已经被迁移成了 PB11.5 的版本了。

像这样的操作应该事件tb做备份的。
------解决方案--------------------------------------------------------
高的能兼容低的,低的不能兼容高的
------解决方案--------------------------------------------------------
如果你没有备份的话 那你悲剧了
------解决方案--------------------------------------------------------
找一以前的备份,用备份吧

如果没有备份,你真的悲剧了
------解决方案--------------------------------------------------------
试试 Regenerate
posted @ 2012-09-08 13:34 tbwshc| 编辑 收藏

仅列出标题
共10页: 1 2 3 4 5 6 7 8 9 Last