﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-铁血石头</title><link>http://www.cppblog.com/Stone7299/</link><description>中庸</description><language>zh-cn</language><lastBuildDate>Tue, 09 Jun 2026 19:07:21 GMT</lastBuildDate><pubDate>Tue, 09 Jun 2026 19:07:21 GMT</pubDate><ttl>60</ttl><item><title>链表</title><link>http://www.cppblog.com/Stone7299/archive/2011/08/31/154769.html</link><dc:creator>曹磊</dc:creator><author>曹磊</author><pubDate>Wed, 31 Aug 2011 03:36:00 GMT</pubDate><guid>http://www.cppblog.com/Stone7299/archive/2011/08/31/154769.html</guid><wfw:comment>http://www.cppblog.com/Stone7299/comments/154769.html</wfw:comment><comments>http://www.cppblog.com/Stone7299/archive/2011/08/31/154769.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Stone7299/comments/commentRss/154769.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Stone7299/services/trackbacks/154769.html</trackback:ping><description><![CDATA[<p><span style="background-color: rgb(153,230,0)">出自：<a href="http://hi.baidu.com/caolei7299/blog/">http://hi.baidu.com/caolei7299/blog/</a><br />//***********************************************************</span><br /><span style="background-color: rgb(153,230,0)">//</span><br /><span style="background-color: rgb(153,230,0)">// Author: _Stone_7299</span><br /><span style="background-color: rgb(153,230,0)">// data: 2011-8-26</span><br /><span style="background-color: rgb(153,230,0)">// From: 笃志</span><a href="http://www.rpgchina.net/read-htm-tid-28012.html"><span style="background-color: rgb(153,230,0)">http://www.rpgchina.net/read-htm-tid-28012.html</span></a><br /><span style="background-color: rgb(153,230,0)">// AfterWritingAre: 笃志大侠的List 敲了一天</span><br /><span style="background-color: rgb(153,230,0)">//***********************************************************/</span></p>
<p>#ifndef __SINGLE_LIST_H__<br />#define __SINGLE_LIST_H__</p>
<p>#include&lt;assert.h&gt; //支持断言<br />#include&lt;crtdbg.h&gt; //支持内存泄漏</p>
<p>//DEBUG 模式下，定义获得错误信息 文件名 行数</p>
<p>#ifdef _DEBUG<br />#define DEBUG_NEW new ( _NORMAL_BLOCK, THIS_FILE, __LINE__ )<br />#endif</p>
<p>#ifdef _DEBUG<br />#define new DEBUG_NEW<br />#undef THIS_FILE</p>
<p>//节省空间，没必要生成大量的错误信息，仅保存一个常量，<br />//出现错误其他指针 指向这里即可(没有看懂)<br />static char THIS_FILE[] = __FILE__;<br />#endif</p>
<p>//若是DEBUG模式，则断言有效，否则使其无效<br />#ifdef _DEBUG<br />#ifndef ASSERT<br />#define ASSERT assert<br />#endif<br />#else<br />#ifndef ASSERT<br />#define ASSERT<br />#endif<br />#endif</p>
<p>//单链表 节点结构<br />template&lt;typename T&gt;<br />class CNode<br />{<br />public:<br />T data;<br />CNode&lt; T &gt; *next;</p>
<p>public:<br />CNode(): data( T() ), next(NULL){};</p>
<p>CNode(const T &amp;initdata):data(initdata), next(NULL){};</p>
<p>CNode(const T &amp;initdata, CNode&lt; T &gt; *p):data(initdata), next(p){};</p>
<p>};</p>
<p><br />//单链表结构<br />template &lt;typename T &gt;<br />class CSList<br />{</p>
<p>protected:</p>
<p>int m_nCount;<br />CNode&lt; T &gt; *m_pNodeHead;</p>
<p>public:<br />CSList();<br />CSList(const T &amp;initdata);<br />~CSList();</p>
<p>public: //常用的对外接口</p>
<p>/* 关于T与T&amp;返回值的说明.该部分的所有获取函数都实现了两次,<br />目的是,返回值为T的,允许修改,即读写操作均允许.<br />返回值为T&amp;的,是其内存地址所写的常量值,不允许进行写操作,进行了保护<br />const的目的在于进行函数重载,若不加的话,编译器认为是相同的函数<br />*/</p>
<p>//判断单链表是否为空<br />bool ISEmpty() const;<br />//获取单链表结点个数<br />int GetCount() const;<br />//在指定位置之前添加结点<br />int InsertBefore(const int pos, const T data);<br />//在指定位置之后添加结点<br />int InsertAfter(const int pos, const T data);<br />//在链表头部添加结点<br />int AddHead(const T data);<br />//在链表尾部添加结点<br />int AddTail(const T data);<br />//删除指定的结点<br />void RemoveAt(const int pos);<br />//删除头结点<br />void RemoveHead();<br />//删除尾结点<br />void RemoveTail();<br />//删除所有结点<br />void RemoveAll();<br />//获取头结点数据<br />T&amp; GetHead();<br />//获取头结点数据<br />T GetHead() const;<br />//获取尾结点数据<br />T&amp; GetTail();<br />//获取尾结点数据<br />T GetTail() const;<br />//获取指定位置结点<br />T&amp; GetAt(const int pos);<br />//获取指定结点位置<br />T GetAt(const int pos) const;<br />//更改指定位置结点数据<br />void SetAt(const int pos, T data);<br />//查询指定数据位置<br />int Find(const T data) const;<br /><br />};</p>
<p>/* 由于模版类不支持.h和.cpp分离,故实现也写在头文件中 <br />除非编译器支持export关键字,而实际上基本没有编译器支持\(-_-)/ */<br />/* 代码短小常用的函数使用内联比较迅速 */</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline CSList&lt; T &gt;::CSList()<br />:m_nCount (0),<br />m_pNodeHead (NULL)<br />{</p>
<p>}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline CSList&lt; T &gt;::CSList(const T &amp;initdata)<br />:m_nCount (0),<br />m_pNodeHead (NULL)<br />{<br />AddHead(initdata);<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline CSList&lt; T &gt;::~CSList()<br />{<br />RemoveAll();<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline bool CSList&lt; T &gt;::ISEmpty() const<br />{<br />if(m_nCount == 0)<br />{<br />return true;<br />}<br />else<br />{<br />return false;<br />}</p>
<p>}<br /><br />//-----------------------------------<br />template&lt; typename T &gt;<br />inline int CSList&lt; T &gt;::GetCount() const<br />{<br />return m_nCount;<br />}</p>
<p>//-----------------------------------<br />//返回值说明: 若返回0 则插入失败 否则 记录插入结点的当前位置<br />template&lt; typename T &gt;<br />inline int CSList&lt; T &gt;::InsertBefore(const int pos, const T data)<br />{<br />/*将结点插入位置之前的操作分为三种可能<br />1: 空链表插入，头指针需要添加，新节点的指针无效<br />2: 插入链表头部，头指针需要改变，新节点的指针赋值<br />3: 插入链表中间，头指针不改变，改变位置前结点指针，自身指针赋值<br />*/</p>
<p>int i;<br />int nRetPos; //结点实际所在位置 0代表插入失败<br />CNode&lt; T &gt; *pTmpNode; //目标位置前结点<br />CNode&lt; T &gt; *pNewNode; //想插入的目标结点</p>
<p>//若创建失败<br />pNewNode = new CNode&lt; T &gt;;<br />if(pNewNode == NULL)<br />{<br />return 0;<br />}</p>
<p>pNewNode-&gt;data = data;</p>
<p>//若链表为空,则相当于将数据结点设置为首节点<br />if(m_pNodeHead == NULL)<br />{<br />pNewNode-&gt;next = NULL;<br />m_pNodeHead = pNewNode;</p>
<p>nRetPos = 1;<br />++ m_nCount;<br />return nRetPos;<br />}<br /><br />//断言: 传入的参数必须在合理的范围之内<br />ASSERT((1 &lt;= pos) &amp;&amp; (pos &lt;= m_nCount));</p>
<p>//若插入的是头结点<br />if(pos == 1)<br />{<br />pNewNode-&gt;next = m_pNodeHead;<br />m_pNodeHead = pNewNode;</p>
<p>nRetPos = 1;<br />++ m_nCount;<br />return nRetPos;<br />} </p>
<p>//一般情况<br />pTmpNode = m_pNodeHead;<br />for(i = 1;i &lt; pos - 1; ++i )<br />{<br />pTmpNode = pTmpNode-&gt;next;<br />}<br /><br />//通过循环获得的指针位置原来的结点的前一个结点pTmpNode<br />pNewNode-&gt;next = pTmpNode-&gt;next;<br />pTmpNode-&gt;next = pNewNode;</p>
<p>nRetPos = pos;<br />++ m_nCount;<br />return nRetPos;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline int CSList&lt; T &gt;::InsertAfter(const int pos, const T data)<br />{<br />/*比起InsertBefore 少了一种情况<br />1: 链表为空的时候依旧需要处理<br />2: 插入点不能为最前，若为最后的话，也可按照一般情况，<br />所以仅需要两种处理方式<br />*/<br />int i;<br />int nRetPos; <br />CNode&lt; T &gt; *pTmpNode; <br />CNode&lt; T &gt; *pNewNode;<br /><br />pNewNode = new CNode&lt; T &gt;;<br />if(pNewNode == NULL)<br />{<br />return 0;<br />}</p>
<p>pNewNode-&gt;data = data;</p>
<p>if(m_pNodeHead == NULL)<br />{<br />m_pNodeHead = pNewNode;<br />pNewNode-&gt;next =NULL;<br />m_nCount ++;<br />nRetPos = 1;<br />return nRetPos;<br />}</p>
<p>ASSERT((pos&gt;=1) &amp;&amp; (pos&lt;= m_nCount));<br />pTmpNode = m_pNodeHead;</p>
<p>/*注意: 和InsertBefore不同, 多加一次<br />InsertInsertBefore获得的是目标位置原结点的前一个结点<br />InsertInsertAfter获得的是目标位置原结点<br />*/<br />for(i = 1;i&lt;pos;++i)<br />{<br />pTmpNode = pTmpNode-&gt;next;<br />}<br /><br />//通过获得的指定位置原结点pTmpNode<br />pNewNode-&gt;next = pTmpNode-&gt;next;<br />pTmpNode-&gt;next = pNewNode;</p>
<p>++ m_nCount;<br />nRetPos = pos + 1; /*注意: 此处加1 */</p>
<p>return nRetPos;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline int CSList&lt; T &gt;::AddHead(const T data)<br />{<br />CNode&lt; T &gt; *pNewNode;<br />pNewNode = new CNode&lt; T &gt;;</p>
<p>if(pNewNode == NULL)<br />{<br />return 0;<br />}<br /><br />pNewNode-&gt;data = data;<br />pNewNode-&gt;next = m_pNodeHead;</p>
<p>m_pNodeHead = pNewNode;<br />++m_nCount;</p>
<p>return 1;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline int CSList&lt; T &gt;::AddTail(const T data)<br />{<br />if(InsertAfter(GetCount(),data))<br />{<br />return 1;<br />}<br />else<br />{<br />return 0;<br />}<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline void CSList&lt; T &gt;::RemoveAt(const int pos)<br />{<br />//断言合法性<br />ASSERT((pos&gt;=1) &amp;&amp; (pos&lt;= m_nCount));</p>
<p>int i;<br />CNode&lt; T &gt; *pTmpNode; //目标结点的前一个结点<br />CNode&lt; T &gt; *pDeskNode; //目标位置结点<br />pTmpNode = m_pNodeHead;</p>
<p>if(pos == 1)<br />{<br />m_pNodeHead = m_pNodeHead-&gt;next;<br />delete pTmpNode;<br />pTmpNode = NULL;</p>
<p>-- m_nCount;<br />return;<br />}</p>
<p>//一般情况<br />for(i = 1;i &lt; pos-1; ++i)<br />{<br />pTmpNode = pTmpNode-&gt;next;<br />}</p>
<p>pDeskNode = pTmpNode-&gt;next;<br />pTmpNode-&gt;next = pDeskNode-&gt;next;<br />delete pDeskNode;<br />pDeskNode = NULL;</p>
<p>-- m_nCount;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline void CSList&lt; T &gt;::RemoveHead()<br />{<br />ASSERT(m_nCount != 0);<br />RemoveAt(1);<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline void CSList&lt; T &gt;::RemoveTail()<br />{<br />ASSERT(m_nCount != 0);</p>
<p>RemoveAt(GetCount());<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline void CSList&lt; T &gt;::RemoveAll()<br />{<br />int i;<br />int nCount;<br />CNode&lt; T &gt; *pTmpNode;</p>
<p>nCount = m_nCount;<br />for(i = 0; i &lt; nCount; ++i)<br />{<br />/*从链表的头部开始删除*/<br />pTmpNode = m_pNodeHead-&gt;next;<br />delete m_pNodeHead;<br />m_pNodeHead = 0;</p>
<p>m_pNodeHead = pTmpNode;<br />}<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline T&amp; CSList&lt; T &gt;::GetHead()<br />{<br />ASSERT( m_nCount != 0);<br />return m_pNodeHead-&gt;data;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline T CSList&lt; T &gt;::GetHead() const <br />{<br />ASSERT( m_nCount != 0);<br />return m_pNodeHead-&gt;data;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline T&amp; CSList&lt; T &gt;::GetTail()<br />{<br />ASSERT( m_nCount != 0);</p>
<p>int i;<br />int nCount;<br />CNode&lt; T &gt; *pTmpNode;<br />nCount = m_nCount;<br />pTmpNode = m_pNodeHead;<br />for(int i = 0;i &lt; nCount; ++i)<br />{<br />pTmpNode = pTmpNode-&gt;next;<br />}</p>
<p>return pTmpNode-&gt;data;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline T CSList&lt; T &gt;::GetTail() const<br />{<br />ASSERT( m_nCount != 0);</p>
<p>int i;<br />int nCount;<br />CNode&lt; T &gt; *pTmpNode;<br />nCount = m_nCount;<br />pTmpNode = m_pNodeHead;<br />for(int i = 0;i &lt; nCount; ++i)<br />{<br />pTmpNode = pTmpNode-&gt;next;<br />}</p>
<p>return pTmpNode-&gt;data;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline T&amp; CSList&lt; T &gt;::GetAt(const int pos) <br />{<br />ASSERT((pos &gt;= 1) &amp;&amp; (pos &lt;= m_nCount));<br />int i;<br />CNode&lt; T &gt; *pTmpNode;<br />pTmpNode = m_pNodeHead;<br />for(i = 1; i &lt; pos; i++)<br />{<br />pTmpNode = pTmpNode-&gt;next;<br />}<br />return pTmpNode-&gt;data;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline T CSList&lt; T &gt;::GetAt(const int pos) const<br />{<br />ASSERT((pos &gt;= 1) &amp;&amp; (pos &lt;= m_nCount));<br />int i;<br />CNode&lt; T &gt; *pTmpNode;<br />pTmpNode = m_pNodeHead;<br />for(i = 1; i &lt; pos; i++)<br />{<br />pTmpNode = pTmpNode-&gt;next;<br />}<br />return pTmpNode-&gt;data;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;<br />inline void CSList&lt; T &gt;::SetAt(const int pos, T data)<br />{<br />ASSERT((pos &gt;= 1) &amp;&amp; (pos &lt;= m_nCount));</p>
<p>int i;<br />CNode&lt; T &gt; *pTmpNode;<br />pTmpNode = m_pNodeHead;<br />for(i = 1; i &lt; pos; i++)<br />{<br />pTmpNode = pTmpNode-&gt;next;<br />}<br />pTmpNode-&gt;data = data;<br />}</p>
<p>//-----------------------------------<br />template&lt; typename T &gt;</p>
<p>inline int CSList&lt; T &gt;::Find(const T data) const<br />{<br />int i;<br />int nCount;<br />CNode&lt; T &gt; *pTmpNode;<br />pTmpNode = m_pNodeHead;<br />nCount = m_nCount;</p>
<p>//遍历所有的结点<br />for(i = 0;i&lt;nCount;++i)<br />{<br />if(data = pTmpNode-&gt;data)<br />{<br />return i + 1; //结点号 索引号差1<br />}<br />pTmpNode = pTmpNode-&gt;next;<br />}</p>
<p>//若没有找到<br />return 0;<br />}</p>
<p>#endif</p>
<p>&nbsp;</p>
<p><span style="background-color: rgb(153,230,0)">//*****************************************************************</span><br /><span style="background-color: rgb(153,230,0)">// Author: _Stone_7299</span><br /><span style="background-color: rgb(153,230,0)">// data: 2011-08-26</span><br /><span style="background-color: rgb(153,230,0)">// From: 笃志</span><a href="http://www.rpgchina.net/read-htm-tid-28012.html"><span style="background-color: rgb(153,230,0)">http://www.rpgchina.net/read-htm-tid-28012.html</span></a><br /><span style="background-color: rgb(153,230,0)">//</span><br /><span style="background-color: rgb(153,230,0)">//*****************************************************************/</span></p>
<p>//测试SinList<br />#include "stdafx.h"<br />#include &lt;iostream&gt;<br />#include"SinList.h"<br />using namespace std;</p>
<p>int main()<br />{ <br />int i;<br />int nCount;<br />CSList&lt; int &gt; sList;</p>
<p>#ifdef _DEBUG<br />/*如果是DEBUG模式下，若main函数运行完毕，还有内存没有释放，则会将其信息反馈<br />到编译器下方的调试窗口有提示（注:但是这句不进行错误位置的提示，所以若需要错误定位<br />依旧需要依靠头文件种的__FILE__那一行）*/<br />_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);<br />#endif</p>
<p>//不想写了，粘贴笃志代码<br />sList.InsertAfter(sList.InsertAfter(sList.AddHead(1), 2), 3); /* 1,2,3 */<br />sList.InsertAfter(sList.InsertAfter(sList.GetCount(), 4), 5); /* 1,2,3,4,5 */<br />sList.InsertAfter(sList.GetCount(), 6); /* 1,2,3,4,5,6 */<br />sList.AddTail(10); /* 1,2,3,4,5,6,10 */<br />sList.InsertAfter(sList.InsertBefore(sList.GetCount(), 7), 8); /* 1,2,3,4,5,6,7,8,10 */<br />sList.SetAt(sList.GetCount(), 9); /* 1,2,3,4,5,6,7,8,9 */<br />sList.RemoveHead(); /* 2,3,4,5,6,7,8,9 */<br />sList.RemoveTail(); /* 2,3,4,5,6,7,8 */</p>
<p>nCount = sList.GetCount();<br />for (i = 0; i &lt; nCount; ++i)<br />{<br />cout &lt;&lt; sList.GetAt(i + 1) &lt;&lt; endl;<br />}<br />// 等待输入才退出<br />getchar();</p>
<p>return 0;<br />}<br /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p><img src ="http://www.cppblog.com/Stone7299/aggbug/154769.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Stone7299/" target="_blank">曹磊</a> 2011-08-31 11:36 <a href="http://www.cppblog.com/Stone7299/archive/2011/08/31/154769.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>