﻿<?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="https://www.softwareace.cn/?cat=24&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>https://www.softwareace.cn</link>
	<description>时刻想着为自己的产品多做一些对他好的事情</description>
	<lastBuildDate>Fri, 20 Mar 2026 06:58:28 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	
	<item>
		<title>XOR加密</title>
		<link>https://www.softwareace.cn/?p=676</link>
		<comments>https://www.softwareace.cn/?p=676#comments</comments>
		<pubDate>Tue, 07 Jan 2014 01:23:28 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=676</guid>
		<description><![CDATA[[代替密码和换位密码] 在计算机出现前，密码学由基于字符的密码算法构成。不同的密码算法是字符之间互相代替 或者 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><strong>[代替密码和换位密码]</strong><br />
在计算机出现前，密码学由基于字符的密码算法构成。不同的密码算法是字符之间互相<strong>代替</strong> 或者互相之间<strong>换位</strong> ，好的密码算法是结合这两种方法，每次进行多次运算。现在的密码学变得复杂了，但原理没有改变。<strong>本质的变化是</strong> ：算法对位而不是对字母进行变换。实际上这只是字母表长度上的改变，从26个元素变为<strong>2个元素</strong> 。大多数好的密码算法仍然是代替和换位的元素组合。</p>
<p><strong>[简单异或]</strong><br />
下面是一个简单异或的对称加解密算法。明文用一个关键字做异或运算以产生密文。因为用同一值去<strong>异或两次就可以恢复出原来的值</strong> ，所以加密和解密都严格采用同一程序。即：<br />
P XOR K = C<br />
C XOR K = P<br />
这种方法比较简单，没有实际的保密性，甚至没有计算机也能够破译。<br />
一种思路是使用<strong>重合码计数法</strong> 找出密钥的长度，按此长度移动密文，并且和自身异或。</p>
<p><strong>[异或的好处]</strong><br />
在算法中经常会用到异或运算。比如下面两种常见的情况：<br />
(1) 在1,1,2,2,3,3&#8230;k,k&#8230;n,n个数的序列中，删除任意一数并求此数。<br />
此时用XOR就比较方便，如果通过求和的话，要考虑溢出的情况，而用XOR绝对不会发生溢出。<br />
(2) 交换两个整形变量。<br />
x^=y;<br />
y^=x;<br />
x^=y;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>运行结果：</p>
<p><img alt="pic" src="http://hi.csdn.net/attachment/201010/4/45214_12862039916ssu.jpg" width="531" height="210" /></p>
<p>&nbsp;</p>
<p>PS: 老邓的写法，也记录在这里</p>
<p>01.#include &lt;iostream&gt;<br />
02.using namespace std;<br />
03.int main()<br />
04.{<br />
05.    char Msg[133] = &#8220;This is a plaintext&#8221;;<br />
06.    cout &lt;&lt; Msg &lt;&lt; endl;<br />
07.    char Key[8] = &#8220;abcde&#8221;;<br />
08.    for (int i = 0; i &lt; 133; ++i)<br />
09.        Msg[i] ^= Key[i % 8];<br />
10.    cout &lt;&lt; Msg &lt;&lt; endl;<br />
11.    for (int i = 0; i &lt; 133; ++i)<br />
12.        Msg[i] ^= Key[i % 8];<br />
13.    cout &lt;&lt; Msg &lt;&lt; endl;<br />
14.    return 0;<br />
15.}</p>
<p>from <a href="http://blog.csdn.net/delphiwcdj/article/details/5921771#comments">http://blog.csdn.net/delphiwcdj/article/details/5921771#comments</a></p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=676</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>C++加密解密函数及用法示例</title>
		<link>https://www.softwareace.cn/?p=575</link>
		<comments>https://www.softwareace.cn/?p=575#comments</comments>
		<pubDate>Tue, 17 Sep 2013 06:30:52 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=575</guid>
		<description><![CDATA[[crayon-69f6bbdc2d787070665168/] &#160;]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">// 常量
#define C1 52845
#define C2 22719
CString Encrypt(CString S, WORD Key) // 加密函数
{
CString Result,str;
int i,j;

Result=S; // 初始化结果字符串
for(i=0; i&lt;S.GetLength(); i++) // 依次对字符串中各字符进行操作
{
   Result.SetAt(i, S.GetAt(i)^(Key&gt;&gt;8)); // 将密钥移位后与字符异或
   Key = ((BYTE)Result.GetAt(i)+Key)*C1+C2; // 产生下一个密钥
}
S=Result; // 保存结果
Result.Empty(); // 清除结果
for(i=0; i&lt;S.GetLength(); i++) // 对加密结果进行转换
{
   j=(BYTE)S.GetAt(i); // 提取字符
   // 将字符转换为两个字母保存
   str="12"; // 设置str长度为2
   str.SetAt(0, 65+j/26);//这里将65改大点的数例如256，密文就会变乱码，效果更好，相应的，解密处要改为相同的数
   str.SetAt(1, 65+j%26);
   Result += str;
}
return Result;
}

CString Decrypt(CString S, WORD Key) // 解密函数
{
CString Result,str;
int i,j;

Result.Empty(); // 清除结果
for(i=0; i &lt; S.GetLength()/2; i++) // 将字符串两个字母一组进行处理
{
   j = ((BYTE)S.GetAt(2*i)-65)*26;);//相应的，解密处要改为相同的数

   j += (BYTE)S.GetAt(2*i+1)-65;
   str="1"; // 设置str长度为1
   str.SetAt(0, j);
   Result+=str; // 追加字符，还原字符串
}
S=Result; // 保存中间结果
for(i=0; i&lt;S.GetLength(); i++) // 依次对字符串中各字符进行操作
{
   Result.SetAt(i, (BYTE)S.GetAt(i)^(Key&gt;&gt;8)); // 将密钥移位后与字符异或
   Key = ((BYTE)S.GetAt(i)+Key)*C1+C2; // 产生下一个密钥
}
return Result;
}
用法
CString text=_T("192.168.18.14");//需要加密的字符串
WORD key=1314;//key
CString jiami=Encrypt(text,key);//加密
AfxMessageBox(_T("密文:")+jiami);
CString jiemi=Decrypt(jiami,key);//解密
AfxMessageBox(_T("原文:")+jiemi);</pre><p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=575</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>个人所得税计算</title>
		<link>https://www.softwareace.cn/?p=174</link>
		<comments>https://www.softwareace.cn/?p=174#comments</comments>
		<pubDate>Tue, 19 Feb 2013 01:14:46 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=174</guid>
		<description><![CDATA[[crayon-69f6bbdc2e074185715953/]]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt; 
using namespace std; 
int main( ) 
{ 
    double dSalary ,dTax =0,dNetIncome=0; 
    cout&amp;lt;&amp;lt;&amp;quot;请输入您本月的收入总额（元）:&amp;quot;; 
    cin&amp;gt;&amp;gt;dSalary; 
    if(dSalary&amp;lt;3500) 
        cout&amp;lt;&amp;lt;&amp;quot;您不需要缴纳个人所得税:&amp;quot;&amp;lt;&amp;lt;endl; 
    else 
    { 
        if(dSalary&amp;gt;=3500&amp;amp;&amp;amp;dSalary&amp;lt;5000) 
            dTax=(dSalary-3500)*0.03-0; 
        if(dSalary&amp;gt;=5000&amp;amp;&amp;amp;dSalary&amp;lt;8000) 
            dTax=(dSalary-3500)*0.1-105; 
        if(dSalary&amp;gt;=8000&amp;amp;&amp;amp;dSalary&amp;lt;12500) 
            dTax=(dSalary-3500)*0.2-555; 
        if(dSalary&amp;gt;=12500&amp;amp;&amp;amp;dSalary&amp;lt;38500) 
            dTax=(dSalary-3500)*0.25-1005; 
        if(dSalary&amp;gt;=38500&amp;amp;&amp;amp;dSalary&amp;lt;58500) 
            dTax=(dSalary-3500)*0.3-2755; 
        if(dSalary&amp;gt;=58500&amp;amp;&amp;amp;dSalary&amp;lt;83500) 
            dTax=(dSalary-3500)*0.35-5505; 
        if(dSalary&amp;gt;=83500) 
            dTax=(dSalary-3500)*0.45-13505; 
    } 
    dNetIncome=dSalary-dTax; 
    cout&amp;lt;&amp;lt;&amp;quot;您本月应缴纳个人所得税&amp;quot;&amp;lt;&amp;lt;dTax&amp;lt;&amp;lt;&amp;quot;元,税后收入是&amp;quot;&amp;lt;&amp;lt;dNetIncome&amp;lt;&amp;lt;&amp;quot;元。n&amp;quot;; 
    cout&amp;lt;&amp;lt;&amp;quot;依法纳税，共享繁荣！谢谢使用！n&amp;quot;; 
    return 0; 
}</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=174</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>快速排序（QuickSort)</title>
		<link>https://www.softwareace.cn/?p=172</link>
		<comments>https://www.softwareace.cn/?p=172#comments</comments>
		<pubDate>Sat, 16 Feb 2013 05:28:28 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=172</guid>
		<description><![CDATA[快速排序(QuickSort)也是一种排序算法，对包含n个数组的输入数组，最坏情况运行时间为O(n^2)。虽然 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
	<span style="FONT-SIZE: 18px">快速排序(QuickSort)也是一种排序算法，对包含n个数组的输入数组，最坏情况运行时间为O(n^2)。虽然这个最坏情况运行时间比较差，但是快速排序通常是用于排序的最佳实用选择，这是因为其平均性能相当好，期望的运行时间为O(nlgn)，且O(nlgn)中隐含的常数因子很小，另外它还能够进行就地排序在虚拟环境中也能很好的工作。</span></p>
<p>
	<span style="FONT-SIZE: 18px">一、快速排序原理</span></p>
<p>
	<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp;快速排序也和合并排序一样，基于分治法，分为分解、解决、合并三个步骤；</span></p>
<p>
	<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp;分解：数组array[low...high]被分为两个(可能空)子数组array[low...temp-1]和array[temp+1...high]，使得array[low...temp-1]中的每一个元素都小于等于array[temp]，而array[temp+1...high]中的每一个元素都大于array[temp]，下标temp也是在这个过程中被计算出来；</span></p>
<p>
	<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp;解决：通过递归的调用快速排序，对子数组array[low...temp-1]，array[temp+1...high]进行排序；</span></p>
<p>
	<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp;合并：因为两个子数组是就地排序的，将他们的合并不需要操作，整个数组array[low...high]是已经排好序的。</span></p>
<p>
	<span style="FONT-SIZE: 18px">二、快速排序实现</span></p>
<p></p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;
#include &amp;lt;ctime&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#define N 10

using namespace std;

//快速排序的递归算法
void quickSort(int * array , int low , int high);
//求分割点
int partition(int * array , int low , int high);
//交换两个变量的值
void exchange(int &amp;amp;a,int &amp;amp;b);

int main()
{
	//声明一个待排序数组   
    int array[N];  
    //设置随机化种子，避免每次产生相同的随机数    
    srand(time(0));   
    for(int i=0 ; i&amp;lt;N ; i++)    
    {    
        array[i] = rand()%101;//数组赋值使用随机函数产生1-100之间的随机数      
    }    
    cout&amp;lt;&amp;lt;&amp;quot;排序前：&amp;quot;&amp;lt;&amp;lt;endl;    
    for(int j=0;j&amp;lt;N;j++)    
    {    
        cout&amp;lt;&amp;lt;array[j]&amp;lt;&amp;lt;&amp;quot;  &amp;quot;;    
    }   
    cout&amp;lt;&amp;lt;endl&amp;lt;&amp;lt;&amp;quot;排序后：&amp;quot;&amp;lt;&amp;lt;endl;    
    //调用快速排序函数对该数组进行排序      
    quickSort(array,0,N-1);   
    for(int k=0;k&amp;lt;N;k++)    
    {    
        cout&amp;lt;&amp;lt;array[k]&amp;lt;&amp;lt;&amp;quot;  &amp;quot;;    
    }    
    cout&amp;lt;&amp;lt;endl;    
    return 0;    
}//main

void quickSort(int * array , int low , int high)
{
	if(low &amp;lt; high)
	{
		int temp = partition(array , low , high);
		quickSort(array , low , temp-1);
		quickSort(array , temp+1 , high);
	}
}

int partition(int * array , int low , int high)
{
	int i = low - 1;
	int x = array[high];

	for(int j=low ; j&amp;lt;high ; j++)
	{
		if(array[j] &amp;lt;= x)//在array[i]左边都是小于x即array[high]的数，右边均是大于它的数
		{
			i += 1;
			exchange(array[i],array[j]);
		}
	}
	exchange(array[i+1],array[high]);
	return i+1;//所以循环完毕后，i+1就是该数组的分割点
}
void exchange(int &amp;amp;a,int &amp;amp;b)
{
	int temp = a;
	a = b;
	b = temp;
}</pre><p></p>
<div class="article_content" id="article_content">
<p>
		<span style="FONT-SIZE: 18px">三、快速排序性能分析</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp;快速排序的运行时间与划分是否对称有关，而后者又与选择了哪一个元素进行划分有关。如果划分是对称的，那么本算法在渐近意义上与合并排序一样快，如果划分是不对称的那么本算法在渐进意义上与插入排序一样慢。下面分别讨论快速排序的最坏情况划分、最家情况划分、平衡的划分。</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp;<strong> &nbsp;<span style="COLOR: #ff0000">最坏情况划分：</span></strong>快速排序的最坏情况划分行为发生在划分过程中产生的两个区域分别包含n-1个元素和0个元素的时候。假设算法每次递归调用都出现了这种不对称划分，划分的时间代价为O(n)，因为对一个大小为0的数组进行递归调用后，返回了T(n)=O(1)，故算法的运行时间可递归的表示为：</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T(n) = T(n-1) + T(0) + O(n) = T(n-1) + O(n)</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp;从直观上来看，如果将每一层递归的代价加起来，就可以得到一个算术级数(等式(array,2)其和值的量极为O(n^2))利用代换法可以比较直接的证明递归式<span style="FONT-SIZE: 18px">&nbsp;T(n) = T(n-1) + O(n)的解为</span>&nbsp;T(n) = O(n^2)。</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp;因此如果在算法的每一层递归上，划分都是最大程度不对称的，那么算法的运行时间为O(n^2)，亦即快速排序算法的最坏情况运行时间不如插入排序的好。此外当输入数组完全排好序时，快速排序的运行时间是O(n^2)，而插入排序的运行时间为O(n)。</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; <strong>&nbsp;<span style="COLOR: #ff0000">最佳情况划分：</span></strong>在Partition可能做的最平衡划分中，得到的两个子问题的大小都不可能大于[n/2]，因为若其中一个子问题的大小为[n/2]，则另外一个子问题的大小必然为[n/2]-1。在这种情况下，快速排序的运行速度要快得多，这时表达其运行时间的递归式为：</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;T(n) &lt;= 2T(n/2) + O(n) &nbsp; &nbsp;&nbsp;</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; &nbsp;解该递归式可得T(n) = O(nlgn)。由于在每一层递归划分的两边都是对称的，因此从渐进意义上来看，算法运行的就更快了。</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp; &nbsp; &nbsp; <span style="COLOR: #ff0000; FONT-WEIGHT: bold">&nbsp;平衡的划分：</span>&nbsp;快速排序的平均情况运行时间与其最佳情况运行时间很接近，而不是非常接近与其最坏情况运行时间(证明原因详细参考《算法导论》原书第二版P88)，因为任何一种按常数比例进行划分都会产生深度为O(lgn)的递归树，其中每一层的代价都是O(n)，因而每当按照常数比例进行划分时，总的运行时间都是O(nlgn)。</span></p>
</div>
<p>
	<br />
	&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=172</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>合并排序（归并排序 MergeSort)</title>
		<link>https://www.softwareace.cn/?p=171</link>
		<comments>https://www.softwareace.cn/?p=171#comments</comments>
		<pubDate>Sat, 16 Feb 2013 05:27:05 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=171</guid>
		<description><![CDATA[]]></description>
				<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=171</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>堆排序(HeapSort)</title>
		<link>https://www.softwareace.cn/?p=170</link>
		<comments>https://www.softwareace.cn/?p=170#comments</comments>
		<pubDate>Sat, 16 Feb 2013 05:23:55 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=170</guid>
		<description><![CDATA[本文主要介绍堆排序算法（HeapSort），堆排序像合并排序而不像插入排序，堆排序的运行时间为O(nlgn)； [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
	<span style="FONT-SIZE: 18px">本文主要介绍堆排序算法（HeapSort），堆排序像合并排序而不像插入排序，堆排序的运行时间为O(nlgn)；像插入排序而不像合并排序，它是一种原地(in place)排序算法。在任何时候，数组中只有常数个元素存储在输入数组以外，这样，堆排序就把插入排序和合并排序的优点结合起来。</span></p>
<p>
	<span style="FONT-SIZE: 18px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 堆排序还引入了另外一种算法设计技术，利用某种数据结构(在此算法中为&ldquo;堆&rdquo;)来管理算法执行中的信息。堆数据结构不只在堆排序算法中有用，还可以构成一个有效的优先队列。堆数据结构是一种数组对象，它可以被视为一颗完全二叉树，树种每个结点与数组中存放该结点值的那个元素对应。树的每一层都是填满的，最后一层除外(最后一层从一个结点的左子树开始填)。</span></p>
<p>
	<span style="FONT-SIZE: 18px">&nbsp;一、堆排序算法原理</span></p>
<p>
	<span style="FONT-SIZE: 18px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 开始时，堆排序算法先用BuildMaxHeap()函数将n个元素的输入数组array[0...n-1]建造成一个大顶堆。因为数组中最大元素在对应堆树的根A[1]，所以可以通过把它与A[n]互换来达到最终正确的位置。现在如果从堆中&ldquo;去掉&rdquo;结点n(通过减小堆大小HeapSize)，可以很容易的将这一数组转换成一个最大堆。原来根的子女仍是最大堆，而新的堆元素可能违背了最大堆性质。这时调用MaxHeapify(array ,temp)函数就可以保持这一性质，由此在A[1...n-1]中构造出最大堆。堆排序算法不断重复这个过程，堆的大小从n-1一直降到2。</span></p>
<p>
	<span style="FONT-SIZE: 18px">二、堆排序算法的实现</span></p>
<p></p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;
#include &amp;lt;time.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#define N 10
using namespace std;

//声明建大顶堆函数
void BuildMaxHeap(int * array);
//声明堆排序函数
void HeapSort(int * array);
//声明调整为大顶堆函数
void MaxHeapify(int * array,int n);
//返回堆的数据个数
int HeapSize;

int main()
{
	//声明一个待排序数组
	int array[N];
	//设置随机化种子，避免每次产生相同的随机数 
	srand(time(0));	
	for(int i=0 ; i&amp;lt;N ; i++)  
    {  
        array[i] = rand()%101;//数组赋值使用随机函数产生1-100之间的随机数   
    }  
    cout&amp;lt;&amp;lt;&amp;quot;排序前：&amp;quot;&amp;lt;&amp;lt;endl;  
    for(int j=0;j&amp;lt;N;j++)  
    {  
        cout&amp;lt;&amp;lt;array[j]&amp;lt;&amp;lt;&amp;quot;  &amp;quot;;  
    } 
    cout&amp;lt;&amp;lt;endl&amp;lt;&amp;lt;&amp;quot;排序后：&amp;quot;&amp;lt;&amp;lt;endl;  
    //调用堆排序函数对该数组进行排序   
    HeapSort(array); 
    for(int k=0;k&amp;lt;N;k++)  
    {  
        cout&amp;lt;&amp;lt;array[k]&amp;lt;&amp;lt;&amp;quot;  &amp;quot;;  
    }  
    cout&amp;lt;&amp;lt;endl;  
    return 0;  
}

void HeapSort(int * array)
{
	BuildMaxHeap(array);
	for(int i=N-1 ; i&amp;gt;=0 ; i--)//数组中下标从0  -  N-1
	{
		int temp = array[0];
		array[0] = array[i];
		array[i] = temp;		
		HeapSize -= 1;
		MaxHeapify(array,1);//在堆中，堆顶元素下标从1开始
	}
}

void BuildMaxHeap(int * array)
{
	HeapSize = N;
	for(int i = (N-1)/2 ; i&amp;gt;=1 ; i--)//注意i的取值,堆的高度从1  -  (N-1)/2
	{
		MaxHeapify(array,i);
	}
}

void MaxHeapify(int * array,int temp)
{
	int largest;//以temp为顶点的子树的堆顶
	int l = 2*temp ;//求以temp为顶点的子树左儿子
	int r = 2*temp+1;//求以temp为顶点的子树右儿子

	if(l &amp;lt;= HeapSize &amp;amp;&amp;amp; array[l-1] &amp;gt; array[temp-1])//首先判断左儿子是否存在，即l&amp;lt;=HeapSize
	{
		largest = l;
	}else{
		largest = temp;
	}

	if(r &amp;lt;= HeapSize &amp;amp;&amp;amp; array[r-1] &amp;gt; array[largest-1])//首先判断右儿子是否存在，即r&amp;lt;=HeapSize
	{
		largest = r;
	}

	if(largest != temp)
	{
		int t = array[temp-1];
		array[temp-1] = array[largest-1];
		array[largest-1] = t;
		MaxHeapify(array,largest);//调整为大顶堆
	}
}</pre><p></p>
<div class="article_content" id="article_content">
<p>
		运行结果：<br />
		&nbsp; <img alt="" src="http://img.my.csdn.net/uploads/201301/28/1359384724_7979.png" /></p>
<p>
		&nbsp;&nbsp;<img alt="" src="http://img.my.csdn.net/uploads/201301/28/1359384724_7979.png" /><img alt="" src="http://img.my.csdn.net/uploads/201301/28/1359384724_7979.png" /></p>
<p>
		<span style="FONT-SIZE: 18px">三、堆排序算法分析</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 堆排序算法集中的插入排序和合并排序的优点，既可以原地排序又有一个较优异的复杂性O(nlgn)，而且所采用的堆数据结构还有一个广泛的应用，作为高效的优先级队列(Priority Queue)。详细应用讲解可以参考《算法导论》原书第二版P80。</span></p>
<p>
		<span style="FONT-SIZE: 18px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外，须知在实际应用中，快速排序的一个好的实现往往由于堆排序。</span></p>
</div>
<p>
	<br />
	&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=170</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>插入排序</title>
		<link>https://www.softwareace.cn/?p=169</link>
		<comments>https://www.softwareace.cn/?p=169#comments</comments>
		<pubDate>Sat, 16 Feb 2013 05:03:27 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=169</guid>
		<description><![CDATA[[crayon-69f6bbdc2e6fd448099590/] 插入排序InsertionSort，参数是一 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
void insert(int a[], int len)
{
	/*
		1.从第二个开始，把第二个抽出来当临时变量，这时假设这个位置是空的
		2.当左边的数据比这个临时变量大时，将左边的数值向右移动，
		  直到遇到左边，直到左边的数据小于这个临时变量为止
		3.将这个临时变量插入到这个空位置上
		  排序数组：5 7 4 2 6
		  第一次  
			temp = 7
			5 0 4 2 6--》左边的比这个临时变量小，且已经到达了最左端
			5 7 4 2 6（结束）

		  第二次
			temp = 4
			5 7 0 2 6
			5 5 7 2 6
			5 5 7 2 6
			4 5 7 2 6 (结束)

		  第三次
			temp = 2
			4 5 7 7 6
			4 5 5 7 6
			4 4 5 7 6
			2 4 5 7 6 (结束)

		 第四次
			temp = 6
			2 4 5 7 7
			2 4 5 6 7 (结束) 因为左边的5比6小，所以就停止将左边的数据右移了，将临时变量插入到这里
	*/
	for (int i=1; i&amp;lt;len; i++)
	{
		cout&amp;lt;&amp;lt;&amp;quot;第&amp;quot;&amp;lt;&amp;lt;i&amp;lt;&amp;lt;&amp;quot;次排序：&amp;quot;&amp;lt;&amp;lt;endl;

		int temp = a[i];		//定义临时变量
		cout&amp;lt;&amp;lt;&amp;quot;temp = &amp;quot;&amp;lt;&amp;lt;temp&amp;lt;&amp;lt;endl;
		
		int j;		
		//当 (j&amp;gt;0) 遇到最左端时，或者，(a[j-1] &amp;gt; temp) 左边的数据比这个临时变量小时，停止
		for (j=i; j&amp;gt;0&amp;amp;&amp;amp;a[j-1]&amp;gt;temp; j--)
		{
			a[j] = a[j-1];//将左边的数值向右移到右边

			//循环输出，看看排序经过
			for (int y=0; y&amp;lt;len; y++)
			{
				cout&amp;lt;&amp;lt;a[y]&amp;lt;&amp;lt;&amp;quot; &amp;quot;;
			}
			cout&amp;lt;&amp;lt;endl;
		}
		cout&amp;lt;&amp;lt;&amp;quot;要插入的位置 j = &amp;quot;&amp;lt;&amp;lt;j&amp;lt;&amp;lt;endl;
		cout&amp;lt;&amp;lt;&amp;quot;要插入的位置上的值 a[j] = &amp;quot;&amp;lt;&amp;lt;a[j]&amp;lt;&amp;lt;endl;
		a[j] = temp;	//将这个临时变量插入到这个空位上

		//循环输出，看看排序经过
		cout&amp;lt;&amp;lt;&amp;quot;第&amp;quot;&amp;lt;&amp;lt;i&amp;lt;&amp;lt;&amp;quot;次排序后的结果：&amp;quot;&amp;lt;&amp;lt;endl;
		for (int k=0; k&amp;lt;len; k++)
		{
			cout&amp;lt;&amp;lt;a[k]&amp;lt;&amp;lt;&amp;quot; &amp;quot;;
		}
		cout&amp;lt;&amp;lt;endl&amp;lt;&amp;lt;endl;
	}
}

void show(int a[], int len)
{
	for (int i=0; i&amp;lt;len; i++)
	{
		cout&amp;lt;&amp;lt;a[i]&amp;lt;&amp;lt;&amp;quot; &amp;quot;;
	}
	cout&amp;lt;&amp;lt;endl;
}

int main()
{
	int a[5] = {5,7,4,2,6};

	cout&amp;lt;&amp;lt;&amp;quot;插入排序：&amp;quot;&amp;lt;&amp;lt;endl;
	cout&amp;lt;&amp;lt;&amp;quot;排序前：&amp;quot;&amp;lt;&amp;lt;endl;
	show(a, 5);
	cout&amp;lt;&amp;lt;endl;
	insert(a, 5);
	cout&amp;lt;&amp;lt;endl;
	cout&amp;lt;&amp;lt;&amp;quot;排序后：&amp;quot;&amp;lt;&amp;lt;endl;
	show(a, 5);
	return 0;
}</pre><p></p>
<p>
	插入排序InsertionSort，参数是一个数组包含了n个待排序的数，输入的各个数字是原地排序的（sorted in place），意即这些数字就是在数组A中进行重新排序的，在任何时刻，至多只有其中的常数个数字是存储在数组之外的，当过程InsertionSort执行完毕后，输入数组A中就包含了已排好序的数组输出序列。</p>
<p>
	下面是利用C++语言实现的插入排序代码:</p>
<p></p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;
#define N 10
using namespace std;
//声明插入排序函数
int* insertionSort(int *array,int length);
int main()
{
	int array[N] = {2,1,3,67,35,12,9,7,45,0};
	insertionSort(array,N);
	for(int i=0;i&amp;lt;N;i++)
	{
		cout&amp;lt;&amp;lt;array[i]&amp;lt;&amp;lt;endl;
	}
	return 0;
}

int * insertionSort(int * array,int length)
{
	for(int i=1;i&amp;lt;length;i++)
	{
		int key = array[i];
		int j = i-1;
		while(j&amp;gt;=0 &amp;amp;&amp;amp; array[j]&amp;gt;key)//注意j的取值&amp;gt;=0
		{
			array[j+1] = array[j];	
			j=j-1;
		}//while
			array[j+1] = key;
	}//for
	return array;
}</pre><p></p>
<p>
	插入排序的算法复杂性分析：对于插入排序，它的复杂性依赖于待排序数组的一些属性，待排序数组长度、已排好序程度等。我们一般考察最坏情况下即逆序排序和最佳情况下即已排好序的复杂性。</p>
<p>
	最佳情况下：此时待排序数组已经是一个排好序的数组，推理可得程序运行时间可以表示为an+b；因此，它是n的一个线性函数。</p>
<p>
	最坏情况下：此时待排序数组是一个逆序数组，此时，我们必须把每个元素array[i]与整个已排序的子数组array[1...i-1]中的每个元素进行比较，因而，最坏情况下程序的运行 时间为an^2+bn+c，这是一个关于n的二次函数。</p>
<p>
	一般来说，如同插入排序一样，一个算法的运行时间对某一给定的输入来说，往往是固定的。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=169</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>选择排序</title>
		<link>https://www.softwareace.cn/?p=168</link>
		<comments>https://www.softwareace.cn/?p=168#comments</comments>
		<pubDate>Sat, 16 Feb 2013 05:00:19 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=168</guid>
		<description><![CDATA[[crayon-69f6bbdc2e954791882559/]]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

void select(int a[], int len)
{
	/*
		1. 将第一个数的位置设为最小位置，然后将这个数与后面所有的数进行比较
		2. 如果这个最小数大于后面的数， 则将后面这个值所在的位置设为最小位置
		3. 再用这个新的最小位置的最小值向后比较，直到没有比最小值更小的
	
			排序数组: 5 7 4 2 6
			第一次排序：
				min = 0   最小值：a[0] = 5
				5(最小)  7  4  2  6
				5  7  4(最小)  2  6		min = 2   比较：5&amp;lt;--&amp;gt;4
				5  7  4  2(最小)  6		min = 3	  比较：4&amp;lt;--&amp;gt;2
				排序后：2  7  4  5  6

			第二次排序：
				min = 1   最小值：a[1] = 7
				2  7(最小)  4  5  6  
				2  7  4(最小)  5  6		min = 2   比较：7&amp;lt;--&amp;gt;4
				2  7  4(最小)  5  6		min = 3	  比较：4&amp;lt;--&amp;gt;5
				2  7  4(最小)  5  6     min = 4   比较：4&amp;lt;--&amp;gt;6
				排序后：2  4  7  5  6

			第三次排序:
				min = 2   最小值：a[2] = 7
				2  4  7(最小  5  6
				2  4  7  5(最小)  6		min = 3   比较：7&amp;lt;--&amp;gt;5
				2  4  7  5(最小)  6     min = 3   比较：5&amp;lt;--&amp;gt;6
				排序后：2  4  5  7  6

			第四次排序：
				min = 3   最小值：a[3] = 7
				2  4  5  7(最小)  6
				2  4  5  7  6(最小)		min = 4   比较：7&amp;lt;--&amp;gt;6
				排序后：2  4  5  6  7
				
	*/
	for (int i=0; i&amp;lt;len; i++)
	{
		cout&amp;lt;&amp;lt;&amp;quot;第&amp;quot;&amp;lt;&amp;lt;i+1&amp;lt;&amp;lt;&amp;quot;次排序：&amp;quot;&amp;lt;&amp;lt;endl;
		int min = i;	//制定第一个位置为最小值

		//循环依次向后比较
		for (int j=i+1; j&amp;lt;len; j++)
		{
			cout&amp;lt;&amp;lt;&amp;quot;旧的最小值 a[min] = &amp;quot;&amp;lt;&amp;lt;a[min];
			if (a[j]&amp;lt;a[min])//将后面的位置和最小值比较
				min = j;	//如果比最小值还小，则将新的位置设为最小位置
							//用交换后的这个最小值，再与后面的值进行比较
			cout&amp;lt;&amp;lt;&amp;quot;, 新的最小值 a[min] = &amp;quot;&amp;lt;&amp;lt;a[min]&amp;lt;&amp;lt;endl;
			cout&amp;lt;&amp;lt;&amp;quot;交换后的最小位置 min = &amp;quot;&amp;lt;&amp;lt;min&amp;lt;&amp;lt;endl;
		}
		swap(a[min], a[i]);//将最小值排到最前

		//输出一轮排序后的结果
		cout&amp;lt;&amp;lt;&amp;quot;第&amp;quot;&amp;lt;&amp;lt;i+1&amp;lt;&amp;lt;&amp;quot;次排序的结果：&amp;quot;;
		for (int x=0; x&amp;lt;len; x++)
		{
			cout&amp;lt;&amp;lt;a[x]&amp;lt;&amp;lt;&amp;quot; &amp;quot;;
		}
		cout&amp;lt;&amp;lt;endl&amp;lt;&amp;lt;endl;;
	}
}

void show(int a[], int len)
{
	for (int i=0; i&amp;lt;len; i++)
	{
		cout&amp;lt;&amp;lt;a[i]&amp;lt;&amp;lt;&amp;quot; &amp;quot;;
	}
	cout&amp;lt;&amp;lt;endl;
}

int main()
{
	int a[5] = {5,7,4,2,6};

	cout&amp;lt;&amp;lt;&amp;quot;选择排序：&amp;quot;&amp;lt;&amp;lt;endl;
	cout&amp;lt;&amp;lt;&amp;quot;排序前：&amp;quot;&amp;lt;&amp;lt;endl;
	show(a, 5);
	cout&amp;lt;&amp;lt;endl;
	select(a, 5);
	cout&amp;lt;&amp;lt;endl;
	cout&amp;lt;&amp;lt;&amp;quot;排序后：&amp;quot;&amp;lt;&amp;lt;endl;
	show(a, 5);
	return 0;
}</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=168</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>冒泡排序法</title>
		<link>https://www.softwareace.cn/?p=167</link>
		<comments>https://www.softwareace.cn/?p=167#comments</comments>
		<pubDate>Sat, 16 Feb 2013 04:56:28 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=167</guid>
		<description><![CDATA[[crayon-69f6bbdc2eb53500299660/]]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt; 
#include &amp;lt;algorithm&amp;gt;
using namespace std;

void bubble(int a[], int len)
{
	/*   
	* 从头开始向后，一次结束后，最后的那个数就是最大的，   
	* 然后长度减一，就是减去最后那个最大的数，因为它不需要再排序了   

	* 当一次排序结束后，再从头开始，依次往后，结束后，最后一个又是最大的   

	7  4  2  6   
	4  7  2  6  
	5  4  2  7  6   

	5  4  2  6  7(最大)  第一轮结束   

	4  5  2  6   
	4  2  5  6(最大) 第二轮结束   
	2  4  5(最大)  第三轮结束   
	2  4(最大) 第思轮结束   
	2(最大)   
	*/   
	cout&amp;lt;&amp;lt;&amp;quot;冒泡排序法：&amp;quot;&amp;lt;&amp;lt;endl;
	int flag;//判断是否发生了交换 0：无交换  1：交换 
	do
	{
		flag = 0;//清零 
		for (int i=1; i&amp;lt;len; i++)
		{
			cout&amp;lt;&amp;lt;&amp;quot;第&amp;quot;&amp;lt;&amp;lt;i&amp;lt;&amp;lt;&amp;quot;次排序: &amp;quot;&amp;lt;&amp;lt;endl;
			if (a[i] &amp;lt; a[i-1])
			{
				swap(a[i], a[i-1]);
				for (int j=0; j&amp;lt;len; j++)
				{
					cout&amp;lt;&amp;lt;a[j]&amp;lt;&amp;lt;&amp;quot;  &amp;quot;;
				}
				cout&amp;lt;&amp;lt;endl;
				flag = 1;
			}   
		}
		--len;  //每次排序后都是长度减少1，提高效率 
	} while(flag == 1);

	//cout&amp;lt;&amp;lt;&amp;quot;第 &amp;quot;&amp;lt;&amp;lt;i&amp;lt;&amp;lt;&amp;quot; 次排序&amp;quot;&amp;lt;&amp;lt;endl; 
}
void show(int a[], int len)
{
	for (int i=0; i&amp;lt;len; i++)
	{
		cout&amp;lt;&amp;lt;a[i]&amp;lt;&amp;lt;&amp;quot;  &amp;quot;;
	}
	cout&amp;lt;&amp;lt;endl;
}

int main(int argc, char* argv[])

{
	int a[5] = {5,7,4,2,6};
	cout&amp;lt;&amp;lt;&amp;quot;排序前：&amp;quot;&amp;lt;&amp;lt;endl;
	show(a, 5);
	bubble(a, 5);
	cout&amp;lt;&amp;lt;&amp;quot;排序后：&amp;quot;&amp;lt;&amp;lt;endl;
	show(a, 5);
	getchar();
	return 0;
}</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=167</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
