基于有序二叉树的专家系统应用——动物游戏(C++)

二、设计与实现

1、设计思想

      建立一个有序二叉树作为决策树,用来作为专家系统的知识库。决策树中的叶子结点存储各种动物的名称,其他节点存储有关动物特征的问题。从根节点开始,访问节点的内容。如果是节点内容是问题,由用户回答“是”、“否”。若回答“是”,访问左孩子结点,若回答否,访问右孩子节点,直到节点的内容为动物名称为止。此时,程序给出猜测结果。如果猜对,专家胜利。如果猜错,用户给出动物名称和特征,程序根据两者更改决策树、添加新的节点。

2、类结构

基于有序二叉树的专家系统应用——动物游戏(C++)

基于有序二叉树的专家系统应用——动物游戏(C++)

 

 

3、主要数据结构

主要的数据结构是链栈和二叉树。

二叉树,用来作为决策树,叶节点存储动物名称,其他节点存储有关动物特征的问题。同时对于每个问题节点,回答“是”对应的是左孩子节点,回答“否”对应的右孩子节点。

链栈在从文件中读取决策树中起作用。由于在文件中存储的决策树是按照后序遍历的方式存入的。在读取决策树的时候,也按照后序的次序建立相应的节点。栈中存储的是即将建立的双亲结点的孩子节点。也就是在每一轮中,首先被读入的是两个孩子节点,被存入到栈中,当读到它们的双亲结点时,两个孩子节点出栈,作为双亲结点的左右孩子后,双亲结点入栈。

4、算法设计

基于有序二叉树的专家系统应用——动物游戏(C++)

 

5、核心代码展示

static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    int wmId, wmEvent;
    wmId = LOWORD(wParam);
    wmEvent = HIWORD(wParam);
    HDC hdc;
    PAINTSTRUCT ps;
    switch (message)
    {
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);

        // To paint with a DDB it first needs to be associated
        // with a memory device context. We make a DC that
        // is compatible with the screen by passing NULL to
        // CreateCompatibleDC.
        // Then we need to associate our saved bitmap with the
        // device context.

        HDC hdcMem = CreateCompatibleDC(NULL);
        HBITMAP hbmT = SelectBitmap(hdcMem, hbm);

        // Now, the BitBlt function is used to transfer the contents of the 
        // drawing surface from one DC to another. Before we can paint the
        // bitmap however we need to know how big it is. We call the GDI
        // function GetObject to get the relevent details.
        BITMAP bm;
        GetObject(hbm, sizeof(bm), &bm);

        BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);

        // Now, clean up. A memory DC always has a drawing
        // surface in it. It is created with a 1X1 monochrome
        // bitmap that we saved earlier, and need to put back
        // before we destroy it.
        SelectBitmap(hdcMem, hbmT);
        DeleteDC(hdcMem);

        // EndPaint balances off the BeginPaint call.
        EndPaint(hWnd, &ps);

        break;
    }
    case WM_CREATE:
    { static2 = CreateWindow(TEXT("STATIC"), TEXT("欢迎来到专家系统应用"), WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 10, 500, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
    SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
    button5 = CreateWindow(TEXT("BUTTON"), TEXT("进入专家系统应用"), WS_CHILD | WS_VISIBLE, 360, 100, 150, 40, hWnd, (HMENU)IDC_BUTTON5, NULL, NULL);
    SendMessage(button5, WM_SETFONT, (WPARAM)hFont, 1);
    HINSTANCE hInstance = GetWindowInstance(hWnd);
    //hbm = LoadBitmapW(hInstance,MAKEINTRESOURCE(IDB_BITMAP1));//C:\\Users\\Administrator.33XBYKMCA2C5EX4\Desktop\SpecPic
    hbm = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
    return 0;
    }
    case WM_COMMAND:
    {
        HWND hwndTmp;
        int wmId = LOWORD(wParam);
        switch (wmId)
        {
        case ID_40003:
        {
            MessageBox(hWnd, TEXT("开发人员名单:武祎、王艺然、何鸿丞、辛喆\n开发时间:2020年6月\n版本号:8.0\n学校:北京理工大学"), TEXT("开发者信息"), MB_OK);
            break;
        }
        case ID_40001:
        {
            MessageBox(hWnd, in_address, TEXT("当前决策树的文件路径"), MB_OK);
            break;
        }
        case ID_40004:
        {
            AnimalNumber();
            MessageBox(hWnd, t_num,TEXT ("决策树中的动物数量"), MB_OK);
            break;
        }
        case ID_40005:
        {
            if (IsTreeEmpty())
            {
                MessageBox(hWnd, TEXT("当前决策树为空!"), TEXT("提示"), MB_ICONWARNING);
            }
            else
            {
                TCHAR2Char(in_address, a);
                Save(hWnd);
            }
            break;
        }
        case ID_40006:
        {
            TCHAR2Char(in_address, a);
            Build(hWnd);
            break;
        }
        case IDC_BUTTON3:
            GetDlgItemText(hWnd, IDC_EDIT1, address, 100);
            TCHAR2Char(address, a);
            if (Build(hWnd))
            {
                if (flag == 0)
                {
                    static3 = CreateWindow(TEXT("STATIC"), TEXT("后序遍历输出的语句"), WS_CHILD | WS_VISIBLE|WS_EX_TRANSPARENT, 10, 200, 200, 20, hWnd, (HMENU)IDC_STATIC3, NULL, NULL);
                    SendMessage(static3, WM_SETFONT, (WPARAM)hFont, 1);
                    edit2=CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE|WS_HSCROLL|WS_VSCROLL , 10, 220, 300, 200, hWnd, (HMENU)IDC_EDIT2, NULL, NULL);
                    SendMessage(edit2, WM_SETFONT, (WPARAM)hFont, 1);
                    flag++;
                }
                GetDlgItemText(hWnd, IDC_EDIT1, in_address, 100);
                Display(hWnd);
            }
            break;
        case IDC_BUTTON4:
        {
           
            if (Expert(-1, hWnd))
            {
               
            }
            else
            {
                ClearAllWindows();
                static1 = CreateWindow(TEXT("STATIC"), TEXT("猜动物"), WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 10, 50, 20, hWnd, (HMENU)IDC_STATIC1, NULL, NULL);
                SendMessage(static1, WM_SETFONT, (WPARAM)hFont, 1);
                static2 = CreateWindow(TEXT("STATIC"), question, WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 50, 500, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
                SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
                button5 = CreateWindow(TEXT("BUTTON"), TEXT("结束本轮游戏"), WS_CHILD | WS_VISIBLE, 360, 300, 120, 30, hWnd, (HMENU)IDC_BUTTON5, NULL, NULL);
                SendMessage(button5, WM_SETFONT, (WPARAM)hFont, 1);
                button8 = CreateWindow(TEXT("BUTTON"), TEXT("是"), WS_CHILD | WS_VISIBLE, 10, 100, 60, 30, hWnd, (HMENU)IDC_BUTTON8, NULL, NULL);
                SendMessage(button8, WM_SETFONT, (WPARAM)hFont, 1);
                button11 = CreateWindow(TEXT("BUTTON"), TEXT("否"), WS_CHILD | WS_VISIBLE, 100, 100, 60, 30, hWnd, (HMENU)IDC_BUTTON11, NULL, NULL);
                SendMessage(button11, WM_SETFONT, (WPARAM)hFont, 1);
            }
            break;
            
        }
        case IDC_BUTTON8:
        {
            if (!Expert(1, hWnd))
            {
                DestroyWindow(static2);
                static2 = NULL;
                static2 = CreateWindow(TEXT("STATIC"), question, WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 50, 500, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
                SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
            }
            else
            {
                DestroyWindow(static2);
                static2 = NULL;
                static2 = CreateWindow(TEXT("STATIC"), question, WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 50, 500, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
                SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
                DestroyWindow(button8);
                button8 = NULL;
                DestroyWindow(button11);
                button11 = NULL;
                button12 = CreateWindow(TEXT("BUTTON"), TEXT("猜对了"), WS_CHILD | WS_VISIBLE, 10, 250, 60, 30, hWnd, (HMENU)IDC_BUTTON12, NULL, NULL);
                SendMessage(button12, WM_SETFONT, (WPARAM)hFont, 1);
                button13 = CreateWindow(TEXT("BUTTON"), TEXT("猜错了"), WS_CHILD | WS_VISIBLE, 100, 250, 60, 30, hWnd, (HMENU)IDC_BUTTON13, NULL, NULL);
                SendMessage(button13, WM_SETFONT, (WPARAM)hFont, 1);
            }
            break;
        }
        case IDC_BUTTON11:
        {
            if (!Expert(0, hWnd))
            {
                DestroyWindow(static2);
                static2 = NULL;
                static2 = CreateWindow(TEXT("STATIC"), question, WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 50, 500, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
                SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
            }
            else
            {
                DestroyWindow(static2);
                static2 = NULL;
                static2 = CreateWindow(TEXT("STATIC"), question, WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 50, 500, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
                SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
                DestroyWindow(button8);
                button8 = NULL;
                DestroyWindow(button11);
                button11 = NULL;
                button12 = CreateWindow(TEXT("BUTTON"), TEXT("猜对了"), WS_CHILD | WS_VISIBLE, 10, 250, 60, 30, hWnd, (HMENU)IDC_BUTTON12, NULL, NULL);
                SendMessage(button12, WM_SETFONT, (WPARAM)hFont, 1);
                button13 = CreateWindow(TEXT("BUTTON"), TEXT("猜错了"), WS_CHILD | WS_VISIBLE, 100, 250, 60, 30, hWnd, (HMENU)IDC_BUTTON13, NULL, NULL);
                SendMessage(button13, WM_SETFONT, (WPARAM)hFont, 1);

            }
            break;
        }
      
        case IDC_BUTTON5:
        {
            ClearAllWindows();
            static2 = CreateWindow(TEXT("STATIC"), TEXT("菜单"), WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 10, 50, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
            SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
            button4 = CreateWindow(TEXT("BUTTON"), TEXT("进入猜动物环节"), WS_CHILD | WS_VISIBLE, 360, 200, 150, 40, hWnd, (HMENU)IDC_BUTTON4, NULL, NULL);
            SendMessage(button4, WM_SETFONT, (WPARAM)hFont, 1);
            button6 = CreateWindow(TEXT("BUTTON"), TEXT("将决策树写入文件"), WS_CHILD | WS_VISIBLE, 360, 300, 150, 40, hWnd, (HMENU)IDC_BUTTON6, NULL, NULL);
            SendMessage(button6, WM_SETFONT, (WPARAM)hFont, 1);
            button7 = CreateWindow(TEXT("BUTTON"), TEXT("从文件中读入决策树"), WS_CHILD | WS_VISIBLE, 360, 100, 150, 40, hWnd, (HMENU)IDC_BUTTON7, NULL, NULL);
            SendMessage(button7, WM_SETFONT, (WPARAM)hFont, 1);
            button10 = CreateWindow(TEXT("BUTTON"), TEXT("退出系统"), WS_CHILD | WS_VISIBLE, 360, 400, 150, 40, hWnd, (HMENU)IDC_BUTTON10, NULL, NULL);
            SendMessage(button10, WM_SETFONT, (WPARAM)hFont, 1);
            break;
        }
        case IDC_BUTTON6:
        {
            if (IsTreeEmpty())
            {
                MessageBox(hWnd, TEXT("您的决策树为空树!"), TEXT("提示"), MB_ICONWARNING);
                break;
            }
            ClearAllWindows();
            static1 = CreateWindow(TEXT("STATIC"), TEXT("将决策树写入文件"), WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 10, 140, 20, hWnd, (HMENU)IDC_STATIC1, NULL, NULL);
            SendMessage(static1, WM_SETFONT, (WPARAM)hFont, 1);
            static2 = CreateWindow(TEXT("STATIC"), TEXT("请输入txt文件的地址:"), WS_CHILD | WS_VISIBLE, 10, 100, 160, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
            SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
            button9 = CreateWindow(TEXT("BUTTON"), TEXT("确定"), WS_CHILD | WS_VISIBLE, 320, 140, 80, 30, hWnd, (HMENU)IDC_BUTTON9, NULL, NULL);
            SendMessage(button9, WM_SETFONT, (WPARAM)hFont, 1);
            button5 = CreateWindow(TEXT("BUTTON"), TEXT("返回"), WS_CHILD | WS_VISIBLE, 320, 200, 80, 30, hWnd, (HMENU)IDC_BUTTON5, NULL, NULL);
            SendMessage(button5, WM_SETFONT, (WPARAM)hFont, 1);
            flag = 0;
            edit1 = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER|ES_MULTILINE|WS_HSCROLL, 10, 140, 300, 50, hWnd, (HMENU)IDC_EDIT1, NULL, NULL);
            SendMessage(edit1, WM_SETFONT, (WPARAM)hFont, 1);
            break;
        }
        case IDC_BUTTON9:
        {
            GetDlgItemText(hWnd, IDC_EDIT1, address, 100);
            TCHAR2Char(address, a);
            Save(hWnd);
            break;
        }
        case IDC_BUTTON7:
        {
            ClearAllWindows();
            static1 = CreateWindow(TEXT("STATIC"), TEXT("读取文件建立决策树"), WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 10, 140, 20, hWnd, (HMENU)IDC_STATIC1, NULL, NULL);
            SendMessage(static1, WM_SETFONT, (WPARAM)hFont, 1);
            static2 = CreateWindow(TEXT("STATIC"), TEXT("请输入txt文件的地址:"), WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 100, 160, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
            SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
            button3 = CreateWindow(TEXT("BUTTON"), TEXT("确定"), WS_CHILD | WS_VISIBLE, 320, 140, 80, 30, hWnd, (HMENU)IDC_BUTTON3, NULL, NULL);
            SendMessage(button3, WM_SETFONT, (WPARAM)hFont, 1);
            flag = 0;
            edit1 = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER| WS_HSCROLL | ES_MULTILINE, 10, 140, 300, 50, hWnd, (HMENU)IDC_EDIT1, NULL, NULL);
            SendMessage(edit1, WM_SETFONT, (WPARAM)hFont, 1);
            button5 = CreateWindow(TEXT("BUTTON"), TEXT("返回"), WS_CHILD | WS_VISIBLE, 320, 200, 80, 30, hWnd, (HMENU)IDC_BUTTON5, NULL, NULL);
            SendMessage(button5, WM_SETFONT, (WPARAM)hFont, 1);
            break;
        }
        case IDC_BUTTON12:
        {
            MessageBox(hWnd, TEXT("你竟然被一台电脑打败了,,,"), TEXT("提示"), MB_OK);
            ClearAllWindows();
            button4 = CreateWindow(TEXT("BUTTON"), TEXT("再玩一次"), WS_CHILD | WS_VISIBLE, 420, 200, 150, 40, hWnd, (HMENU)IDC_BUTTON4, NULL, NULL);
            SendMessage(button4, WM_SETFONT, (WPARAM)hFont, 1);
            button5 = CreateWindow(TEXT("BUTTON"), TEXT("返回"), WS_CHILD | WS_VISIBLE, 160, 200, 150, 40, hWnd, (HMENU)IDC_BUTTON5, NULL, NULL);
            SendMessage(button5, WM_SETFONT, (WPARAM)hFont, 1);
            break;
        }
        case IDC_BUTTON13:
        {
            MessageBox(hWnd, TEXT("专家猜错,请告诉专家动物信息"), TEXT("提示"), MB_OK);
            ClearAllWindows();
            static1 = CreateWindow(TEXT("STATIC"), TEXT("动物名称"), WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 110, 150, 20, hWnd, (HMENU)IDC_STATIC1, NULL, NULL);
            SendMessage(static1, WM_SETFONT, (WPARAM)hFont, 1);
            static2 = CreateWindow(TEXT("STATIC"), TEXT("区别于专家猜测的动物的特征(例如“它(不)是/(不)会/(没)有”句式)"), WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT, 10, 200, 600, 20, hWnd, (HMENU)IDC_STATIC2, NULL, NULL);
            SendMessage(static2, WM_SETFONT, (WPARAM)hFont, 1);
            edit1 = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | ES_MULTILINE, 10, 140, 300, 50, hWnd, (HMENU)IDC_EDIT1, NULL, NULL);
            SendMessage(edit1, WM_SETFONT, (WPARAM)hFont, 1);
            edit2 = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | ES_MULTILINE, 10, 230, 300, 50, hWnd, (HMENU)IDC_EDIT2, NULL, NULL);
            SendMessage(edit2, WM_SETFONT, (WPARAM)hFont, 1);
            button14 = CreateWindow(TEXT("BUTTON"), TEXT("确定"), WS_CHILD | WS_VISIBLE, 320, 300, 80, 30, hWnd, (HMENU)IDC_BUTTON14, NULL, NULL);
            SendMessage(button14, WM_SETFONT, (WPARAM)hFont, 1);
            button5 = CreateWindow(TEXT("BUTTON"), TEXT("返回"), WS_CHILD | WS_VISIBLE, 320, 350, 80, 30, hWnd, (HMENU)IDC_BUTTON5, NULL, NULL);
            SendMessage(button5, WM_SETFONT, (WPARAM)hFont, 1);
            break;
        }
        case IDC_BUTTON14:
        {
            GetDlgItemText(hWnd, IDC_EDIT1, a_name, 100);
            GetDlgItemText(hWnd, IDC_EDIT2, a_feature, 100);
            if (a_name[0] == '\0')
            {
                MessageBox(hWnd, TEXT("动物名称不能为空"), TEXT("提示"), MB_ICONWARNING);
                break;
            }
            if (a_feature[0] == '\0')
            {
                MessageBox(hWnd, TEXT("相关特征不能为空"), TEXT("提示"), MB_ICONWARNING);
                break;
            }
            Expert(14, hWnd);
            ClearAllWindows();
            button4 = CreateWindow(TEXT("BUTTON"), TEXT("再玩一次"), WS_CHILD | WS_VISIBLE, 420, 200, 150, 40, hWnd, (HMENU)IDC_BUTTON4, NULL, NULL);
            SendMessage(button4, WM_SETFONT, (WPARAM)hFont, 1);
            button5 = CreateWindow(TEXT("BUTTON"), TEXT("返回"), WS_CHILD | WS_VISIBLE, 160, 200, 150, 40, hWnd, (HMENU)IDC_BUTTON5, NULL, NULL);
            SendMessage(button5, WM_SETFONT, (WPARAM)hFont, 1);
            break;
        }
        case IDC_BUTTON10:
        {
            PostQuitMessage(0);
            return 0;
        }
        }
       
    }
    return 0;

    case WM_CTLCOLORSTATIC:
    {
        HDC hdc = (HDC)wParam;
        
    }
    return (BOOL)((HBRUSH)GetStockObject(NULL_BRUSH));
    
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    
    return DefWindowProc(hWnd, message, wParam, lParam);
}

三、测试与结论

1、测试环境:Visual Studio 2019
 1)从文件读取决策树如下图:

基于有序二叉树的专家系统应用——动物游戏(C++)

2)用户依次选择问题答案如下图:

基于有序二叉树的专家系统应用——动物游戏(C++)

 

3)程序输出猜测结果如下图:

基于有序二叉树的专家系统应用——动物游戏(C++)

 

4)若猜测正确则显示如下图:

基于有序二叉树的专家系统应用——动物游戏(C++)

 

5)猜测错误则用户输入动物名称并按照提示描述特征如下图(如果用户输入为空系统会发出提示):

基于有序二叉树的专家系统应用——动物游戏(C++)

 基于有序二叉树的专家系统应用——动物游戏(C++)

 

6)用户可选择再玩一次或将新的决策树保存到文件中如下图:

基于有序二叉树的专家系统应用——动物游戏(C++)

 基于有序二叉树的专家系统应用——动物游戏(C++)

 


7)在上侧菜单中,文件栏下,有以下辅助功能;在关于栏下,有开发者信息;在数据栏下,有动物的个数。

基于有序二叉树的专家系统应用——动物游戏(C++)

 基于有序二叉树的专家系统应用——动物游戏(C++)

基于有序二叉树的专家系统应用——动物游戏(C++)

 

 

  1. 若用户没有读入决策树就开始进入猜动物环节,程序有相应提醒。

基于有序二叉树的专家系统应用——动物游戏(C++)

 

 

9)当用户非法输入时会有相应提醒。

基于有序二叉树的专家系统应用——动物游戏(C++)

 

  1. 当用户未建立决策树就开始保存到新文件时,会有相应提醒。

基于有序二叉树的专家系统应用——动物游戏(C++)

程序源码:

基于有序二叉树的专家系统应用——动物游戏(C++)源代码与应用程序-C/C++文档类资源-CSDN文库

 

上一篇:​基于Docker的负载均衡和服务发现


下一篇:负载均衡SLB 及 3种负载均衡方案 - 讲解