<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>开心编程网 &#187; 数据结构</title>
	<atom:link href="http://www.kaixinbc.com/category/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84/feed" rel="self" type="application/rss+xml" />
	<link>http://www.kaixinbc.com</link>
	<description>是一个专注于java、.net、asp、jsp、php、C语言、C++语言、Delphi、go语言、MySQL、sql server、linux、oracle、及Web 2.0等的原创IT编程网站，为国内众多的编程爱好者提供一个“平等自由协作创造”的开放式交流环境，提供编程专题文章、编程论坛、资源下载、博客和开源项目等栏目,作者方志凯（fangzhikai）。</description>
	<lastBuildDate>Tue, 31 Aug 2010 09:07:16 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>MASM中标号和变量的命名规范</title>
		<link>http://www.kaixinbc.com/2010/01/masm.html</link>
		<comments>http://www.kaixinbc.com/2010/01/masm.html#comments</comments>
		<pubDate>Tue, 26 Jan 2010 02:56:13 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[数据结构]]></category>

		<guid isPermaLink="false">http://www.kaixinbc.com/?p=148</guid>
		<description><![CDATA[
MASM中标号和变量的命名规范
MASM中标号和变量的命名规范是相同的，如下：
1)        可以用字母、数字、下划线及符号@、$和?。
2)        第一个符号不能是数字。
3)        长度不能超过240个字符。
4)        不能使用指令名等关键字。
5)        在作用域内必须是唯一的。
全局变量
全局变量的作用域是整个程序
Win32汇编的全部变量定义在.data或.data?段内，这两个段都是可写的。可以同时定义变量的类型和长度。
全局变量的定义格式如下：
变量名    类型       初始值1,初始值2,&#8230;&#8230;
变量名    类型       重复数量 dup （初始值1,初始值2,&#8230;&#8230;）
MASM支持的变量类型如下表：



名称
表示方式
缩写
长度(字节)


字节
Byte
db
1


字
word
dw
2


双字(double word)
dword
dd
4


三字(far word)
fword
df
6


四字(quad word)
qword
dq
8


10字节BCD码(ten byte)
tbyte
dt
10


有符号字节(sign byte)
sbyte
 
1


有符号字(sign word)
sword
 
2


有符号双字(sign dword)
sdword
 
4


单精度浮点数
Real4
 
4


双精度浮点数
Real8
 
8


10字节浮点数
Real10
 
10



注意：只有定义全局变量的时候，类型才可以用缩写。
在byte类型变量的定义中，可以用引号定义字符串和数值定义的方法混用。
例如：szText        db           ‘Hello,world!’,0dh,0ah,’Hello again’,0dh,0ah,0
全局变量的初始化：
全局变量在定义中既可以指定初值，也可以只用问号预留空间。
全局变量定义在.data?段中时，只能用问号预留空间，因为.data?段不能指定初始值。
定义时用问号指定的全局变量的初始值是0。
局部变量
局部变量的好处是使程序的模块结构更加分明。
局部变量的缺点是因为空间是临时分配的，所以无法定义含有初始化值的变量，对局部变量的初始化一般在子程序中由指令完成。
局部变量的作用域是单个子程序。
局部变量定义在堆栈中。
局部变量的定义格式如下：
local       变量名1[[重复数量]][:类型],变量名2[[重复数量]][:类型] &#8230;&#8230;
local是MASM提供的伪指令，用于支持局部变量的定义。有了local伪指令降低不少难度。
定义局部变量需注意以下几点：
a)         local伪指令必须紧接在子程序定义的伪指令proc后、其它指令开始之前，因为局部变量的数目必须在子程序开始的时候就确定下来；
b)        定义局部变量时数据类型不能用缩写。如果要定义数据结构，可以用数据结构的名称当作类型；
c)        Win32汇编中，参数的默认类型是dword，如果定义dword类型的局部变量，类型可以省略；
d)        当定义数组类型的局部变量时，重复数量可以用“[]”括起来，不能使用定义全局变量的dup伪指令。
e)         局部变量不能和已定义的全局变量同名。
f)         局部变量的作用域是当前的子程序，所以在不同的子程序中可以有同名的局部变量。
局部变量的初始化：
局部变量无法在定义的时候指定初始化值，因为local伪指令只是为局部变量留出空间。
局部变量的初始值是随机的，所以，对局部变量的值一定要初始化。
一般在子程序中使用指令来初始化局部变量。
使用局部变量时的注意点：
a)         ebp寄存器是关键，它起到保存原始esp寄存器值的作用；
b)        另外，ebp寄存器随时用做存取局部变量的指针基址，所以绝不能把ebp寄存器用于别的用途；
c)        ebp寄存器的值绝对不能被改变，把ebp寄存器的值改掉，程序就玩完；
数据结构
数据结构相当于一种自定义的数据类型，类似C语言中的struct定义。
汇编中，数据结构的定义方法如下：
结构名    struct
字段1     类型       ？
字段2     类型       ？
&#8230;&#8230;
结构名    ends
定义数据结构并不会在某个段中产生数据，只有使用数据结构在数据段中定义数据后，才会产生数据。
使用数据结构在数据段中定义数据的两种方法如下：
第一种定义方法是未初始化的定义方法：
                     .data?
stWndClass    WNDCLASS         &#60;&#62;
&#8230;&#8230;
第二种定义方法是定义的同时指定结构中个字段的初始值：
                     .data
stWndClass    WNDCLASS         &#60;1,1,1,1,1,1,1,1,1,1&#62;
&#8230;&#8230;
汇编中，对数据结构变量的几种引用方法如下：
a)         最直接的方法：
              mov eax,stWndClass.lpfnWndProc
              如果stWndClass结构变量在内存中的起始地址是403000h，那么这句指令会被编译成mov eax,[403004h]
b)        在实际使用中，常有使用指针存取数据结构变量的情况：
              [...]]]></description>
			<content:encoded><![CDATA[<div id="blog_text">
<p><strong>MASM中标号和变量的命名规范</strong></p>
<p>MASM中标号和变量的命名规范是相同的，如下：</p>
<p>1)        可以用字母、数字、下划线及符号@、$和?。</p>
<p>2)        第一个符号不能是数字。</p>
<p>3)        长度不能超过240个字符。</p>
<p>4)        不能使用指令名等关键字。</p>
<p>5)        在作用域内必须是唯一的。</p>
<p><strong>全局变量</strong></p>
<p>全局变量的作用域是整个程序</p>
<p>Win32汇编的全部变量定义在.data或.data?段内，这两个段都是可写的。可以同时定义变量的类型和长度。</p>
<p>全局变量的定义格式如下：</p>
<p>变量名    类型       初始值1,初始值2,&#8230;&#8230;</p>
<p>变量名    类型       重复数量 dup （初始值1,初始值2,&#8230;&#8230;）</p>
<p>MASM支持的变量类型如下表：</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="167" valign="top">名称</td>
<td width="117" valign="top">表示方式</td>
<td width="142" valign="top">缩写</td>
<td width="142" valign="top">长度(字节)</td>
</tr>
<tr>
<td width="167" valign="top">字节</td>
<td width="117" valign="top">Byte</td>
<td width="142" valign="top">db</td>
<td width="142" valign="top">1</td>
</tr>
<tr>
<td width="167" valign="top">字</td>
<td width="117" valign="top">word</td>
<td width="142" valign="top">dw</td>
<td width="142" valign="top">2</td>
</tr>
<tr>
<td width="167" valign="top">双字(double word)</td>
<td width="117" valign="top">dword</td>
<td width="142" valign="top">dd</td>
<td width="142" valign="top">4</td>
</tr>
<tr>
<td width="167" valign="top">三字(far word)</td>
<td width="117" valign="top">fword</td>
<td width="142" valign="top">df</td>
<td width="142" valign="top">6</td>
</tr>
<tr>
<td width="167" valign="top">四字(quad word)</td>
<td width="117" valign="top">qword</td>
<td width="142" valign="top">dq</td>
<td width="142" valign="top">8</td>
</tr>
<tr>
<td width="167" valign="top">10字节BCD码(ten byte)</td>
<td width="117" valign="top">tbyte</td>
<td width="142" valign="top">dt</td>
<td width="142" valign="top">10</td>
</tr>
<tr>
<td width="167" valign="top">有符号字节(sign byte)</td>
<td width="117" valign="top">sbyte</td>
<td width="142" valign="top"> </td>
<td width="142" valign="top">1</td>
</tr>
<tr>
<td width="167" valign="top">有符号字(sign word)</td>
<td width="117" valign="top">sword</td>
<td width="142" valign="top"> </td>
<td width="142" valign="top">2</td>
</tr>
<tr>
<td width="167" valign="top">有符号双字(sign dword)</td>
<td width="117" valign="top">sdword</td>
<td width="142" valign="top"> </td>
<td width="142" valign="top">4</td>
</tr>
<tr>
<td width="167" valign="top">单精度浮点数</td>
<td width="117" valign="top">Real4</td>
<td width="142" valign="top"> </td>
<td width="142" valign="top">4</td>
</tr>
<tr>
<td width="167" valign="top">双精度浮点数</td>
<td width="117" valign="top">Real8</td>
<td width="142" valign="top"> </td>
<td width="142" valign="top">8</td>
</tr>
<tr>
<td width="167" valign="top">10字节浮点数</td>
<td width="117" valign="top">Real10</td>
<td width="142" valign="top"> </td>
<td width="142" valign="top">10</td>
</tr>
</tbody>
</table>
<p>注意：只有定义全局变量的时候，类型才可以用缩写。</p>
<p>在byte类型变量的定义中，可以用引号定义字符串和数值定义的方法混用。</p>
<p>例如：szText        db           ‘Hello,world!’,0dh,0ah,’Hello again’,0dh,0ah,0</p>
<p>全局变量的初始化：</p>
<p>全局变量在定义中既可以指定初值，也可以只用问号预留空间。</p>
<p>全局变量定义在.data?段中时，只能用问号预留空间，因为.data?段不能指定初始值。</p>
<p>定义时用问号指定的全局变量的初始值是0。</p>
<p><strong>局部变量</strong></p>
<p>局部变量的好处是使程序的模块结构更加分明。</p>
<p>局部变量的缺点是因为空间是临时分配的，所以无法定义含有初始化值的变量，对局部变量的初始化一般在子程序中由指令完成。</p>
<p>局部变量的作用域是单个子程序。</p>
<p>局部变量定义在堆栈中。</p>
<p>局部变量的定义格式如下：</p>
<p>local       变量名1[[重复数量]][:类型],变量名2[[重复数量]][:类型] &#8230;&#8230;</p>
<p>local是MASM提供的伪指令，用于支持局部变量的定义。有了local伪指令降低不少难度。</p>
<p>定义局部变量需注意以下几点：</p>
<p>a)         local伪指令必须紧接在子程序定义的伪指令proc后、其它指令开始之前，因为局部变量的数目必须在子程序开始的时候就确定下来；</p>
<p>b)        定义局部变量时数据类型不能用缩写。如果要定义数据结构，可以用数据结构的名称当作类型；</p>
<p>c)        Win32汇编中，参数的默认类型是dword，如果定义dword类型的局部变量，类型可以省略；</p>
<p>d)        当定义数组类型的局部变量时，重复数量可以用“[]”括起来，不能使用定义全局变量的dup伪指令。</p>
<p>e)         局部变量不能和已定义的全局变量同名。</p>
<p>f)         局部变量的作用域是当前的子程序，所以在不同的子程序中可以有同名的局部变量。</p>
<p>局部变量的初始化：</p>
<p>局部变量无法在定义的时候指定初始化值，因为local伪指令只是为局部变量留出空间。</p>
<p>局部变量的初始值是随机的，所以，对局部变量的值一定要初始化。</p>
<p>一般在子程序中使用指令来初始化局部变量。</p>
<p>使用局部变量时的注意点：</p>
<p>a)         ebp寄存器是关键，它起到保存原始esp寄存器值的作用；</p>
<p>b)        另外，ebp寄存器随时用做存取局部变量的指针基址，所以绝不能把ebp寄存器用于别的用途；</p>
<p>c)        ebp寄存器的值绝对不能被改变，把ebp寄存器的值改掉，程序就玩完；</p>
<p><strong>数据结构</strong></p>
<p>数据结构相当于一种自定义的数据类型，类似C语言中的struct定义。</p>
<p>汇编中，数据结构的定义方法如下：</p>
<p>结构名    struct</p>
<p>字段1     类型       ？</p>
<p>字段2     类型       ？</p>
<p>&#8230;&#8230;</p>
<p>结构名    ends</p>
<p>定义数据结构并不会在某个段中产生数据，只有使用数据结构在数据段中定义数据后，才会产生数据。</p>
<p>使用数据结构在数据段中定义数据的两种方法如下：</p>
<p>第一种定义方法是未初始化的定义方法：</p>
<p>                     .data?</p>
<p>stWndClass    WNDCLASS         &lt;&gt;</p>
<p>&#8230;&#8230;</p>
<p>第二种定义方法是定义的同时指定结构中个字段的初始值：</p>
<p>                     .data</p>
<p>stWndClass    WNDCLASS         &lt;1,1,1,1,1,1,1,1,1,1&gt;</p>
<p>&#8230;&#8230;</p>
<p>汇编中，对数据结构变量的几种引用方法如下：</p>
<p>a)         最直接的方法：</p>
<p>              mov eax,stWndClass.lpfnWndProc</p>
<p>              如果stWndClass结构变量在内存中的起始地址是403000h，那么这句指令会被编译成mov eax,[403004h]</p>
<p>b)        在实际使用中，常有使用指针存取数据结构变量的情况：</p>
<p>              如果使用esi寄存器做指针寻址</p>
<p>              mov esi,offset stWndClass</p>
<p>              mov eax,[esi + WNDCLASS.lpfnWndProc]</p>
<p>              第二句指令将被编译成mov eax,[esi+4]</p>
<p>c)        使用assume伪指令把寄存器预先定义为结构指针，在进行操作：</p>
<p>              mov       esi,offset stWndClass</p>
<p>              assume esi:ptr WNDCLASS</p>
<p>              mov        eax,[esi].lpfnWndClass</p>
<p>              &#8230;&#8230;</p>
<p>              assume esi:nothing</p>
<p>              编译后产生同样的代码，不过程序的可读性比较好。</p>
<p>              注意：在不使用esi寄存器做指针的时候要用assume esi:nothing取消定义。</p>
<p>结构的嵌套定义如下：</p>
<p>NEW_WNDCLASS      struct</p>
<p>dwOption                     dword            ?</p>
<p>oldWndClass                 WNDCLASS &lt;&gt;</p>
<p>NEW_WNDCLASS       ends</p>
<p>引用嵌套的oldWndClass结构变量的lpfnWndProc字段的方法：</p>
<p>assume esi:ptr NEW_WNDCLASS</p>
<p>mov       eax,[esi].oldWndClass.lpfnWndProc</p>
<p>&#8230;&#8230;</p>
<p>assume esi:nothing</p>
<p>windows.inc文件定义了大部分Win32 API所涉及的常量和数据结构。</p>
<p><strong>以不同的类型访问变量</strong></p>
<p>MASM中以不同的类型访问不会对变量造成影响。而C语言中的数据类型强制转换过程中，数据的内容已经发生变化。</p>
<p>MASM中，如果要用指定类型之外的长度访问变量，必须显式地指出要访问的长度，这样，编译器忽略语法上的长度校验，仅使用变量的地址。</p>
<p>访问变量是显式地指出要访问长度的方法是：</p>
<p>类型       ptr   变量名</p>
<p>例如：</p>
<p>mov       ax,word ptr szBuffer</p>
<p>mov       eax,dword ptr szBuffer</p>
<p>类型可以设置为byte、word、dword、fword、qword、real8和real10。</p>
<p>类型必须和操作的寄存器长度匹配，否则无法通过编译。</p>
<p>需要注意的是：</p>
<p>指定类型的访问变量并不会去检测长度是否溢出。</p>
<p><strong>变量的尺寸和数量</strong></p>
<p>sizeof伪操作符可以取得变量、数据类型或数据结构以字节为单位的长度（尺寸）。</p>
<p>格式：</p>
<p>sizeof     变量、数据类型或数据结构名</p>
<p>lengthof伪操作符可以取得变量、数据类型或数据结构中数据的项数（数量）</p>
<p>格式：</p>
<p>length      变量、数据类型或数据结构名</p>
<p>对字符串使用sizeof伪操作符，取得的长度包括结束符0。</p>
<p>需要注意的是：</p>
<p>sizeof伪操作符和length伪操作符取得的数值是编译期产生的，由编译器直接替换到指令中去。所以，在反汇编得到的代码中没有sizeof或lengthof，而只有它们取得的数值。</p>
<p>取得字符串长度的一种特殊情况：</p>
<p>如果szHello的定义分成两行：</p>
<p>szHello db    ‘Hello’,0dh,0ah</p>
<p>              db    ‘World’,0</p>
<p>sizeof szHello得到的数值是7而不是13。</p>
<p>这种定义方式实质为越界使用字符串变量。</p>
<p>MASM中的变量定义只认一行，后一行db ‘World’,0实际上是另一个没有名称的数据定义。</p>
<p>要取得这种字符串的长度时，千万不能用sizeof伪指令，最好是在程序中用lstrlen函数去计算。</p>
<p><strong>获取变量地址</strong></p>
<p>获取全局变量地址和获取局部变量地址的操作是不同的。</p>
<p>因为全局变量定义在数据段中，而局部变量在堆栈中。全局变量的地址可以在编译期确定，而局部变量的地址只能在运行期确定。</p>
<p>全局变量的地址在编译期已经由编译器确定了。</p>
<p>获取全局变量的地址使用offset伪操作符，这个操作在编译期而不是运行期完成。</p>
<p>mov       寄存器,offset 变量名</p>
<p>不可能用offset伪操作符来获取局部变量地址的原因是：</p>
<p>局部变量是用ebp来做指针访问的，由于ebp的值随着程序的执行环境不同可能是不同的，所以局部变量的地址值在编译期也是不确定的。</p>
<p>获取局部变量的地址使用lea指令</p>
<p>lea指令是80386处理器指令集中的一条指令。</p>
<p>lea eax,[ebp-4]</p>
<p>在invoke伪指令的参数中用到某个局部变量的地址，使用MASM提供的伪操作符addr。</p>
<p>格式为:</p>
<p>addr        局部变量名和全局变量名</p>
<p>addr伪操作符即可用于局部变量，也可用于全局变量</p>
<p>使用addr伪操作符需要注意以下几点：</p>
<p>a)         对局部变量取地址的时候，addr伪操作符只能用在invoke的参数中，不能用在如下的mov指令中。</p>
<p>mov eax,addr 局部变量名           ；这是错误的用法</p>
<p>因为在这句mov指令中，编译器无法把addr伪操作符替换成lea指令。</p>
<p>b)        当在invoke中使用addr伪操作符时，在addr伪操作符的左边不能使用eax寄存器，否则eax寄存器的值会被覆盖掉，当然eax寄存器用在addr伪操作符的右边的参数中是可以的。</p>
<p>MASM对于这种情况会报编译期错误。</p>
<p><strong>条件测试语句</strong></p>
<p>MASM的条件测试的语法和C语言相同。</p>
<p>同样，对于不含比较符的单个变量或寄存器，MASM也是将所有非零值认为是“真”，零值认为是“假”。</p>
<p>与C语言的条件测试相同，MASM的条件测试伪操作符并不会改变被测试的变量或寄存器的值。</p>
<p>MASM的条件测试伪操作符经过编译器编译会翻译成类似cmp或test之类的比较或位测试的指令。</p>
<p>MASM条件测试的基本表达式如下：</p>
<p>寄存器或变量       操作符    操作数</p>
<p>两个以上的表达式可以用逻辑运算符连接：</p>
<p>（表达式1）逻辑运算符（表达式2）逻辑运算符（表达式3）&#8230;</p>
<p>条件测试中的操作符和逻辑运算符如下表</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="189" valign="top">操作符和逻辑运算符</td>
<td width="98" valign="top">操作</td>
<td width="281" valign="top">用途</td>
</tr>
<tr>
<td width="189" valign="top">==</td>
<td width="98" valign="top">等于</td>
<td width="281" valign="top">变量和操作数之间的比较</td>
</tr>
<tr>
<td width="189" valign="top">!=</td>
<td width="98" valign="top">不等于</td>
<td width="281" valign="top">变量和操作数之间的比较</td>
</tr>
<tr>
<td width="189" valign="top">&gt;</td>
<td width="98" valign="top">大于</td>
<td width="281" valign="top">变量和操作数之间的比较</td>
</tr>
<tr>
<td width="189" valign="top">&gt;=</td>
<td width="98" valign="top">大于等于</td>
<td width="281" valign="top">变量和操作数之间的比较</td>
</tr>
<tr>
<td width="189" valign="top">&lt;</td>
<td width="98" valign="top">小于</td>
<td width="281" valign="top">变量和操作数之间的比较</td>
</tr>
<tr>
<td width="189" valign="top">&lt;=</td>
<td width="98" valign="top">小于等于</td>
<td width="281" valign="top">变量和操作数之间的比较</td>
</tr>
<tr>
<td width="189" valign="top">&amp;</td>
<td width="98" valign="top">位测试</td>
<td width="281" valign="top">将变量和操作数做“与”操作</td>
</tr>
<tr>
<td width="189" valign="top">!</td>
<td width="98" valign="top">逻辑取反</td>
<td width="281" valign="top">对变量取反或对表达式的结果取反</td>
</tr>
<tr>
<td width="189" valign="top">&amp;&amp;</td>
<td width="98" valign="top">逻辑与</td>
<td width="281" valign="top">对两个表达式的结果进行逻辑“与”操作</td>
</tr>
<tr>
<td width="189" valign="top">||</td>
<td width="98" valign="top">逻辑或</td>
<td width="281" valign="top">对两个表达式的结果进行逻辑“或”操作</td>
</tr>
</tbody>
</table>
<p>MASM的条件测试语句有如下几点限制：</p>
<p>a)         表达式的左边只能是变量或寄存器，不能为常数；</p>
<p>b)        表达式的两边不能同时为变量，但可以同时为寄存器；</p>
<p>这些限制来自于80&#215;86的指令。</p>
<p><strong>分支语句</strong></p>
<p>MASM中的分支伪指令的语法如下：</p>
<p>.if 条件表达式1</p>
<p>       表达式1为“真”时执行的指令</p>
<p>[.elseif 条件表达式2]</p>
<p>       表达式2为“真”时执行的指令</p>
<p>[.elseif 条件表达式3]</p>
<p>       表达式3为“真”时执行的指令</p>
<p>&#8230;</p>
<p>[.else]</p>
<p>       所有表达式为“否”时执行的指令</p>
<p>.endif</p>
<p>注意：</p>
<p>关键字if/elseif/else/endif的前面有个小数点，如果不加小数点，就变成宏汇编中的条件汇编伪操作。功能完全不一样。</p>
<p>if/else/endif是宏汇编中条件汇编宏操作的伪操作指令，作用是根据条件决定在最后的可执行文件中包不包括某一段代码。</p>
<p>由.if/.elseif/.else/.endif条件分支伪指令构成的分支结构只能有一个条件被满足。</p>
<p>如果需要构成的分支结构对于所有的表达式为“真”都要执行相应的代码，可以利用多个.if/endif来完成，如下：</p>
<p>.if    表达式1</p>
<p>       表达式1为“真”要执行的指令</p>
<p>.endif</p>
<p>.if    表达式2</p>
<p>       表达式2为“真”要执行的指令</p>
<p>.endif</p>
<p><strong>循环语句</strong></p>
<p>循环语句的语法如下：</p>
<p>.while 条件测试表达式</p>
<p>       指令</p>
<p>       [.break[.if 退出条件]]          ;如果.break伪指令后面跟一个.if测试伪指令的话，那么当退出条件为“真”时才执行.break伪指令。</p>
<p>       [.continue]</p>
<p>.endw</p>
<p>或</p>
<p>.repeat</p>
<p>       指令</p>
<p>       [.break[.if 退出条件]]          ;如果.break伪指令后面跟一个.if测试伪指令的话，那么当退出条件为“真”时才执行.break伪指令。</p>
<p>       [.continue]</p>
<p>.until 条件测试表达式（或.untilcxz [条件测试表达式]）</p>
<p>其中，.while/.break/.continue/.endw/.repeat/.until/.untilcxz都是伪指令。</p>
<p><em>循环体中可以使用.break伪指令强制退出循环</em>。</p>
<p><em>循环体中可以使用.continue伪指令忽略以后的指令。</em></p>
<p>.while/.endw和.repeat/.until的区别如下：</p>
<p>a)         前者可能一次也不会执行循环体内的指令，而后者至少会执行一次循环体内的指令。</p>
<p>b)        前者当判断条件为FALSE时退出循环，而后者当判断条件为TRUE时退出循环。</p>
<p>MASM的条件测试总是把操作数当作无符号数看待。</p>
<p>这就是说，在分支和循环的伪指令反汇编后可以发现，在使用&gt;,&gt;=,&lt;和&lt;=比较符时，MASM的伪指令总是将比较以后的跳转指令使用为jb和jnb等无符号数比较跳转的指令。</p>
<p>所以，如果程序中需要构造有符号数的比较分支或循环结构，那么必须另外用jl和jg等有符号数比较跳转的指令来完成，使用条件测试配合分支或循环伪指令可能会得到错误的结果</p>
</div>
<p><a href="http://17fav.com/?url=http%3A%2F%2Fwww.kaixinbc.com%2F2010%2F01%2Fmasm.html&title=MASM%E4%B8%AD%E6%A0%87%E5%8F%B7%E5%92%8C%E5%8F%98%E9%87%8F%E7%9A%84%E5%91%BD%E5%90%8D%E8%A7%84%E8%8C%83" title="用 17fav 收藏和分享本文"><img src="http://17fav.com/i/bookmark.gif" alt="17fav 收藏本文" /></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kaixinbc.com/2010/01/masm.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>最短路径 和 最小代价生成树</title>
		<link>http://www.kaixinbc.com/2010/01/min-lj.html</link>
		<comments>http://www.kaixinbc.com/2010/01/min-lj.html#comments</comments>
		<pubDate>Tue, 26 Jan 2010 02:52:43 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[数据结构]]></category>

		<guid isPermaLink="false">http://www.kaixinbc.com/?p=146</guid>
		<description><![CDATA[单源最短路径
Dijkstra 算法复杂度 O(V^2 + E)
有向加权图， 所有边非负
Bellman-Ford 算法复杂度O(VE)
有向加权图, 权可为负, 可存在负回路
代码         for (int i = 0; i &#60; N - 1; ++i)
            for (int j = 0; j &#60; SIZE; ++j)
                d[paths[j][1]] = min(d[paths[j][0]] + paths[j][2],d[paths[j][1]]);
        bool avbl = false;
        for (int j = 0; j &#60; SIZE; ++j)
            if (d[paths[j][1]] &#62; d[paths[j][0]] + paths[j][2])
            {
                avbl = true;
                break;
            };
每对节点的最短路径
Floyd-Warshall算法复杂度 O(V^3)
有向加权图, 权可为负, 但不存在负回路
代码         for (int k = 0; k &#60; currencies; ++k)
            for (int i = 0; i &#60; currencies; ++i)
                for (int j = 0; j &#60; currencies; ++j)
                    d[i][j] = max(d[i][k] * d[k][j],d[i][j]);
最小代价生成树
Prim 算法复杂度 O(V^2 + E) 实现与Dijkstra 类似
代码         //init for prim
        l[0] = 0;
        memset(used, 0, sizeof(used));
        used[0] = true;
        for (int i = 0; i &#60; lines; ++i) l[i] = d[0][i];
        for (int i = 1; i &#60; lines; ++i)
        {
            // select available V with min len
            int pos = 0;
            int len = 8;
            for (int j = 0; j &#60; lines; ++j)
                if (used[j] == false &#38;&#38;  len &#62; l[j])
                {
                    len = l[j];
                    pos = j;
                };
            //update l[]
            used[pos] = true;
            for (int j = 0; j &#60; lines; ++j)
                if (used[j] == false &#38;&#38; l[j] &#62; d[pos][j]) l[j] = d[pos][j];
        }
]]></description>
			<content:encoded><![CDATA[<p>单源最短路径</p>
<p>Dijkstra 算法复杂度 O(V^2 + E)</p>
<p>有向加权图， 所有边非负</p>
<p>Bellman-Ford 算法复杂度O(VE)</p>
<p>有向加权图, 权可为负, 可存在负回路</p>
<p>代码         for (int i = 0; i &lt; N - 1; ++i)<br />
            for (int j = 0; j &lt; SIZE; ++j)<br />
                d[paths[j][1]] = min(d[paths[j][0]] + paths[j][2],d[paths[j][1]]);</p>
<p>        bool avbl = false;<br />
        for (int j = 0; j &lt; SIZE; ++j)<br />
            if (d[paths[j][1]] &gt; d[paths[j][0]] + paths[j][2])<br />
            {<br />
                avbl = true;<br />
                break;<br />
            };</p>
<p>每对节点的最短路径</p>
<p>Floyd-Warshall算法复杂度 O(V^3)</p>
<p>有向加权图, 权可为负, 但不存在负回路</p>
<p>代码         for (int k = 0; k &lt; currencies; ++k)<br />
            for (int i = 0; i &lt; currencies; ++i)<br />
                for (int j = 0; j &lt; currencies; ++j)<br />
                    d[i][j] = max(d[i][k] * d[k][j],d[i][j]);</p>
<p>最小代价生成树</p>
<p>Prim 算法复杂度 O(V^2 + E) 实现与Dijkstra 类似</p>
<p>代码         //init for prim<br />
        l[0] = 0;<br />
        memset(used, 0, sizeof(used));<br />
        used[0] = true;<br />
        for (int i = 0; i &lt; lines; ++i) l[i] = d[0][i];</p>
<p>        for (int i = 1; i &lt; lines; ++i)<br />
        {<br />
            // select available V with min len<br />
            int pos = 0;<br />
            int len = 8;<br />
            for (int j = 0; j &lt; lines; ++j)<br />
                if (used[j] == false &amp;&amp;  len &gt; l[j])<br />
                {<br />
                    len = l[j];<br />
                    pos = j;<br />
                };</p>
<p>            //update l[]<br />
            used[pos] = true;<br />
            for (int j = 0; j &lt; lines; ++j)<br />
                if (used[j] == false &amp;&amp; l[j] &gt; d[pos][j]) l[j] = d[pos][j];</p>
<p>        }</p>
<p><a href="http://17fav.com/?url=http%3A%2F%2Fwww.kaixinbc.com%2F2010%2F01%2Fmin-lj.html&title=%E6%9C%80%E7%9F%AD%E8%B7%AF%E5%BE%84+%E5%92%8C+%E6%9C%80%E5%B0%8F%E4%BB%A3%E4%BB%B7%E7%94%9F%E6%88%90%E6%A0%91" title="用 17fav 收藏和分享本文"><img src="http://17fav.com/i/bookmark.gif" alt="17fav 收藏本文" /></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kaixinbc.com/2010/01/min-lj.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>贪心算法和动态规划</title>
		<link>http://www.kaixinbc.com/2010/01/txsf.html</link>
		<comments>http://www.kaixinbc.com/2010/01/txsf.html#comments</comments>
		<pubDate>Tue, 26 Jan 2010 02:51:19 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[数据结构]]></category>

		<guid isPermaLink="false">http://www.kaixinbc.com/?p=144</guid>
		<description><![CDATA[贪心算法
1．贪心选择性质
      所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择，即贪心选择来达到。这是贪心算法可行的第一个基本要素，也是贪心算法与动态规划算法的主要区别。在动态规划算法中，每步所作的选择往往依赖于相关子问题的解。因而只有在解出相关子问题后，才能作出选择。而在贪心算法中，仅在当前状态下作出最好选择，即局部最优选择。然后再去解作出这个选择后产生的相应的子问题。贪心算法所作的贪心选择可以依赖于以往所作过的选择，但决不依赖于将来所作的选择，也不依赖于子问题的解。正是由于这种差别，动态规划算法通常以自底向上的方式解各子问题，而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择，每作一次贪心选择就将所求问题简化为一个规模更小的子问题。
      对于一个具体问题，要确定它是否具有贪心选择性质，我们必须证明每一步所作的贪心选择最终导致问题的一个整体最优解。通常可以用我们在证明活动安排问题的贪心选择性质时所采用的方法来证明。首先考察问题的一个整体最优解，并证明可修改这个最优解，使其以贪心选择开始。而且作了贪心选择后，原问题简化为一个规模更小的类似子问题。然后，用数学归纳法证明，通过每一步作贪心选择，最终可得到问题的一个整体最优解。其中，证明贪心选择后的问题简化为规模更小的类似子问题的关键在于利用该问题的最优子结构性质。
2．最优子结构性质
      当一个问题的最优解包含着它的子问题的最优解时，称此问题具有最优子结构性质。问题所具有的这个性质是该问题可用动态规划算法或贪心算法求解的一个关键特征。在活动安排问题中，其最优子结构性质表现为：若a是对于正的活动安排问题包含活动1的一个最优解,则相容活动集合a’=a—{1}是对于e’={i∈e:si≥f1}的活动安排问题的一个最优解。
动态规划
动态规划的动机是消除递归过程中产生的大量重叠子问题, 两种方法 : 记忆化搜索 和 自底向上递推.
无后效性,决策只取决于当前状态的特征因素, 而和到达此状态的方式无关.
最优子结构, 在问题转化为子问题时, 原问题最优当且仅当子问题最优.
决策, 状态转移方程就是决策, 对于多阶段的决策问题, 如果具备最优子结构和无后效性, 就可以用动态规划来解决它
多阶段策略问题利用递归的思想, 把规模为n的问题转化为规模为n-1的问题, 直到转化为可以直接求解的原子问题. 一般情况下, 这样的递归方法的时间复杂度是指数级别的, 但是如果所有不同的子问题的数目是多项式级别的, 那么只需要多项式时间就可以解决这个问题, 这就是动态规划的本质. 动态规划算法有三个要素:
1) 所有不同的子问题所组成的表(他包含的问题数目成为问题的大小).
2)问题解决得依赖关系可以看成是一个图.
3) 填充子问题的顺序(实际上是2所得到的图的拓扑排序).
如果子问题数目为O(n^t), 且每个子问题需要依赖O(n^e)个其他子问题, 则称这个问题为tD/eD的.
方程一(1D/1D):最长上升子序列
定义一个实函数w(i, j)(1&#60;=i&#60;j&#60;=n)已知D[0], 状态转移方程为
E[j] = min{D[i] + w(i, j)}, 1&#60;=i&#60;j&#60;=n
其中D[i]可以根据E[i]在常数时间里计算出来.
方程二(2D/0D):最长公共子序列
已知D[i,0]和D[0,j](0&#60;=i, j&#60;=n), 状态转移方程为
E[i, j]=min{D[i-1,j]+xi, D[i,j-1]+yj, D[i-1][j-1]+zii}
其中xi, yj, zij都可以在常数时间里算出来
方程三(2D/1D)
定义实函数w(i, j)(1&#60;=i&#60;j&#60;=n), 已知d[i, i] = 0 (1&#60;=i&#60;=n), 状态转移方程为
C[i, j] = w(i, j) + [...]]]></description>
			<content:encoded><![CDATA[<p><strong>贪心算法</strong></p>
<p>1．贪心选择性质</p>
<p>      所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择，即贪心选择来达到。这是贪心算法可行的第一个基本要素，也是贪心算法与动态规划算法的主要区别。在动态规划算法中，每步所作的选择往往依赖于相关子问题的解。因而只有在解出相关子问题后，才能作出选择。而在贪心算法中，仅在当前状态下作出最好选择，即局部最优选择。然后再去解作出这个选择后产生的相应的子问题。贪心算法所作的贪心选择可以依赖于以往所作过的选择，但决不依赖于将来所作的选择，也不依赖于子问题的解。正是由于这种差别，动态规划算法通常以自底向上的方式解各子问题，而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择，每作一次贪心选择就将所求问题简化为一个规模更小的子问题。</p>
<p>      对于一个具体问题，要确定它是否具有贪心选择性质，我们必须证明每一步所作的贪心选择最终导致问题的一个整体最优解。通常可以用我们在证明活动安排问题的贪心选择性质时所采用的方法来证明。首先考察问题的一个整体最优解，并证明可修改这个最优解，使其以贪心选择开始。而且作了贪心选择后，原问题简化为一个规模更小的类似子问题。然后，用数学归纳法证明，通过每一步作贪心选择，最终可得到问题的一个整体最优解。其中，证明贪心选择后的问题简化为规模更小的类似子问题的关键在于利用该问题的最优子结构性质。</p>
<p>2．最优子结构性质</p>
<p>      当一个问题的最优解包含着它的子问题的最优解时，称此问题具有最优子结构性质。问题所具有的这个性质是该问题可用动态规划算法或贪心算法求解的一个关键特征。在活动安排问题中，其最优子结构性质表现为：若a是对于正的活动安排问题包含活动1的一个最优解,则相容活动集合a’=a—{1}是对于e’={i∈e:si≥f1}的活动安排问题的一个最优解。</p>
<p><strong>动态规划</strong></p>
<p>动态规划的动机是消除递归过程中产生的大量重叠子问题, 两种方法 : 记忆化搜索 和 自底向上递推.</p>
<p>无后效性,决策只取决于当前状态的特征因素, 而和到达此状态的方式无关.</p>
<p>最优子结构, 在问题转化为子问题时, 原问题最优当且仅当子问题最优.</p>
<p>决策, 状态转移方程就是决策, 对于多阶段的决策问题, 如果具备最优子结构和无后效性, 就可以用动态规划来解决它</p>
<p>多阶段策略问题利用递归的思想, 把规模为n的问题转化为规模为n-1的问题, 直到转化为可以直接求解的原子问题. 一般情况下, 这样的递归方法的时间复杂度是指数级别的, 但是如果所有不同的子问题的数目是多项式级别的, 那么只需要多项式时间就可以解决这个问题, 这就是动态规划的本质. 动态规划算法有三个要素:</p>
<p>1) 所有不同的子问题所组成的表(他包含的问题数目成为问题的大小).</p>
<p>2)问题解决得依赖关系可以看成是一个图.</p>
<p>3) 填充子问题的顺序(实际上是2所得到的图的拓扑排序).</p>
<p>如果子问题数目为O(n^t), 且每个子问题需要依赖O(n^e)个其他子问题, 则称这个问题为tD/eD的.</p>
<p>方程一(1D/1D):最长上升子序列</p>
<p>定义一个实函数w(i, j)(1&lt;=i&lt;j&lt;=n)已知D[0], 状态转移方程为</p>
<p>E[j] = min{D[i] + w(i, j)}, 1&lt;=i&lt;j&lt;=n</p>
<p>其中D[i]可以根据E[i]在常数时间里计算出来.</p>
<p>方程二(2D/0D):最长公共子序列</p>
<p>已知D[i,0]和D[0,j](0&lt;=i, j&lt;=n), 状态转移方程为</p>
<p>E[i, j]=min{D[i-1,j]+xi, D[i,j-1]+yj, D[i-1][j-1]+zii}</p>
<p>其中xi, yj, zij都可以在常数时间里算出来</p>
<p>方程三(2D/1D)</p>
<p>定义实函数w(i, j)(1&lt;=i&lt;j&lt;=n), 已知d[i, i] = 0 (1&lt;=i&lt;=n), 状态转移方程为</p>
<p>C[i, j] = w(i, j) + min{C[i,k-1] + C[k, j]},1&lt;=i&lt;j&lt;=n</p>
<p>方程四(2D/2D)</p>
<p>定义实函数w(i, j)(0&lt;=i&lt;j&lt;=2n), 已知D[i,0]和D[0,j](0&lt;=i, j&lt;=n),状态转移方程为</p>
<p>E[i, j] = min{D[i', j'] + w(i&#8217; + j&#8217;, i + j)}, 1&lt;=i, j&lt;=n</p>
<p>其中D[i, j]可以根据E[i, j]在常数时间里算出来</p>
<p>向前递推和向后递推:递归模型容易算出状态的前趋,适合顺推; 用多阶段决策建立模型, 容易算出状态后继, 适合逆推.</p>
<p>记忆化搜索, 自顶向下递归, 可以避免无用状态, 书写简单, 可以应用剪枝, 但是无法应用滚动数组等优化手段.</p>
<p>recursivefunc(i, j){</p>
<p>                if (calculated[i, j]) return memory[i, j];</p>
<p>                fill calculated[i, j] and memory[i, j]</p>
<p>                return memory[i, j]</p>
<p>}</p>
<p><a href="http://17fav.com/?url=http%3A%2F%2Fwww.kaixinbc.com%2F2010%2F01%2Ftxsf.html&title=%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95%E5%92%8C%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92" title="用 17fav 收藏和分享本文"><img src="http://17fav.com/i/bookmark.gif" alt="17fav 收藏本文" /></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kaixinbc.com/2010/01/txsf.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>基本数据结构</title>
		<link>http://www.kaixinbc.com/2010/01/jbjg.html</link>
		<comments>http://www.kaixinbc.com/2010/01/jbjg.html#comments</comments>
		<pubDate>Tue, 26 Jan 2010 02:50:22 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[数据结构]]></category>

		<guid isPermaLink="false">http://www.kaixinbc.com/?p=142</guid>
		<description><![CDATA[1. 队列
广度优先搜索
2. 堆栈
深度优先搜索
3. 二叉树，二叉搜索树 &#38; 平衡二叉搜索树
Binary Search
4. 哈希表
POJ 3349, Snowflake Snow Snowflakes
POJ 3274, Gold Balanced Lineup
POJ 1840, Eqs
POJ 2002, Squares
POJ 2503, Babelfish
5. 堆
POJ 3253, Fence Repair
6. Tries
POJ 2513, Colored Sticks
7. 并查集
POJ 2524, Ubiquitous Religions
POJ 2513, Colored Sticks
8. 线段树
]]></description>
			<content:encoded><![CDATA[<p>1. 队列</p>
<p>广度优先搜索</p>
<p>2. 堆栈</p>
<p>深度优先搜索</p>
<p>3. 二叉树，二叉搜索树 &amp; 平衡二叉搜索树</p>
<p>Binary Search</p>
<p>4. 哈希表</p>
<p>POJ 3349, Snowflake Snow Snowflakes</p>
<p>POJ 3274, Gold Balanced Lineup</p>
<p>POJ 1840, Eqs</p>
<p>POJ 2002, Squares</p>
<p>POJ 2503, Babelfish</p>
<p>5. 堆</p>
<p>POJ 3253, Fence Repair</p>
<p>6. Tries</p>
<p>POJ 2513, Colored Sticks</p>
<p>7. 并查集</p>
<p>POJ 2524, Ubiquitous Religions</p>
<p>POJ 2513, Colored Sticks</p>
<p>8. 线段树</p>
<p><a href="http://17fav.com/?url=http%3A%2F%2Fwww.kaixinbc.com%2F2010%2F01%2Fjbjg.html&title=%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84" title="用 17fav 收藏和分享本文"><img src="http://17fav.com/i/bookmark.gif" alt="17fav 收藏本文" /></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kaixinbc.com/2010/01/jbjg.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>数据结构 栈的顺序存储结构</title>
		<link>http://www.kaixinbc.com/2010/01/sjjg-zhan.html</link>
		<comments>http://www.kaixinbc.com/2010/01/sjjg-zhan.html#comments</comments>
		<pubDate>Tue, 26 Jan 2010 02:49:04 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[数据结构]]></category>

		<guid isPermaLink="false">http://www.kaixinbc.com/?p=140</guid>
		<description><![CDATA[栈是一种特殊的线性表，所以在前面讨论的线性表的各种存储结构都可以作为栈的存储结构，因此，栈也有两种存储表示方法：顺序存储和链式存储。
   栈的顺序结构简称顺序栈，是利用一组地址连续的存储单元一次存放紫栈底到栈顶的数据元素，同时附设指针top指示栈顶元素在顺序栈中的位置。用一维数组表示栈的顺序存储结构，一般以top=0表示空栈，由于C语言中数组的小标约定从0开始，因此用C做描述语言时，这样设定会带来很大不便，因此用top=-1表示栈空，顺序存储结构可表示为：
   typedey struct
{
    int stacksize;
datatype *bottom;
datatype *top;
}SqlStack; //顺序栈类型定义
Sqlstack *S//S是顺序栈类型指针
   其中stacksize 是指栈的当前可使用的最大容量，top为栈顶指针，其初值指向栈顶，即top=-1可作为栈空的标记，每当插入新的站定元素时，指针top增加1，删除栈顶元素时，top减1.
约定top指向真正的栈顶位置上面的一个空单元，即新数据将要插入的位置。
置空栈的操作（栈的初始化）
Initstack(seqstack *s)
{
s-&#62;top=0;
   s-&#62;base=0;
}
判栈空操作
   int Empty(seqstack *s)
{
   if(s-&#62;top==s-&#62;base)
       return true;
   else
       return false;
}
进栈操作
datatype Push(seqstack *s,datatype x)//将元素x插入顺序栈s的顶部
{
     if(s-&#62;top==maxsize)
       {
           printf(&#8220;overflow&#8221;);
                return NULL;
        }
    else
      {
         s-&#62;data[s-&#62;top]=x;
         s-&#62;top++;
       }
return true;
}
出栈操作
datatype Pop(seqstack *s,datatype e)//若栈非空，删除栈顶元素，用e返回其值
{
if(Empty(s))
{
printf(&#8220;underflow&#8221;);return NULL;
}
else
{
s-&#62;top&#8211;;
e=s-&#62;data[s-&#62;top];
return (e);
}
}
取栈顶操作
datatype GetTop(seqstack *s)
{
if(Empty(s))
{
printf(&#8220;stack is empty&#8221;);//空栈
return NULL;
}
else
return (s-&#62;data[s-&#62;(top-1)]);
}
      在实际工作中可能会用到多个栈，在使用一个数组存储栈时。数组中一般都会有剩余 的空间，如果给每个栈都定义一个数组，则有时会出现一个栈上溢，而另一个栈剩余很多空间的情况。为了合理地使用这些存储单元，可以采用将多个栈存储在同一数组中的方法，即多栈共享空间。
     假设两个栈共享一个一维数组s【0，。。。。maxsize-1】，根据栈操作的特点，可使第一个栈使用数组空间的前面空间，并使栈底在前，而使用第二个栈使用数组空间的后面部分，并使栈底在后。
   这样处理可以使两个栈最大限度地使用数组空间，下面给出这种空间存储结构的定义：
   typedef datatype [...]]]></description>
			<content:encoded><![CDATA[<p>栈是一种特殊的线性表，所以在前面讨论的线性表的各种存储结构都可以作为栈的存储结构，因此，栈也有两种存储表示方法：顺序存储和链式存储。</p>
<p>   栈的顺序结构简称顺序栈，是利用一组地址连续的存储单元一次存放紫栈底到栈顶的数据元素，同时附设指针top指示栈顶元素在顺序栈中的位置。用一维数组表示栈的顺序存储结构，一般以top=0表示空栈，由于C语言中数组的小标约定从0开始，因此用C做描述语言时，这样设定会带来很大不便，因此用top=-1表示栈空，顺序存储结构可表示为：</p>
<p>   typedey struct</p>
<p>{</p>
<p>    int stacksize;</p>
<p>datatype *bottom;</p>
<p>datatype *top;</p>
<p>}SqlStack; //顺序栈类型定义</p>
<p>Sqlstack *S//S是顺序栈类型指针</p>
<p>   其中stacksize 是指栈的当前可使用的最大容量，top为栈顶指针，其初值指向栈顶，即top=-1可作为栈空的标记，每当插入新的站定元素时，指针top增加1，删除栈顶元素时，top减1.</p>
<p>约定top指向真正的栈顶位置上面的一个空单元，即新数据将要插入的位置。</p>
<p>置空栈的操作（栈的初始化）</p>
<p>Initstack(seqstack *s)</p>
<p>{</p>
<p>s-&gt;top=0;</p>
<p>   s-&gt;base=0;</p>
<p>}</p>
<p>判栈空操作</p>
<p>   int Empty(seqstack *s)</p>
<p>{</p>
<p>   if(s-&gt;top==s-&gt;base)</p>
<p>       return true;</p>
<p>   else</p>
<p>       return false;</p>
<p>}</p>
<p>进栈操作</p>
<p>datatype Push(seqstack *s,datatype x)//将元素x插入顺序栈s的顶部</p>
<p>{</p>
<p>     if(s-&gt;top==maxsize)</p>
<p>       {</p>
<p>           printf(&#8220;overflow&#8221;);</p>
<p>                return NULL;</p>
<p>        }</p>
<p>    else</p>
<p>      {</p>
<p>         s-&gt;data[s-&gt;top]=x;</p>
<p>         s-&gt;top++;</p>
<p>       }</p>
<p>return true;</p>
<p>}</p>
<p>出栈操作</p>
<p>datatype Pop(seqstack *s,datatype e)//若栈非空，删除栈顶元素，用e返回其值<br />
{<br />
if(Empty(s))<br />
{<br />
printf(&#8220;underflow&#8221;);return NULL;<br />
}<br />
else<br />
{<br />
s-&gt;top&#8211;;<br />
e=s-&gt;data[s-&gt;top];<br />
return (e);<br />
}<br />
}</p>
<p>取栈顶操作</p>
<p>datatype GetTop(seqstack *s)<br />
{<br />
if(Empty(s))<br />
{<br />
printf(&#8220;stack is empty&#8221;);//空栈<br />
return NULL;<br />
}<br />
else<br />
return (s-&gt;data[s-&gt;(top-1)]);<br />
}</p>
<p>      在实际工作中可能会用到多个栈，在使用一个数组存储栈时。数组中一般都会有剩余 的空间，如果给每个栈都定义一个数组，则有时会出现一个栈上溢，而另一个栈剩余很多空间的情况。为了合理地使用这些存储单元，可以采用将多个栈存储在同一数组中的方法，即多栈共享空间。</p>
<p>     假设两个栈共享一个一维数组s【0，。。。。maxsize-1】，根据栈操作的特点，可使第一个栈使用数组空间的前面空间，并使栈底在前，而使用第二个栈使用数组空间的后面部分，并使栈底在后。</p>
<p>   这样处理可以使两个栈最大限度地使用数组空间，下面给出这种空间存储结构的定义：</p>
<p>   typedef datatype int //栈元素的数据类型</p>
<p>#define maxsize 64;</p>
<p>typedef struct</p>
<p>{</p>
<p>    datatype data[maxsize];</p>
<p>   int top1,top2;</p>
<p>}dstack;</p>
<p>设栈s1和s2共享空间s，s1从前向后存放，s2从后向前存放，top1和top2分别是s1和s2的栈顶指针，则在这种存储结构中初始化，进栈，出栈操作算法如下。</p>
<p>初始化操作</p>
<p>InitDstack(dstack *s)</p>
<p>{</p>
<p>    s-&gt;top1=0;</p>
<p>    s-&gt;top2=maxsize-1;</p>
<p>}</p>
<p>进栈操作</p>
<p>PushDstack(dstack *s ,char ch,datatype x)//把数据元素x压入栈s的左栈或右栈</p>
<p>    {<br />
if (s-&gt;top2-s-&gt;top1==1) return 0;//栈已满<br />
if(ch==&#8217;s1&#8242;)<br />
{<br />
   s-&gt;data[s-&gt;top1]=x;<br />
   s-&gt;top1=s-&gt;top1+1;<br />
   return 1;<br />
}//进入栈s1；<br />
if (ch==&#8217;s2&#8242;)<br />
{<br />
   s-&gt;data[s-&gt;top2]=x;<br />
   s-&gt;top2=s-&gt;top2-1;<br />
   return 1;<br />
}//进入栈s2<br />
}   </p>
<p>出栈操作</p>
<p>PopDstack(dstack *s,char ch)<br />
{<br />
//从栈s1或s2取出栈顶元素并返回其值<br />
if(char==&#8217;s1&#8242;)<br />
{<br />
if(s-&gt;top1==0) return NULL;//栈s1已空<br />
     else<br />
{<br />
   s-&gt;top1=s-&gt;top1-1;<br />
   return (s-&gt;data[s-&gt;top1]);<br />
}<br />
}<br />
if(char==&#8217;s2&#8242;)<br />
{<br />
if(s-&gt;top2&gt;maxsize-1) return NULL;<br />
else<br />
{<br />
   s-&gt;top2=s-&gt;top2+1;<br />
   return (s-&gt;data[s-&gt;top2]);<br />
}<br />
}//s2出栈</p>
<p>}</p>
<p>关于3个或3个以上的栈共享一个数组空间的情况，由于可能需要移动中间某个在数组中的相对位置，处理起来不很方便，因为一般不采用。</p>
<p>栈的链式存储结构，</p>
<p>栈的链式存储结构也称为链栈，它是运算受限制的单链表，其插入和删除操作仅限于在表头位置进行，由于只能在链表的头部进行操作，所以没有必要再附加头结点，链栈的栈顶指针就是链表的头指针。</p>
<p>链栈是单链表的特例。所以其类型和变量的说明和单链表一样。</p>
<p>top是栈顶指针，它唯一地确定一个链栈，当top=NULL时，该链表是空栈，</p>
<p>进栈操作</p>
<p>当需要一个新元素w插入链栈时，可动态地向系统申请一个结点p的存储空间，将新元素w写入新结点p的数据域，将栈顶指针top的值写入p结点的指针域。使原栈顶结点成为新结点p的直接后继结点，栈顶指针top改为指向p结点。</p>
<p>linkstack *PushLinkStack(linkstack *top,datatype w)//将元素w插入链表top的栈顶。</p>
<p>{<br />
linkstack *p;<br />
p=(linkstack *)malloc(sizeof(linkstack));<br />
p-&gt;data=w;<br />
p-&gt;next=top;<br />
top=p;<br />
return p;<br />
}</p>
<p>出栈操作</p>
<p>当栈顶元素出栈时，先取出栈顶元素的值，将栈顶指针top指向top结点的直接后继结点，释放原栈顶结点。</p>
<p>linkstack *PopLinkStack(linkstack *top,datatype *x)//删除链栈top的栈顶结点让x指向栈顶结点的值，返回新栈指针</p>
<p>{<br />
linkstack*p;<br />
if(top==NULL)<br />
{<br />
printf(&#8220;空栈，下溢&#8221;);return NULL;<br />
}<br />
    else<br />
{<br />
*x=top-&gt;data;//将栈顶数据存入*x<br />
p=top;//保存栈顶结点地址<br />
top=top-&gt;Next;//删除原栈顶结点。<br />
free(p);//释放原栈顶结点。<br />
return top;//返回新栈顶指针。<br />
}<br />
}</p>
<p>置空栈</p>
<p>   void InitStack(linkstack *S)</p>
<p>{</p>
<p>s=NULL;</p>
<p>}</p>
<p>判空栈</p>
<p>     int StackEmpty(linkstack *S)<br />
{</p>
<p>if(S==NULL) return 1;</p>
<p>else</p>
<p>return 0;<br />
}</p>
<p>去栈顶元素</p>
<p>datatype StackTop(linkstack *S)</p>
<p>{</p>
<p>     if(StackEmpty(S))</p>
<p>{Error(&#8220;Stack is empty&#8221;); return NULL;}</p>
<p>return S-&gt;data;</p>
<p>}</p>
<p>顺序栈和链式栈的比较</p>
<p>   实现顺序栈和链式栈的所有操作的时间相同，都是常数级的时间，但初始化一个顺序栈必须先声明一个固定长度。这样在栈不够满时。就浪费了一部分存储空间，而链式栈不存在这个问题。</p>
<p>   但可以利用顺序栈的这一特性同时实现两个栈，使用一个数组存储两个栈，每个栈从各自的端点向中间延伸，这样就节约了空间。只有当整个向量空间被两个栈占满（即两个栈顶相遇时）才发生上溢，因此，两个栈共享一个长度为m的向量空间和两个栈分别占用两个长度为m/2和m/2的向量空间比较，前者发生上溢的概率比后者要小的多。</p>
<p><a href="http://17fav.com/?url=http%3A%2F%2Fwww.kaixinbc.com%2F2010%2F01%2Fsjjg-zhan.html&title=%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84+%E6%A0%88%E7%9A%84%E9%A1%BA%E5%BA%8F%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84" title="用 17fav 收藏和分享本文"><img src="http://17fav.com/i/bookmark.gif" alt="17fav 收藏本文" /></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kaixinbc.com/2010/01/sjjg-zhan.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>算法效率的度量和存储空间需求</title>
		<link>http://www.kaixinbc.com/2010/01/sf.html</link>
		<comments>http://www.kaixinbc.com/2010/01/sf.html#comments</comments>
		<pubDate>Tue, 26 Jan 2010 02:45:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[数据结构]]></category>

		<guid isPermaLink="false">http://www.kaixinbc.com/?p=137</guid>
		<description><![CDATA[一、算法效率的度量
算法执行的时间是算法优劣和问题规模的函数。评价一个算法的优劣，可以在相同的规模下，考察算法执行时间的长短来进行判断。而一个程序的执行时间通常有两种方法：
1、事后统计的方法。
缺点：不利于较大范围内的算法比较。（异地，异时，异境）
2、事前分析估算的方法。





程序在计算机上运行所需时间的影响因素



算法本身选用的策略
 


问题的规模
规模越大，消耗时间越多


书写程序的语言
语言越高级，消耗时间越多


编译产生的机器代码质量
 


机器执行指令的速度
 



综上所述，为便于比较算法本身的优劣，应排除其它影响算法效率的因素。
从算法中选取一种对于所研究的问题来说是基本操作的原操作，以该基本操作重复执行的次数作为算法的时间量度。 （原操作在所有该问题的算法中都相同）
T(n)=O(f(n))
上示表示随问题规模n的增大，算法执行时间的增长率和f(n)的增长率相同，称作算法的渐近时间复杂度，简称时间复杂度。




求4*4矩阵元素和，T(4)=O(f(4))
f=n*n;
sum(int num[4][4])
{ int i,j,r=0;
for(i=0;i&#60;4;i++)
for(j=0;j&#60;4;j++)
r+=num[i][j]; /*原操作*/

return r;
}


最好情况：
T（4）=O（0）
最坏情况：
T（4）=O（n*n）
ispass(int num[4][4])
{ int i,j;
for(i=0;i&#60;4;i++)
for(j=0;j&#60;4;j++)
if(num[i][j]!=i*4+j+1)
return 0;


return 1;
}



原操作执行次数和包含它的语句的频度相同。语句的频度指的是该语句重复执行的次数。




语句


频度


时间复杂度



{++x;s=0;}

1


O(1)



for(i=1;i&#60;=n;++i)
{++x;s+=x;}


n


O(n)



for(j=1;j&#60;=n;++j)
for(k=1;k&#60;=n;++k)
{++x;s+=x;}



n*n


O(n*n)



 
 

O(log n)



 
 







 




基本操作的执行次数不确定时的时间复杂度



平均时间复杂度
依基本操作执行次数概率计算平均


最坏情况下时间复杂度
在最坏情况下基本操作执行次数



 

二、算法的存储空间需求
类似于算法的时间复杂度，空间复杂度可以作为算法所需存储空间的量度。
记作：
S(n)=O(f(n))
若额外空间相对于输入数据量来说是常数，则称此算法为原地工作。
如果所占空间量依赖于特定的输入，则除特别指明外，均按最坏情况来分析。
三、总结
渐近时间复杂度
空间复杂度
]]></description>
			<content:encoded><![CDATA[<p>一、算法效率的度量</p>
<blockquote><p>算法执行的时间是算法优劣和问题规模的函数。评价一个算法的优劣，可以在相同的规模下，考察算法执行时间的长短来进行判断。而一个程序的执行时间通常有两种方法：</p>
<p>1、事后统计的方法。</p>
<blockquote><p>缺点：不利于较大范围内的算法比较。（异地，异时，异境）</p></blockquote>
<p>2、事前分析估算的方法。</p>
<blockquote>
<table border="1" cellspacing="0" width="500">
<tbody>
<tr bgcolor="#ffcccc">
<td colspan="2">
<div>程序在计算机上运行所需时间的影响因素</div>
</td>
</tr>
<tr>
<td width="215">算法本身选用的策略</td>
<td width="275"> </td>
</tr>
<tr>
<td width="215">问题的规模</td>
<td width="275">规模越大，消耗时间越多</td>
</tr>
<tr>
<td width="215">书写程序的语言</td>
<td width="275">语言越高级，消耗时间越多</td>
</tr>
<tr>
<td width="215">编译产生的机器代码质量</td>
<td width="275"> </td>
</tr>
<tr>
<td width="215">机器执行指令的速度</td>
<td width="275"> </td>
</tr>
</tbody>
</table>
<p>综上所述，为便于比较算法本身的优劣，应排除其它影响算法效率的因素。</p>
<p>从算法中选取一种对于所研究的问题来说是基本操作的<span style="color: #cc00cc;">原操作</span>，以该基本操作重复执行的次数作为算法的时间量度。 （原操作在所有该问题的算法中都相同）</p>
<p><span style="font-size: xx-small;"><em>T</em></span>(n)=<em><span style="font-size: xx-small;">O</span></em>(f(<span>n</span>))</p>
<p>上示表示随问题规模n的增大，算法执行时间的增长率和f(n)的增长率相同，称作算法的<span style="color: #ff3333;"><strong>渐近时间复杂度</strong></span>，简称<span style="color: #ff3333;"><strong>时间复杂度</strong></span>。</p></blockquote>
<blockquote>
<table border="1" cellspacing="0" width="481">
<tbody>
<tr>
<td width="131">求4*4矩阵元素和，T(4)=O(f(4))</p>
<p>f=n*n;</td>
<td width="340" bgcolor="#ccccff">sum(int num[4][4])</p>
<p>{ int i,j,r=0;<br />
for(i=0;i&lt;4;i++)</p>
<blockquote><p>for(j=0;j&lt;4;j++)</p>
<blockquote><p>r+=num[i][j]; /*<span style="color: #cc00cc;">原操作</span>*/</p></blockquote>
</blockquote>
<p>return r;<br />
}</td>
</tr>
<tr>
<td width="131">最好情况：<br />
T（4）=O（0）</p>
<p>最坏情况：<br />
T（4）=O（n*n）</td>
<td width="340" bgcolor="#009999">ispass(int num[4][4])</p>
<p>{ int i,j;<br />
for(i=0;i&lt;4;i++)</p>
<blockquote><p>for(j=0;j&lt;4;j++)</p>
<blockquote><p>if(num[i][j]!=i*4+j+1)</p>
<blockquote><p>return 0;</p></blockquote>
</blockquote>
</blockquote>
<p>return 1;<br />
}</td>
</tr>
</tbody>
</table>
<p>原操作执行次数和包含它的语句的<span style="color: #ff0000;">频度</span>相同。语句的<span style="color: #ff0033;">频度</span>指的是该语句重复执行的次数。</p>
<table border="1" cellspacing="0" width="478">
<tbody>
<tr bgcolor="#ffcccc">
<td width="252">
<div>语句</div>
</td>
<td width="60">
<div>频度</div>
</td>
<td width="152">
<div>时间复杂度</div>
</td>
</tr>
<tr>
<td width="252">{++x;s=0;}</td>
<td width="60">
<div>1</div>
</td>
<td width="152">
<div>O(1)</div>
</td>
</tr>
<tr>
<td width="252">for(i=1;i&lt;=n;++i)</p>
<blockquote><p>{++x;s+=x;}</p></blockquote>
</td>
<td width="60">
<div>n</div>
</td>
<td width="152">
<div>O(n)</div>
</td>
</tr>
<tr>
<td width="252" height="63">for(j=1;j&lt;=n;++j)</p>
<blockquote><p>for(k=1;k&lt;=n;++k)</p>
<blockquote><p>{++x;s+=x;}</p></blockquote>
</blockquote>
</td>
<td width="60" height="63">
<div>n*n</div>
</td>
<td width="152" height="63">
<div>O(n*n)</div>
</td>
</tr>
<tr>
<td width="252"> </td>
<td width="60"> </td>
<td width="152">
<div>O(log n)</div>
</td>
</tr>
<tr>
<td width="252" height="37"> </td>
<td width="60" height="37"> </td>
<td width="152" height="37">
<div>
<span style="font-size: xx-small;"><img src="http://www.bccn.net/Article/UploadFDL0024/200411/20041112070431488.jpg" alt="" width="39" height="21" /></span></div>
</td>
</tr>
</tbody>
</table>
<p> </p>
<table border="1" cellspacing="0" width="481">
<tbody>
<tr bgcolor="#ffcccc">
<td colspan="2" height="28">
<div>基本操作的执行次数不确定时的时间复杂度</div>
</td>
</tr>
<tr>
<td width="211" height="30" bgcolor="#ccccff">平均时间复杂度</td>
<td width="260" height="30">依基本操作执行次数概率计算平均</td>
</tr>
<tr>
<td width="211" height="31" bgcolor="#ccccff">最坏情况下时间复杂度</td>
<td width="260" height="31">在最坏情况下基本操作执行次数</td>
</tr>
</tbody>
</table>
<p> </p></blockquote>
</blockquote>
<p>二、算法的存储空间需求</p>
<blockquote><p>类似于算法的时间复杂度，空间复杂度可以作为算法所需存储空间的量度。</p>
<p>记作：</p>
<p><span style="font-size: xx-small;"><em>S</em></span>(n)=<span style="font-size: xx-small;"><em>O</em></span>(<em>f</em><span>(n)</span>)</p>
<p>若额外空间相对于输入数据量来说是常数，则称此算法为<strong>原地工作</strong>。</p>
<p>如果所占空间量依赖于特定的输入，则除特别指明外，均按最坏情况来分析。</p></blockquote>
<p>三、总结</p>
<blockquote><p>渐近时间复杂度</p>
<p>空间复杂度</p></blockquote>
<p><a href="http://17fav.com/?url=http%3A%2F%2Fwww.kaixinbc.com%2F2010%2F01%2Fsf.html&title=%E7%AE%97%E6%B3%95%E6%95%88%E7%8E%87%E7%9A%84%E5%BA%A6%E9%87%8F%E5%92%8C%E5%AD%98%E5%82%A8%E7%A9%BA%E9%97%B4%E9%9C%80%E6%B1%82" title="用 17fav 收藏和分享本文"><img src="http://17fav.com/i/bookmark.gif" alt="17fav 收藏本文" /></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kaixinbc.com/2010/01/sf.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
