• 博客(0)
  • 资源 (4)

空空如也

ICTC-6

N-最短路径中文词语粗分是分词过程中非常重要的一步,而原有ICTCLAS中该部分代码也是我认为最难读懂的部分,到现在还有一些方法没有弄明白,因此我几乎重写了NShortPath类。要想说明N-最短路径代码是如何工作的并不容易,所以分成两步分,本部分先说说SharpICTCLAS中1-最短路径是如何实现的,在下一篇文章中再引申到N-最短路径。<br><br>1、数据表示<br>这里我们求最短路的例子使用如下的有向图,每条边的权重已经在图中标注出来了。<br><br><br><br>(图一)<br><br>根据上篇文章内容,该图该可以等价于如下的二维表格表示:<br><br><br><br>(图二)<br><br>而对应于该表格的是一个ColumnFirstDynamicArray,共有10个结点,每个结点的取值如下表所示:<br><br> Copy Code该示例对应的ColumnFirstDynamicArray<br>row:0, col:1, eWeight:1, nPOS:0, sWord: 始@A <br>row:1, col:2, eWeight:1, nPOS:0, sWord: A@B <br>row:1, col:3, eWeight:2, nPOS:0, sWord: A@C <br>row:2, col:3, eWeight:1, nPOS:0, sWord: B@C <br>row:2, col:4, eWeight:1, nPOS:0, sWord: B@D <br>row:3, col:4, eWeight:1, nPOS:0, sWord: C@D <br>row:4, col:5, eWeight:1, nPOS:0, sWord: D@E <br>row:3, col:6, eWeight:2, nPOS:0, sWord: C@末 <br>row:4, col:6, eWeight:3, nPOS:0, sWord: D@末 <br>row:5, col:6, eWeight:1, nPOS:0, sWord: E@末<br>2、计算出每个结点上可达最短路的PreNode<br>在求解N-最短路径之前,先看看如何求最短PreNode。如下图所示:<br><br><br><br>(图三)<br><br>首先计算出到达每个结点的最短路径,并将该结点的父结点压入该结点所对应的队列。例如3号“C”结点,到达该结点的最短路径长度为3,它的Parent结点可以是1号“A”结点,也可以是2号“B”结点,因此在队列中存储了两个PreNode结点。<br><br>而在实际计算时,如何知道到达3号“C”结点的路径有几条呢?其实我们首先计算所有到达3号“C”结点的路径长度,并按照路径长度从小到大的顺序排列(所有这些都是靠CQueue这个类完成的),然后从队列中依次向后取值,取出所有最短路径对应的PreNode。<br><br>计算到当前结点(nCurNode)可能的边,并根据总路径长度由小到大压入队列的代码如下(经过简化):<br><br> Copy CodeEnQueueCurNodeEdges方法<br>//==================================================================== <br>// 将所有到当前结点(nCurNode)可能的边根据eWeight排序并压入队列 <br>//==================================================================== <br>private void EnQueueCurNodeEdges(ref CQueue queWork, int nCurNode) <br>{ <br> int nPreNode; <br> double eWeight; <br> ChainItem<ChainContent> pEdgeList; <br><br> queWork.Clear(); <br> pEdgeList = m_apCost.GetFirstElementOfCol(nCurNode); <br><br> // 获取所有到当前结点的边 <br> while (pEdgeList != null && pEdgeList.col == nCurNode) <br> { <br> nPreNode = pEdgeList.row; // 很特别的命令,利用了row与col的关系 <br> eWeight = pEdgeList.Content.eWeight; <br><br> // 第一个结点,没有PreNode,直接加入队列 <br> if (nPreNode == 0) <br> { <br> queWork.EnQueue(new QueueElement(nPreNode, eWeight)); <br> break; <br> } <br><br> queWork.EnQueue(new QueueElement(nPreNode, eWeight + m_pWeight[nPreNode - 1])); <br> pEdgeList = pEdgeList.next; <br> } <br>} <br><br>这段代码中有一行很特别的命令,就是用红颜色注释的那句“nPreNode = pEdgeList.row;”,让我琢磨了半天终于弄明白原有ICTCLAS用意的一句话。这需要参考本文图二,为了方便起见,我将它挪到了这里:<br><br><br><br>注意 3 号“C”结点在该表中处于第 3 列,所有可以到达该结点的边就是该列中的元素(目前有两个元素“A@C”与“B@C”)。而与 3 号“C”结点构成这两条边的PreNode结点恰恰是这两个元素的“行号”,分别是 1 号“A”结点与 2 号“B”结点。正是因为这种特殊的对应关系,为我们检索所有可达边提供了便捷的方法。阅读上面那段代码务必把握好这种关系。<br><br>3、求解最短路径<br>求出每个结点上最短路径的PreNode后就需要据此推导出完整的最短路径。原ICTCLAS代码中是靠GetPaths方法实现的,只是到现在我也没有读懂这个方法的代码究竟想干什么 ,只知道它用了若干个while,若干个if,若干个嵌套...(将ICTCLAS中的GetPaths放上来,如果谁读懂了,回头给我讲讲 ,感觉应该和我的算法差不多)。<br><br> Copy CodeNShortPath.cpp程序中的GetPaths方法<br>void CNShortPath::GetPaths(unsigned int nNode, unsigned int nIndex, int <br> **nResult, bool bBest) <br>{ <br> CQueue queResult; <br> unsigned int nCurNode, nCurIndex, nParentNode, nParentIndex, nResultIndex = 0; <br><br> if (m_nResultCount >= MAX_SEGMENT_NUM) <br> //Only need 10 result <br> return ; <br> nResult[m_nResultCount][nResultIndex] = - 1; //Init the result <br> queResult.Push(nNode, nIndex); <br> nCurNode = nNode; <br> nCurIndex = nIndex; <br> bool bFirstGet; <br> while (!queResult.IsEmpty()) <br> { <br> while (nCurNode > 0) <br> // <br> { <br> //Get its parent and store them in nParentNode,nParentIndex <br> if (m_pParent[nCurNode - 1][nCurIndex].Pop(&nParentNode, &nParentIndex, 0, <br> false, true) != - 1) <br> { <br> nCurNode = nParentNode; <br> nCurIndex = nParentIndex; <br> } <br> if (nCurNode > 0) <br> queResult.Push(nCurNode, nCurIndex); <br> } <br> if (nCurNode == 0) <br> { <br> //Get a path and output <br> nResult[m_nResultCount][nResultIndex++] = nCurNode; //Get the first node <br> bFirstGet = true; <br> nParentNode = nCurNode; <br> while (queResult.Pop(&nCurNode, &nCurIndex, 0, false, bFirstGet) != - 1) <br> { <br> nResult[m_nResultCount][nResultIndex++] = nCurNode; <br> bFirstGet = false; <br> nParentNode = nCurNode; <br> } <br> nResult[m_nResultCount][nResultIndex] = - 1; //Set the end <br> m_nResultCount += 1; //The number of result add by 1 <br> if (m_nResultCount >= MAX_SEGMENT_NUM) <br> //Only need 10 result <br> return ; <br> nResultIndex = 0; <br> nResult[m_nResultCount][nResultIndex] = - 1; //Init the result <br><br> if (bBest) <br> //Return the best result, ignore others <br> return ; <br> } <br> queResult.Pop(&nCurNode, &nCurIndex, 0, false, true); //Read the top node <br> while (queResult.IsEmpty() == false && (m_pParent[nCurNode - <br> 1][nCurIndex].IsSingle() || m_pParent[nCurNode - 1][nCurIndex].IsEmpty <br> (true))) <br> { <br> queResult.Pop(&nCurNode, &nCurIndex, 0); //Get rid of it <br> queResult.Pop(&nCurNode, &nCurIndex, 0, false, true); //Read the top node <br> } <br> if (queResult.IsEmpty() == false && m_pParent[nCurNode - <br> 1][nCurIndex].IsEmpty(true) == false) <br> { <br> m_pParent[nCurNode - 1][nCurIndex].Pop(&nParentNode, &nParentIndex, 0, <br> false, false); <br> nCurNode = nParentNode; <br> nCurIndex = nParentIndex; <br> if (nCurNode > 0) <br> queResult.Push(nCurNode, nCurIndex); <br> } <br> } <br>}<br>我重写了求解最短路径的方法,其算法表述如下:<br><br><br><br>(图四)<br><br>1)首先将最后一个元素压入堆栈(本例中是6号结点),什么时候这个元素弹出堆栈,什么时候整个任务结束。<br><br>2)对于每个结点的PreNode队列,维护了一个当前指针,初始状态都指向PreNode队列中第一个元素。<br><br>3)从右向左依次取出PreNode队列中的当前元素并压入堆栈,并将队列指针重新指向队列中第一个元素。如图四:6号元素PreNode是3,3号元素PreNode是1,1号元素PreNode是0。<br><br>4)当第一个元素压入堆栈后,输出堆栈内容即为一条队列。本例中0, 1, 3, 6便是一条最短路径。<br><br>5)将堆栈中的内容依次弹出,每弹出一个元素,就将当时压栈时对应的PreNode队列指针下移一格。如果到了末尾无法下移,则继续执行第5步,如果仍然可以移动,则执行第3步。<br><br>对于本例,先将“0”弹出堆栈,该元素对应的是1号“A”结点的PreNode队列,该队列的当前指针已经无法下移,因此继续弹出堆栈中的“1” ;该元素对应3号“C”结点,因此将3号“C”结点对应的PreNode队列指针下移。由于可以移动,因此将队列中的2压入队列,2号“B”结点的PreNode是1,因此再压入1,依次类推,直到0被压入,此时又得到了一条最短路径,那就是0,1,2,3,6。如下图:<br><br><br><br>(图五)<br><br>再往下,0、1、2都被弹出堆栈,3被弹出堆栈后,由于它对应的6号元素PreNode队列记录指针仍然可以下移,因此将5压入堆栈并依次将其PreNode入栈,直到0被入栈。此时输出第3条最短路径:0, 1, 2, 4, 5, 6。入下图:<br><br><br><br>(图六)<br><br>输出完成后,紧接着又是出栈,此时已经没有任何堆栈元素对应的PreNode队列指针可以下移,于是堆栈中的最后一个元素6也被弹出堆栈,此时输出工作完全结束。我们得到了3条最短路径,分别是:<br><br>0, 1, 3, 6, <br>0, 1, 2, 3, 6, <br>0, 1, 2, 4, 5, 6, <br>让我们看看在SharpICTCLAS中,该算法是如何实现的:<br><br> Copy CodeSharpICTCLAS中的GetPaths方法<br>//==================================================================== <br>// 注:index = 0 : 最短的路径; index = 1 : 次短的路径 <br>// 依此类推。index <= this.m_nValueKind <br>//==================================================================== <br>public List<int[]> GetPaths(int index) <br>{ <br> Stack<PathNode> stack = new Stack<PathNode>(); <br> int curNode = m_nNode - 1, curIndex = index; <br> QueueElement element; <br> PathNode node; <br> int[] aPath; <br> List<int[]> result = new List<int[]>(); <br><br> element = m_pParent[curNode - 1][curIndex].GetFirst(); <br> while (element != null) <br> { <br> // ---------- 通过压栈得到路径 ----------- <br> stack.Push(new PathNode(curNode, curIndex)); <br> stack.Push(new PathNode(element.nParent, element.nIndex)); <br> curNode = element.nParent; <br><br> while (curNode != 0) <br> { <br> element = m_pParent[element.nParent - 1][element.nIndex].GetFirst(); <br> stack.Push(new PathNode(element.nParent, element.nIndex)); <br> curNode = element.nParent; <br> } <br><br> // -------------- 输出路径 -------------- <br> PathNode[] nArray = stack.ToArray(); <br> aPath = new int[nArray.Length]; <br> <br> for(int i=0; i<aPath.Length; i++) <br> aPath[i] = nArray[i].nParent; <br><br> result.Add(aPath); <br><br> // -------------- 出栈以检查是否还有其它路径 -------------- <br> do <br> { <br> node = stack.Pop(); <br> curNode = node.nParent; <br> curIndex = node.nIndex; <br><br> } while (curNode < 1 || (stack.Count != 0 && !m_pParent[curNode - 1][curIndex].CanGetNext)); <br><br> element = m_pParent[curNode - 1][curIndex].GetNext(); <br> } <br><br> return result; <br>}<br>注意,上面的代码是N-最短路径的,比起1-最短路径来说增加了点复杂度,但总体架构不变。这段代码将原有ICTCLAS的70多行求解路径代码缩短到了40多行。<br><br>小结 <br>1)N-最短路径的求解比较复杂,本文先从求解1-最短路径着手,说明SharpICTCLAS是如何计算的,在下篇文章中将推广到N-最短路径。<br><br>2)1-最短路径并不意味着只有一条最短路径,而是路径最短的若干条路径。就如本文案例所示,1-最短路径算法最终求得了3条路径,它们的长度都是5,因此都是最短路径。<br><br> <br><br>posted on 2007-03-09 22:47 吕震宇 阅读(1165) 评论(9) 编辑 收藏 所属分类: ICTCLAS <br> <br><br><br>评论<br>#1楼 [TrackBack] 2007-03-09 22:51 吕震宇 <br>具体内容请访问我的文章 <br>《SharpICTCLAS分词系统简介(4)NShortPath-1 》<br>[引用提示]吕震宇引用了该文章, 地址: http://www.cnblogs.com/zhenyulu/archive/2007/03/09/669801.html <br> 回复 引用 查看 <br><br><br>#2楼 2007-03-10 09:16 yukaizhao [未注册用户] <br>没有看明白,再看一遍 <br> 回复 引用 查看 <br><br><br>#3楼 2007-03-10 14:13 补丁 <br>好~! <br> 回复 引用 查看 <br><br><br>#4楼 2007-03-12 12:46 neoragex2002 <br>呵呵,ICTCLAS的核心算法总算出来了 <br> 回复 引用 查看 <br><br><br>#5楼 [楼主] 2007-03-12 15:34 吕震宇 <br>@neoragex2002 <br>其实到目前为止SharpICTCLAS基本完工,也可以完成词性标注等工作,迟迟没有将完成代码放上来的一个原因就是希望能得到张华平、刘群的授权。我已经发了Mail,正在等待回信。 <br> 回复 引用 查看 <br><br><br>#6楼 2007-03-12 19:54 neoragex2002 <br>呵呵,其实应该也没什么大问题吧,毕竟是很早的成果了,而且张刘也公开发表了相关内容的文章的,只要注明了credits,相信他们也不会表示不满吧。 <br> 回复 引用 查看 <br><br><br>#7楼 2007-03-15 17:39 sinboy [未注册用户] <br>@吕震宇 <br>以前曾给张华平发过一个EMail,一直没有回复,但估计他现在早已离开了中科院软件所 <br> 回复 引用 查看 <br><br><br>#8楼 2007-05-11 14:29 ChineseAlexander [未注册用户] <br>不好意思,我问一上每条边上的权值具体是怎么计算的? <br> 回复 引用 查看 <br><br><br>#9楼 2007-09-21 17:00 kenlistian [未注册用户] <br>感谢楼主把这个n-最短路径讲解的这么清楚,虽源码没有仔细读,但是对于n最短的方法明白了. 原来学数据结构这些忘光了. <br> 回复 引用 查看 <br>

2008-01-21

UserDgHtml

<%@ Control Language="vb" AutoEventWireup="false" Inherits="MOTOANS_REPORT_GSM.UserDG" CodeFile="UserDG.ascx.vb" %><br><LINK href="StyleSheetMain.css" type="text/css" rel="stylesheet"><br><table cellSpacing="0" cellPadding="0" width="100%"><br> <% if NavigationVisible then %><br> <tr class="tr1"><br> <td noWrap><br> <table><br> <tr><br> <td noWrap><asp:label id="Sum" CssClass="Label1" runat="server"></asp:label>|<asp:label id="Count" CssClass="Label1" runat="server"></asp:label>|<asp:label id="Cur" CssClass="Label1" runat="server"></asp:label><asp:button id="FirstPage" CssClass="button2" runat="server" Text="第一页"></asp:button><asp:button id="PrePage" CssClass="button2" runat="server" Text="上一页"></asp:button><asp:button id="NextPage" CssClass="button2" runat="server" Text="下一页"></asp:button><asp:button id="LastPage" CssClass="button2" runat="server" Text="最后页"></asp:button><asp:label id="LabelGo" CssClass="Label1" runat="server">到第</asp:label><asp:textbox id="PageNum" CssClass="TextBox" runat="server" MaxLength="4" Width="40px"></asp:textbox><asp:label id="LabelTo" CssClass="Label1" runat="server">页</asp:label><asp:button id="ButtonGo" CssClass="button2" runat="server" Text="GO"></asp:button><br> <!--默认纪录数--><br> <asp:Label ID="Label_RecordCount" Runat="server" CssClass="Label1">最大记录集数</asp:Label><asp:TextBox ID="txt_RecordCount" Width="40" Runat="server" CssClass="Textbox"></asp:TextBox><br> <asp:button id="ButtonDownLoad" CssClass="button1" runat="server" Text="导出"></asp:button><asp:button id="ButtonOrder" CssClass="button1" runat="server" Text="多重排序"></asp:button><asp:button id="ButtonCust" CssClass="button1" runat="server" Text="定制"></asp:button><asp:button id="ButtonReturn" CssClass="button1" runat="server" Text="关闭"></asp:button><br> </td><br> </tr><br> </table><br> </td><br> </tr><br> <tr><br> <% End IF %><br> <td noWrap Width=<%=viewstate("tablewidth")%>><asp:datagrid id="DG" runat="server" Width="100%" BorderStyle="None" CellPadding="1" onSortCommand="SortGrid"<br> onPageindexchanged="pageGrid" GridLines="Vertical" PageSize="20" BorderWidth="0px" Height="65px"<br> CellSpacing="1" BorderColor="#E7E7FF" BackColor="White" Font-Size="X-Small"><br> <SelectedItemStyle Font-Bold="True" ForeColor="#F7F7F7" BackColor="#738A9C"></SelectedItemStyle><br> <AlternatingItemStyle Wrap="False" ForeColor="Black" BackColor="AliceBlue"></AlternatingItemStyle><br> <ItemStyle BorderWidth="1px" ForeColor="Black" BorderColor="SteelBlue" BackColor="Gainsboro"></ItemStyle><br> <HeaderStyle Font-Size="X-Small" Font-Bold="True" HorizontalAlign="Center" ForeColor="Black"<br> VerticalAlign="Top" BackColor="#99CCFF"></HeaderStyle><br> <PagerStyle Visible="False" NextPageText="下一页" Font-Size="X-Small" PrevPageText="上一页" HorizontalAlign="Left"<br> ForeColor="#4A3C8C" BackColor="LightGray" Wrap="False" Mode="NumericPages"></PagerStyle><br> </asp:datagrid></td><br> </tr><br> <% if NavigationVisible then %><br> <tr class="tr1"><br> <td noWrap><br> <table><br> <tr><br> <td noWrap><asp:label id="Sum1" CssClass="Label1" runat="server"></asp:label>|<asp:label id="Count1" CssClass="Label1" runat="server"></asp:label>|<asp:label id="Cur1" CssClass="Label1" runat="server"></asp:label><asp:button id="FirstPage1" CssClass="Button2" runat="server" Text="第一页"></asp:button><asp:button id="PrePage1" CssClass="Button2" runat="server" Text="上一页"></asp:button><asp:button id="NextPage1" CssClass="Button2" runat="server" Text="下一页"></asp:button><asp:button id="LastPage1" CssClass="Button2" runat="server" Text="最后页"></asp:button><asp:label id="LabelGo1" CssClass="Label1" runat="server">到第</asp:label><asp:textbox id="PageNum1" CssClass="TextBox" MaxLength="4" Width="40px" Runat="server"></asp:textbox><asp:label id="LabelTo1" CssClass="Label1" runat="server">页</asp:label><asp:button id="ButtonGo1" CssClass="button2" runat="server" Text="GO"></asp:button><br> </td><br> </tr><br> </table><br> </td><br> </tr><br> <% End IF %><br></table><br>

2008-01-06

pageshuoming

VS2005 分页自定义控件,测试环境在:VS2005+SQL2005下通过<br><br>演示说明:前台ASPX页(可以绑定的控件是:DataGrid,GridView,Repeater,DataList等等)<br>1:先注册一下控件,不要跟我说看不懂下面这句<br><%@ Register Assembly="CommonClass" Namespace="ng.Common.WebControls" TagPrefix="efp" %><br><br>2:绑定,更加简单,在适合的位置放上这句分页代码:(还有些属性自己试试)<br><efp:PagerBar ID="pbComment" runat="server" EnableViewState="False" PageSize="20"></efp:PagerBar><br><br>3:后台绑定:(更加简单)<br> int recordCount;//总记录数<br> CategoryData cd = new CategoryData();<br> List<CategoryInfo> ciList = cd.GetSoftList(this.pbComment.CurrentPage, this.pbComment.PageSize, out recordCount);//传递参数,必须要有这三个<br> pbComment.RecordCount = recordCount;//因为是输出参数,所以得到他的总记录数<br> GridView1.DataSource = ciList;//最后绑定<br> GridView1.DataBind();<br><br>4:SQL语句<br>Create PROCEDURE [dbo].[SP_Soft_GetSoftList]<br> @CurrentPage int, @PageSize int, @RecordCount int output<br>AS<br> DECLARE @MinPage int, @MaxPage int<br> SET @MinPage = (@CurrentPage - 1) * @PageSize + 1<br> SET @MaxPage = @MinPage + @PageSize<br> <br> BEGIN<br> SELECT * FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY SoftID DESC) AS RowNumber FROM V_SoftCategoryAndSoftInfo ) AS A WHERE RowNumber BETWEEN @MinPage AND @MaxPage<br> <br> SELECT @RecordCount = COUNT(SoftID) FROM Soft_Info<br> END<br><br>注意:sql2005的新特性:ROW_NUMBER(),自己查帮助看看介绍,实在太爽了这个,V_SoftCategoryAndSoftInfo 是我的视图.,因为泄及几个表,所以只好建立这个视图了,如果你的语句比较简单,就直接写表名就行了.\\\<br><br><br><br>就这样,完成了,简单不,测试时,完成了500万条记录测试,速度超前,可以使用在静态页,.或动态页的分页,如果大家以前有看过我写的VS2005智能化生成静态页的,那么大家会觉得很熟识.没错,分页也是这个控件,爽不...<br><br>目前功能只做了:记录数,.当前页数,首页,上一页,下一页,未页,和一个下拉框的导航,至于数字导航的,近期推出,密切留意.<br><br><br>测试环境是在VS2005+SQL2005下通过的,如果你也想用这个组件的,你可以用SQL2000也可以,但我没试过.不妨试一下吧,多点研究还是好的.<br><br><br>OK:演讲完毕,该精品由NET博览群,独家制作和发布,发布和制作人:ng<br><br><br><br>

2008-01-06

procedure

-----------ALTER BY aaaa 20070815<br><br>CREATE PROCEDURE CM_Carrier_Business_Logic <br>@cm_id varchar(50)<br>AS<br>begin tran<br> <br> /*从info中往history搬移数据,首先要判断info中是否有数据,如果有就循环插入到history中*/<br> <br> declare @omc_name varchar(50) <br> set @omc_name=substring(@cm_id ,1,charindex('.',@cm_id )-1) <br><br> -- Modified by YYS 2006-8-18<br> declare @cm_id_carrier varchar(50)<br> select @cm_id_carrier= isnull(max(cm_id),'') from CM_Carrier_New where cm_id like @omc_name +'%'<br> if @cm_id <> ''<br> Update CM_Carrier_New set cm_id= @cm_id where cm_id=@cm_id_carrier<br> -- END YYS<br><br> INSERT INTO cm_carrier_history <br> select * from cm_carrier_info where omc_name = @omc_name<br><br> <br> IF @@ERROR <> 0<br> BEGIN<br> RAISERROR('数据写入cm_carrier_history表出错,数据搬移终止!',18,1)<br> rollback transaction<br> RETURN<br> END <br> <br>-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<br>-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<br>commit transaction<br>GO<br>SET QUOTED_IDENTIFIER OFF <br>GO<br>SET ANSI_NULLS ON <br>GO

2008-01-06

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除