1. 程式人生 > >語音識別的大規模漢語樹形詞典,搜尋速度快如閃電

語音識別的大規模漢語樹形詞典,搜尋速度快如閃電

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               
  1.  #include "stdafx.h"    
  2. #include "YuyinTree.h"    
  3. #include "YuyinTreeDlg.h"    
  4.    
  5. #ifdef _DEBUG    
  6. #define new DEBUG_NEW    
  7. #undef THIS_FILE    
  8. static char THIS_FILE[] = __FILE__;   
  9. #endif 
      
  10.    
  11. /////////////////////////////////////////////////////////////////////////////    
  12. // CAboutDlg dialog used for App About    
  13. CStoredPinyin* m_storedPinyin[30000];   
  14. CWordTree* curTree=new CWordTree;      //指向詞語樹指標 
      
  15. CString MaxLenghci='/'';                  //儲存該單詞包括的最大子詞    
  16. CString Tempci;                       //臨時詞    
  17. int StoredNum=0;       //已存入查詢陣列中拼音個數    
  18. class CAboutDlg : public CDialog   
  19. {   
  20. public:   
  21.     CAboutDlg();   
  22.    
  23. // Dialog Data    
  24.     //{{AFX_DATA(CAboutDlg)    
  25.     enum { IDD = IDD_ABOUTBOX };   
  26.     //}}AFX_DATA    
  27.    
  28.     // ClassWizard generated virtual function overrides    
  29.     //{{AFX_VIRTUAL(CAboutDlg)    
  30.     protected:   
  31.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support    
  32.     //}}AFX_VIRTUAL    
  33.    
  34. // Implementation    
  35. protected:   
  36.     //{{AFX_MSG(CAboutDlg)    
  37.     //}}AFX_MSG    
  38.     DECLARE_MESSAGE_MAP()   
  39. };   
  40.    
  41. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)   
  42. {   
  43.     //{{AFX_DATA_INIT(CAboutDlg)    
  44.     //}}AFX_DATA_INIT    
  45. }   
  46.    
  47. void CAboutDlg::DoDataExchange(CDataExchange* pDX)   
  48. {   
  49.     CDialog::DoDataExchange(pDX);   
  50.     //{{AFX_DATA_MAP(CAboutDlg)    
  51.     //}}AFX_DATA_MAP    
  52. }   
  53.    
  54. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)   
  55.     //{{AFX_MSG_MAP(CAboutDlg)    
  56.         // No message handlers    
  57.     //}}AFX_MSG_MAP    
  58. END_MESSAGE_MAP()   
  59.    
  60. /////////////////////////////////////////////////////////////////////////////    
  61. // CYuyinTreeDlg dialog    
  62.    
  63. CYuyinTreeDlg::CYuyinTreeDlg(CWnd* pParent /*=NULL*/)   
  64.     : CDialog(CYuyinTreeDlg::IDD, pParent)   
  65. {   
  66.     //{{AFX_DATA_INIT(CYuyinTreeDlg)    
  67.     m_inputTongyin = _T("");   
  68.     //}}AFX_DATA_INIT    
  69.     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32    
  70.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);   
  71. }   
  72.    
  73. void CYuyinTreeDlg::DoDataExchange(CDataExchange* pDX)   
  74. {   
  75.     CDialog::DoDataExchange(pDX);   
  76.     //{{AFX_DATA_MAP(CYuyinTreeDlg)    
  77.     DDX_Text(pDX, IDC_PINYIN_EQUAL, m_inputTongyin);   
  78.     //}}AFX_DATA_MAP    
  79. }   
  80.    
  81. BEGIN_MESSAGE_MAP(CYuyinTreeDlg, CDialog)   
  82.     //{{AFX_MSG_MAP(CYuyinTreeDlg)    
  83.     ON_WM_SYSCOMMAND()   
  84.     ON_WM_PAINT()   
  85.     ON_WM_QUERYDRAGICON()   
  86.     ON_BN_CLICKED(IDC_BTN_READFILE, OnBtnReadfile)   
  87.     ON_BN_CLICKED(IDC_BTN_TEST_PANDCHI, OnBtnTestPandchi)   
  88.     ON_BN_CLICKED(IDC_BTN_TEST_TONGYINCI, OnBtnTestTongyinci)   
  89.     ON_BN_CLICKED(IDC_YUYIN_QUERY, OnTongyinQuery)   
  90.     ON_NOTIFY(TVN_SELCHANGED, IDC_YUYIN_TREE, OnSelchangedYuyinTree)   
  91.     //}}AFX_MSG_MAP    
  92. END_MESSAGE_MAP()   
  93.    
  94. /////////////////////////////////////////////////////////////////////////////    
  95. // CYuyinTreeDlg message handlers    
  96.    
  97. BOOL CYuyinTreeDlg::OnInitDialog()   
  98. {   
  99.     CDialog::OnInitDialog();   
  100.    
  101.     // Add "About..." menu item to system menu.    
  102.    
  103.     // IDM_ABOUTBOX must be in the system command range.    
  104.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);   
  105.     ASSERT(IDM_ABOUTBOX < 0xF000);   
  106.    
  107.     CMenu* pSysMenu = GetSystemMenu(FALSE);   
  108.     if (pSysMenu != NULL)   
  109.     {   
  110.         CString strAboutMenu;   
  111.         strAboutMenu.LoadString(IDS_ABOUTBOX);   
  112.         if (!strAboutMenu.IsEmpty())   
  113.         {   
  114.             pSysMenu->AppendMenu(MF_SEPARATOR);   
  115.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);   
  116.         }   
  117.     }   
  118.    
  119.     // Set the icon for this dialog.  The framework does this automatically    
  120.     //  when the application's main window is not a dialog    
  121.     SetIcon(m_hIcon, TRUE);         // Set big icon    
  122.     SetIcon(m_hIcon, FALSE);        // Set small icon    
  123.        
  124.     // TODO: Add extra initialization here    
  125.        
  126.     //程式新增的程式碼:    
  127.     //初始化已讀單詞陣列    
  128.     for(int i=0;i<30000;i++)   
  129.     {   
  130.         m_storedPinyin[i]=NULL;   
  131.     }   
  132.     FILE *InputFile=NULL;   //讀取檔案指標    
  133.     CTreeNode* CurNode=NULL;  //當前節點    
  134.     CTreeNode* FatherNode=NULL; //當前節點的父節點    
  135.     TCHAR NodeItem[100];   //節點的全部資料     
  136.     TCHAR NodePinyin[51];  //節點的拼音    
  137.     TCHAR NodeHanzi[50];   //節點漢字    
  138.     int ZiMuNum,j,k;   
  139.     int WordNum=0;         //統計詞的數目    
  140.     BOOL IsFirst=TRUE;      //標誌是否是根節點的第一個孩子節點    
  141.     CTreeNode* TempfatherNode=NULL;             //臨時父節點    
  142.     CTreeNode* TempfatherNode1=NULL;             //臨時父節點    
  143.     InputFile=fopen("LexiconTree.txt","r");   
  144.    
  145.     while(!feof(InputFile))   
  146.     {   
  147.         WordNum++;   
  148.         fscanf(InputFile,"%s",NodeItem);   
  149.         ZiMuNum=0;        //ZiMuNum為讀取字母個數    
  150.         while(NodeItem[ZiMuNum]!=',')//讀取漢字    
  151.         {   
  152.             NodeHanzi[ZiMuNum]=NodeItem[ZiMuNum];   
  153.             ZiMuNum++;   
  154.         }   
  155.         NodeHanzi[ZiMuNum]='/0';// 此時NodeHanzi儲存了漢字    
  156.         ZiMuNum++;   
  157.            
  158.            
  159.         while(NodeItem[ZiMuNum]!=',')//讀取詞號    
  160.         {   
  161.             ZiMuNum++;   
  162.         }   
  163.         ZiMuNum++;   
  164.         j=ZiMuNum;   
  165.         k=0;   
  166.         while(NodeItem[j]!='/0')  //讀拼音    
  167.         {   
  168.             NodePinyin[k]=NodeItem[j];   
  169.             k++;   
  170.             j++;   
  171.         }   
  172.         NodePinyin[k-1]='/0'//此時NodePinyin儲存了拼音    
  173.         CString TempString;  //暫時儲存拼音    
  174.         TempString=NodePinyin;   
  175.            
  176.         CurNode=new CTreeNode;   
  177.         CurNode->m_Pinyin=TempString;   
  178.         CurNode->m_Word=NodeHanzi;   
  179.         CurNode->m_pParent=NULL;   
  180.         CurNode->m_pchild=NULL;   
  181.         CurNode->m_pneighbour=NULL;   
  182.         CurNode->m_pchar=NULL;   
  183.         CurNode->m_CurNum=0;   
  184.         BOOL Fviewed=FALSE;     //是否查到的標誌,預設為沒查到    
  185.         BOOL FParent=FALSE;     //接點是否有父節點的標誌,如a,;a,ba,;a,ba,hao,    
  186.         BOOL FEqual=FALSE;       //相同發音詞標誌,如a,啊,阿,呵    
  187.         for(int temp=0;temp<30000;temp++) //temp為迭代次數,先檢檢視看是否已經插入了詞    
  188.         {   
  189.             if(m_storedPinyin[temp]!=NULL)       //看當前檢視的資料項是否有值,若有進入迴圈,否則跳過    
  190.             {   
  191.                 int t=-1;   
  192.                 t=TempString.Find(m_storedPinyin[temp]->m_StoredPinyin);       //find 的意思是找到整個匹配串    
  193.                 if(t>=0)         //若有重疊項,進入語句,插資料項    
  194.                 {   
  195.                        
  196.                     if(TempString==m_storedPinyin[temp]->m_StoredPinyin)  //若兩者拼音完全相同,把漢字插入樹節點項的相似字陣列中    
  197.                     {   
  198.                         Fviewed=TRUE;       //查到    
  199.                         FEqual=TRUE;        //相同詞標記TRUE    
  200.                         int TempCurNum=(m_storedPinyin[temp]->m_pcurPosition)->m_CurNum;   
  201.                           
  202.                         CTongyinci* temp1=new CTongyinci;   
  203.                         temp1->next=NULL;   
  204.                         temp1->m_data=new char[50];   
  205.                         strcpy(temp1->m_data,NodeHanzi);   
  206.                            
  207.                         CTongyinci* temp2=(m_storedPinyin[temp]->m_pcurPosition)->m_pchar;   
  208.                         CTongyinci* pre;   
  209.                         while(temp2!=NULL)   
  210.                         {   
  211.                             pre=temp2;   
  212.                             temp2=temp2->next;   
  213.                         }   
  214.                         pre->next=temp1;   
  215.        
  216.                         (m_storedPinyin[temp]->m_pcurPosition)->m_CurNum=(m_storedPinyin[temp]->m_pcurPosition)->m_CurNum+1;   
  217.                         break;   
  218.                     }   
  219.                     else if(t==0)         //否則,插入樹節點項的子節點中,必需保證從第一個字對齊並且在待檢查接點中重疊部分後一位為",",檢查    
  220.                     {                     //比如a和an不能是父子節點關係;la和a不能是父子節點關係    
  221.                            
  222.                            
  223.                         Tempci=m_storedPinyin[temp]->m_StoredPinyin;   
  224.                         int Strsize=Tempci.GetLength();     //問題    
  225.    
  226.                         if(TempString.GetAt(Strsize)==',')   //若滿足重疊部分後一位為","    
  227.                         {   
  228.                             FParent=TRUE;         //有父親節點    
  229.                             if(Strsize>=MaxLenghci.GetLength())   
  230.                             {   
  231.                                MaxLenghci=Tempci;           //注意    
  232.                                TempfatherNode1=m_storedPinyin[temp]->m_pcurPosition;  //注意    
  233.                             }   
  234.                                
  235.                         Fviewed=TRUE;       //查到    
  236.                         }   
  237.                            
  238.                     }   
  239.                        
  240.                 }   
  241.             }   
  242.             else     
  243.                 continue;   
  244.         }   
  245.         if(FParent&&!FEqual)   
  246.         {   
  247.                        CurNode->m_CurNum++;                                      //當前同音字數加1    
  248.        
  249. /*                      char** pTempChar=new char*[50];                                   //開闢一個而維陣列,臨時值向同音字的指標  
  250.                         for(int l=0;l<50;l++)  
  251.                         {  
  252.                             pTempChar[l]=new char[50];  
  253.                             pTempChar[l][0]='/0';  
  254.                         }  
  255.                         */   
  256.                         CTongyinci* temp=new CTongyinci;   
  257.                         temp->next=NULL;   
  258.    
  259.                         temp->m_data=new char[50];   
  260.                         strcpy(temp->m_data,NodeHanzi);   
  261.                         CurNode->m_pchar=temp;   
  262.                            
  263.                         curTree->InsertNode(&CurNode,&TempfatherNode1);   //在查到的節點處插入子節點    
  264.    
  265.                         CStoredPinyin* TempStorPinyin1=new CStoredPinyin;                      //建立臨時待查詢物件    
  266.                           
  267.                         TempStorPinyin1->m_pcurPosition=CurNode;   
  268.                         TempStorPinyin1->m_StoredPinyin=TempString;   
  269.                         TempStorPinyin1->m_pchar=temp;   
  270.                         m_storedPinyin[StoredNum++]=TempStorPinyin1;     //將產生節點存放已訪問陣列中    
  271.         }   
  272.         MaxLenghci='/0';        //恢復用到的兩個變數到初值    
  273.         TempfatherNode1=NULL;   
  274.    
  275.         if(!Fviewed)        //如果在已存詞表中找不到該詞則在根節點插入新詞,並存放在已訪問陣列中    
  276.         {   
  277.                
  278.                
  279.             if(IsFirst==TRUE)   
  280.             {   
  281.               TempfatherNode=curTree->m_Root;                    
  282.             }     
  283.    
  284.             CurNode->m_CurNum++;                                      //當前同音字數加1    
  285.    
  286.                
  287.                
  288. /*          char** pTempChar=new char*[50];                                   //開闢一個而維陣列,臨時值向同音字的指標,存100個詞  
  289.             for(int l=0;l<50;l++)  
  290.             {  
  291.                 pTempChar[l]=new char[10];  
  292.                 pTempChar[l][0]='/0';  
  293.             }  
  294.               
  295.   
  296.             CurNode->m_pchar=pTempChar;  
  297.             strcpy(CurNode->m_pchar[0],NodeHanzi);*/   
  298.             CTongyinci* temp=new CTongyinci;   
  299.             temp->next=NULL;   
  300.             temp->m_data=new char[50];   
  301.             strcpy(temp->m_data,NodeHanzi);   
  302.             CurNode->m_pchar=temp;   
  303.                
  304.             TempfatherNode=curTree->InsertFirstNode(&CurNode,&TempfatherNode);   //在根節點插入新詞    
  305.             IsFirst=FALSE;                                                       //以後插入的點全不是第一個節點    
  306.    
  307.             CStoredPinyin* TempStorPinyin;  //建立臨時待查詢物件    
  308.             TempStorPinyin=new CStoredPinyin;   
  309.                
  310.             TempStorPinyin->m_pcurPosition=CurNode;   
  311.             TempStorPinyin->m_StoredPinyin=NodePinyin;   
  312.             TempStorPinyin->m_pchar=temp;   
  313.                
  314.             //排錯flag   pass 10月21號    
  315.             m_storedPinyin[StoredNum]=TempStorPinyin;     //將產生節點存放已訪問陣列中    
  316.             StoredNum++;   
  317.         }   
  318.              
  319.     }   
  320.     char buffer[50];   
  321.     sprintf(buffer,"已讀取單詞: %d",WordNum);   
  322.        
  323.         AfxMessageBox(buffer);   
  324.         BrowseYuyin();   
  325.    
  326.     return TRUE;  // return TRUE  unless you set the focus to a control    
  327. }   
  328.    
  329. void CYuyinTreeDlg::OnSysCommand(UINT nID, LPARAM lParam)   
  330. {   
  331.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)   
  332.     {   
  333.         CAboutDlg dlgAbout;   
  334.         dlgAbout.DoModal();   
  335.     }   
  336.     else   
  337.     {   
  338.         CDialog::OnSysCommand(nID, lParam);   
  339.     }   
  340. }   
  341.    
  342. // If you add a minimize button to your dialog, you will need the code below    
  343. //  to draw the icon.  For MFC applications using the document/view model,    
  344. //  this is automatically done for you by the framework.    
  345.    
  346. void CYuyinTreeDlg::OnPaint()    
  347. {   
  348.     if (IsIconic())   
  349.     {   
  350.         CPaintDC dc(this); // device context for painting    
  351.    
  352.         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);   
  353.    
  354.         // Center icon in client rectangle    
  355.         int cxIcon = GetSystemMetrics(SM_CXICON);   
  356.         int cyIcon = GetSystemMetrics(SM_CYICON);   
  357.         CRect rect;   
  358.         GetClientRect(&rect);   
  359.         int x = (rect.Width() - cxIcon + 1) / 2;   
  360.         int y = (rect.Height() - cyIcon + 1) / 2;   
  361.    
  362.         // Draw the icon    
  363.         dc.DrawIcon(x, y, m_hIcon);   
  364.     }   
  365.     else   
  366.     {   
  367.         CDialog::OnPaint();   
  368.     }   
  369. }   
  370.    
  371. // The system calls this to obtain the cursor to display while the user drags    
  372. //  the minimized window.    
  373. HCURSOR CYuyinTreeDlg::OnQueryDragIcon()   
  374. {   
  375.     return (HCURSOR) m_hIcon;   
  376. }   
  377.    
  378.    
  379. // 新增的主要程式碼    
  380. void CYuyinTreeDlg::OnBtnReadfile()          //測試樹第一層節點    
  381. {   
  382.      //檢驗第一層節點插入是否正確,結果正確    
  383.      CTreeNode* root=curTree->m_Root;   
  384.      CTreeNode* Temp=root->m_pchild;   
  385.      while(Temp!=NULL)   
  386.      {   
  387.        AfxMessageBox(Temp->m_Pinyin);   
  388.        Temp=Temp->m_pneighbour;   
  389.      }   
  390. }   
  391.    
  392.    
  393.    
  394. CWordTree::CWordTree()   //樹的初始化    
  395. {   
  396.     m_Root=new CTreeNode;   
  397.     m_Root->m_Pinyin="";   
  398.     m_Root->m_pParent=NULL;   
  399.     m_Root->m_pchild=NULL;   
  400.     m_Root->m_pneighbour=NULL;   
  401.     m_Root->m_CurNum=0;   
  402.     m_Root->m_Word="";   
  403.     m_Root->m_pchar=NULL;   
  404. }   
  405.    
  406. void CWordTree::CreateTree()   
  407. {   
  408.        
  409. }   
  410. CTreeNode* CWordTree::InsertFirstNode(CTreeNode** newNode,CTreeNode** parent)       //插入第一層節點    
  411. {   
  412.        
  413.     CTreeNode* WilladNode=*newNode;   
  414.     CTreeNode* FatherNode=*parent;   
  415.     if(FatherNode==curTree->m_Root)   
  416.     {   
  417.         FatherNode->m_pchild=WilladNode;   
  418.         WilladNode->m_pParent=curTree->m_Root;   
  419.     }   
  420.     else   
  421.     {   
  422.         FatherNode->m_pneighbour=WilladNode;   
  423.         WilladNode->