博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据结构实验7:实现二分查找、二叉排序(查找)树和AVL树
阅读量:4950 次
发布时间:2019-06-11

本文共 44312 字,大约阅读时间需要 147 分钟。

实验7

学号:      姓名:     专业:

 

7.1实验目的

(1) 掌握顺序表的查找方法,尤其是二分查找方法。

(2) 掌握二叉排序树的建立及查找。

查找是软件设计中的最常用的运算,查找所涉及到的表结构的不同决定了查找的方法及其性能。二分查找是顺序表的查找中的最重要的方法,应能充分理解其实现方法和有关性能,并能借助其判定树结构来加深理解。二叉排序树结构在实验时具有一定的难度,可结合二叉树的有关内容和方法来实现。

7.2 实验任务

编写算法实现下列问题的求解。

(1) 对下列数据表,分别采用二分查找算法实现查找,给出查找过程依次所比较的元素(的下标),并以二分查找的判定树来解释。

第一组测试数据:

数据表为 (1,2,3,4,6,7,8,9,10,11,12,13,17,18,19,20,24,25,26,30,35,40,45,50,100)

查找的元素分别为: 2,8,20,  30,50,5,15,33,110   

第二组数据:

数据表为 (2,3,5,7,8,10,12,15,18,20,22,25,30,35,40,45,50,55,60, 80,100)

查找的元素分别为: 22,8,80,3,100,1,13,120

(2) 设计出在二叉排序树中插入结点的算法,在此基础上实现构建二叉排序树的算法。     

测试数据:构建二叉排序树的输入序列如下:

第一组数据:

100,150,120,50,70,60,80,170,180,160,110,30,40,35,175   

第二组数据:

100,70,60,80,150,120,50,160,30,40,170,180,175,35

(3) 设计算法在二叉排序树中查找指定值的结点。    

测试数据:在任务<1>中第一组测试数据所构造的二叉排序树中,分别查找下列元素:    150,70,160,190,10,55,175

(4) 设计算法在二叉排序树中删除特定值的结点。    

测试数据:在任务(1)中第一组测试数据所构造的二叉排序树中,分别删除下列元素:30,150,100

(5) 已知整型数组A[1..26]递增有序,设计算法以构造一棵平衡的二叉排序树来存放该数组中的所有元素。    

测试数据:数组元素分别为:

第一组数据:

(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26)

第二组数据:

(1,3,6,10,15,21,28,36,45,55,66,78,91,105,120,136,153,171,190,210,231,253,277,302,328)

7.3实验数据要求

自我编写测试样例,要求每个功能函数的测试样例不少于两组

7.4 运行结果截图及说明

 

图1 测试(1)①

 

图2 测试(1)②

 

图3 测试(2)①

 

图4 测试(2)②

 

图5 测试(3)

 

图6 测试(4)

 

图7 测试(5)①

 

图8 测试(5)①

 

图9 测试(5)①

 

图10 测试(5)①

 

图11 测试(5)②

 

 

图12 测试(5)②

 

图13 测试(5)②

 

图14 测试(5)①(全)

 

图15 测试(5)②(全)

7.5 附源代码

二分查找:

1 // stdafx.h : include file for standard system include files, 2 //  or project specific include files that are used frequently, but 3 //      are changed infrequently 4 // 5  6 #if !defined(AFX_STDAFX_H__940FF418_5647_412A_8B4F_3C89C07F8CA5__INCLUDED_) 7 #define AFX_STDAFX_H__940FF418_5647_412A_8B4F_3C89C07F8CA5__INCLUDED_ 8  9 #if _MSC_VER > 100010 #pragma once11 #endif // _MSC_VER > 100012 13 14 #include 
15 16 using namespace std;17 18 typedef long elementType;19 20 const long maxn = 10000 + 3; 21 22 // TODO: reference additional headers your program requires here23 24 //{
{AFX_INSERT_LOCATION}}25 // Microsoft Visual C++ will insert additional declarations immediately before the previous line.26 27 #endif // !defined(AFX_STDAFX_H__940FF418_5647_412A_8B4F_3C89C07F8CA5__INCLUDED_)
1 // SeqList.h: interface for the SeqList class. 2 // 3 // 4  5 #if !defined(AFX_SEQLIST_H__58D90762_85EC_4BBB_94EA_068A582CCD81__INCLUDED_) 6 #define AFX_SEQLIST_H__58D90762_85EC_4BBB_94EA_068A582CCD81__INCLUDED_ 7  8 #if _MSC_VER > 1000 9 #pragma once10 #endif // _MSC_VER > 100011 12 class SeqList  13 {14 public:15     SeqList();16     virtual ~SeqList();17     bool seqListFull();18     bool seqListEmpty();19     void randomInsert( elementType number );20     void insert( elementType value );21     void showLength();22     elementType binarySearch( elementType value );23     friend ostream &operator<<( ostream &os, SeqList &SL )24     {25         if( SL.length == -1 )26         {27             return os;28         }29         int column = 0;30         for( int i = 1; i <= SL.length; i ++ )31         {32             os << setw(6) << setiosflags( ios::left ) << SL.Arr[i] << " ";33             column ++;34             if( column % 10 == 0 )35                 os << endl;36         }37         os << endl;38     }39 40 private:41     elementType Arr[maxn];42     int length;43 44 };45 46 #endif // !defined(AFX_SEQLIST_H__58D90762_85EC_4BBB_94EA_068A582CCD81__INCLUDED_)

 

1 // SeqList.cpp: implementation of the SeqList class.  2 //  3 //  4   5 #include "stdafx.h"  6 #include "SeqList.h"  7   8 //  9 // Construction/Destruction 10 // 11  12 SeqList::SeqList() 13 { 14     length = 0; 15 } 16  17 SeqList::~SeqList() 18 { 19     ios::sync_with_stdio(false); 20     cout << "The SeqList destruction has been called!" << endl; 21 } 22  23 bool SeqList::seqListFull() 24 { 25     return length == maxn - 1; 26 } 27  28 bool SeqList::seqListEmpty() 29 { 30     return length == 0; 31 } 32  33 void SeqList::randomInsert( elementType number ) 34 { 35     ios::sync_with_stdio(false); 36     if( seqListFull() ) 37     { 38         cerr << "Inserting failed!The sequence list has been full.Error in void SeqList::randomInsert( int number )" << endl; 39         return; 40     } 41  42     srand( time(NULL) ); 43     elementType last = -999; 44     for( int i = 0; i < number; i ++ ) 45     { 46         elementType key = rand() % ( 10000 - 100 + 1 ) + 100; 47         if( key >= last ) 48         { 49             length ++; 50             Arr[length] = key; 51             last = key; 52         } 53         else 54         { 55             i --; 56         } 57     } 58 } 59  60 void SeqList::insert( elementType value ) 61 { 62     ios::sync_with_stdio(false); 63     if( seqListFull() ) 64     { 65         cerr << "Inerting failed!The sequence list has been full.Error in void SeqList::insert( elementType value )" << endl; 66         return; 67     } 68  69     length ++; 70     Arr[length] = value; 71 } 72  73 elementType SeqList::binarySearch( elementType value ) 74 { 75     ios::sync_with_stdio(false); 76     if( seqListEmpty() ) 77     { 78         cerr << "Searching failed!The sequence list is empty.Error in elementType SeqList::binarySearch( elementType value )" << endl; 79         return -1; 80     } 81     elementType lower = 0, upper = length; 82     while( lower <= upper ) 83     { 84         elementType mid = ( lower + upper ) >> 1; //+ 1; 85         if( Arr[mid] == value ) 86         { 87             return mid; 88         } 89         if( Arr[mid] >= value ) 90         { 91             upper = mid - 1; 92         } 93         else 94         { 95             lower = mid + 1; 96         } 97     } 98     return -1; 99 }100 101 void SeqList::showLength()102 {103     ios::sync_with_stdio(false);104     cout << length << endl;105 }

 

1 // BinarySearch.cpp : Defines the entry point for the console application. 2 // 3  4 #include "stdafx.h" 5 #include "SeqList.h" 6  7 void test1() 8 { 9     ios::sync_with_stdio(false);10     SeqList SL1;11     elementType number;12     cin >> number;13     SL1.randomInsert( number );14     cout << SL1;15     elementType value;16     for( int i = 0; i < number; i ++ )17     {18         cin >> value;19         if( SL1.binarySearch(value) != -1 )20         {21             cout << value << " is in the sequence list." << endl;22         }23         else24         {25             cout << value << " is not in the sequence list." << endl;26         }27     }28 }29 30 void test2()31 {32     ios::sync_with_stdio(false);33     SeqList SL1;34     elementType value;35     while( cin >> value )36     {37         if( value == -999 )38         {39             break;40         }41         SL1.insert(value);42     }43     SL1.showLength();44     cout << SL1;45     46     elementType key;47     while( cin >> key )48     {49         //cin >> key;50         if( key == -99 )51         {52             //break;53             return;54         }55         if( SL1.binarySearch(key) != -1 )56         {57             cout << key << " is in the sequence list." << endl;58         }59         else60         {61             cout << key << " is not in the sequence list." << endl;62         }63     }64     65 }66 67 int main(int argc, char* argv[])68 {69     test2();70     71     return 0;72 }

 

二分查找(排序)树:

1 // stdafx.h : include file for standard system include files, 2 //  or project specific include files that are used frequently, but 3 //      are changed infrequently 4 // 5  6 #if !defined(AFX_STDAFX_H__239FA301_F6C5_4AE4_BD82_5EB3365C7ECB__INCLUDED_) 7 #define AFX_STDAFX_H__239FA301_F6C5_4AE4_BD82_5EB3365C7ECB__INCLUDED_ 8  9 #if _MSC_VER > 100010 #pragma once11 #endif // _MSC_VER > 100012 13 14 #include 
15 #include
16 17 using namespace std;18 19 //将 elementType 设为 int 可以顺利完成实验要求;而将其设为 string 则可以输入字符串等,20 //此时的大小关系默认为为字典序21 //typedef string elementType;22 typedef int elementType;23 24 //为了图好玩,调用EasyX库把字体颜色改了一下25 //这是EasyX的官方网站: https://www.easyx.cn/26 27 typedef struct node28 {29 elementType data;30 struct node *leftChidld, *rightChild; 31 }BSTNode, *_BSTree;32 33 // TODO: reference additional headers your program requires here34 35 //{
{AFX_INSERT_LOCATION}}36 // Microsoft Visual C++ will insert additional declarations immediately before the previous line.37 38 #endif // !defined(AFX_STDAFX_H__239FA301_F6C5_4AE4_BD82_5EB3365C7ECB__INCLUDED_)

 

1 // BSTree.h: interface for the BSTree class. 2 // 3 // 4  5 #if !defined(AFX_BSTREE_H__37E371A7_E165_4AC3_898B_DDF38B0F87D8__INCLUDED_) 6 #define AFX_BSTREE_H__37E371A7_E165_4AC3_898B_DDF38B0F87D8__INCLUDED_ 7  8 #if _MSC_VER > 1000 9 #pragma once10 #endif // _MSC_VER > 100011 12 class BSTree  13 {14 public:15     BSTree();16     virtual ~BSTree();17     BSTNode *search( _BSTree BST, elementType value );//递归查找18     BSTNode *search( _BSTree BST, elementType value, _BSTree &father );//迭代查找19     BSTNode *getRootNode();20     bool insert( _BSTree BST, elementType value );21 22     bool deleteNode1( _BSTree &BST, elementType value );    //删除指定结点,failed23     void deleteNode2( _BSTree &BST, elementType value );    //递归删除指定结点24     void deleteNode2_1( _BSTree &BST, elementType value );    //迭代删除指定结点,待调试!25     void deleteNode3( _BSTree &BST, elementType value );26 27     void removeNode1( _BSTree &BST );28     void removeNode2( _BSTree &BST );29     void removeNode3( _BSTree &BST );30 31     void createBinarySearchTree( _BSTree BST, vector
VI/*elementType value*/ );32 void destroy( _BSTree BST );33 void preOrderTraversal( _BSTree BST/*, int space*/ );34 void inOrderTraversal( _BSTree BST/*, int space*/ );35 void postOrderTraversal( _BSTree BST/*, int space*/ );36 private:37 BSTNode *head;38 };39 40 #endif // !defined(AFX_BSTREE_H__37E371A7_E165_4AC3_898B_DDF38B0F87D8__INCLUDED_)

 

1 // BSTree.cpp: implementation of the BSTree class.  2 //  3 //  4   5 #include "stdafx.h"  6 #include "BSTree.h"  7   8 //  9 // Construction/Destruction 10 // 11  12 BSTree::BSTree() 13 { 14     //head = NULL; 15     //head = new BSTNode; 16     //head->leftChidld = head->rightChild = NULL; 17 } 18  19 BSTree::~BSTree() 20 { 21     ios::sync_with_stdio(false); 22     destroy(head); 23     cout << "The binary search tree has been destroyed!" << endl; 24 } 25  26 void BSTree::destroy( _BSTree BST ) 27 { 28     if(BST) 29     { 30         destroy( BST->leftChidld ); 31         destroy( BST->rightChild ); 32         delete BST; 33     } 34 } 35  36 void BSTree::preOrderTraversal( _BSTree BST/*, int space*/ ) 37 { 38     ios::sync_with_stdio(false); 39     /* 40     if(!BST) 41     { 42         cerr << "The binary search tree is empty.Error in void BSTree::preOrderTraversal( _BSTree BST )." << endl; 43         return; 44     } 45     */ 46     if(BST) 47     { 48         cout << BST->data << " "; 49         preOrderTraversal( BST->leftChidld ); 50         preOrderTraversal( BST->rightChild ); 51  52         //for( int i  = 0; i < space; i ++ ) 53         //    cout << " "; 54         //cout << BST->data << endl; 55         //preOrderTraversal( BST->leftChidld, space + 5 ); 56         //preOrderTraversal( BST->rightChild, space + 5 ); 57     } 58 } 59  60 void BSTree::inOrderTraversal( _BSTree BST/*, int space*/ ) 61 { 62     ios::sync_with_stdio(false); 63     if(BST) 64     { 65         inOrderTraversal( BST->leftChidld ); 66         cout << BST->data << " ";  67         inOrderTraversal( BST->rightChild ); 68  69         //inOrderTraversal( BST->leftChidld, space + 5 ); 70         //for( int i  = 0; i < space; i ++ ) 71         //    cout << " "; 72         //cout << BST->data << endl;  73         //inOrderTraversal( BST->rightChild, space + 5 ); 74     } 75 } 76  77 void BSTree::postOrderTraversal( _BSTree BST/*, int space*/ ) 78 { 79     ios::sync_with_stdio(false); 80     if(BST) 81     { 82         postOrderTraversal( BST->leftChidld ); 83         postOrderTraversal( BST->rightChild ); 84         cout << BST->data << " "; 85  86         /* 87         postOrderTraversal( BST->leftChidld, space + 5 ); 88         postOrderTraversal( BST->rightChild, space + 5 ); 89         for( int i  = 0; i < space; i ++ ) 90             cout << " "; 91         cout << BST->data << endl; 92         */ 93     } 94 } 95  96 void BSTree::createBinarySearchTree( _BSTree BST, /*elementType value*/vector
VI ) 97 { 98 //BST = NULL; 99 head = NULL;100 for( int i = 0; i < VI.size(); i ++ )101 {102 insert( head, VI[i] );103 }104 return;105 /*106 while( cin >> value )107 {108 if( value == "#" )109 {110 return;111 }112 else113 insert( head, value );114 }115 116 for( int i = 0; i < value; i ++ )117 {118 elementType key;119 cout << "input: ";120 cin >> key;121 insert( head, key );122 }123 */124 }125 126 BSTNode *BSTree::getRootNode()127 {128 return head;129 }130 131 BSTNode *BSTree::search( _BSTree BST, elementType value )//递归查找132 {133 ios::sync_with_stdio(false);134 if(!head)135 {136 cerr << "The binary search tree is empty.Error in BSTNode *BSTree::search( _BSTree BST, elementType value )." << endl;137 return NULL;138 }139 else if( BST->data == value )140 {141 return BST;142 }143 else if( BST->data > value )144 {145 return search( BST->leftChidld, value );146 }147 else148 {149 return search( BST->rightChild, value );150 }151 }152 153 BSTNode *BSTree::search( _BSTree BST, elementType value, _BSTree &father )//迭代查找154 {155 ios::sync_with_stdio(false);156 /*157 if(!head)158 {159 cerr << "The binary search tree empty.Error in BSTNode *BSTree::search( _BSTree BST, elementType value, _BSTree &father )." << endl;160 return NULL;161 }162 */163 BSTNode *tmp = head;164 father = NULL;165 while( tmp && tmp->data != value )166 {167 father = tmp;168 if( value < tmp->data )169 {170 tmp = tmp->leftChidld;171 }172 else173 {174 tmp = tmp->rightChild;175 }176 }177 return tmp;178 }179 180 bool BSTree::insert( _BSTree BST, elementType value )181 {182 //if(!head)183 //{184 // cerr << "The binary search tree does not exit.Error in bool BSTree::insert( _BSTree BST, elementType value )" << endl;185 // return false;186 //}187 BSTNode *newNode, *target, *father;188 189 target = search( head, value, father );190 if(target)191 {192 cerr << "Inserting failed!" << value << " has been exited in the binary search tree.\nError in bool BSTree::insert( _BSTree BST, elementType value )" << endl;193 return false;194 }195 newNode = new BSTNode;196 newNode->data = value;197 newNode->leftChidld = newNode->rightChild = NULL;198 if(!head)199 {200 head = newNode;201 }202 else if( value < father->data )203 {204 father->leftChidld = newNode;205 }206 else207 {208 father->rightChild = newNode;209 }210 return true;211 }212 213 bool BSTree::deleteNode1( _BSTree &BST, elementType value )214 {215 ios::sync_with_stdio(false);216 //if(!head)217 if(!BST)218 {219 cerr << "The binary search tree does not exit.Error in bool BSTree::deleteNode( _BSTree BST, elementType value )" << endl;220 return false;221 }222 BSTNode *newNode, *target, *father;223 //target = search( head, value, father );224 target = search( BST, value, father );225 if( !target )//查找失败,不删除226 {227 cerr << "Node-deleting failed!\n" << value << " is not in the binary search tree.\n" << "Error in bool BSTree::deleteNode( _BSTree BST, elementType value )." << endl;228 return false;229 }230 if( target->leftChidld && target->rightChild )//被删结点有两个 *target 孩子节点231 {232 newNode = target->rightChild; //找 target 的中序后继 newNode233 father = target;234 while( newNode->leftChidld )235 {236 father = newNode;237 newNode = newNode->leftChidld;238 }239 target->data = newNode->data; //将 *newNode 的数据传給 *target240 target = newNode; //找到的这个结点成为被删除结点241 }242 if( target->leftChidld ) //单孩子,记录非空孩子结点243 {244 newNode = target->leftChidld;245 }246 else247 {248 newNode = target->rightChild;249 }250 //if( target == head ) //被删结点是根结点251 if( target == BST )252 {253 //head = newNode;254 BST = newNode;255 }256 else if( newNode && ( newNode->data < father->data ) ) //重新链接,保持二叉排序树257 {258 father->leftChidld = newNode;259 }260 else261 {262 father->rightChild = newNode;263 }264 delete target;265 return true;266 }267 268 void BSTree::deleteNode2( _BSTree &BST, elementType value )269 {270 if(BST)271 {272 if( value < BST->data )273 {274 deleteNode2( BST->leftChidld, value );275 }276 else if( value > BST->data )277 {278 deleteNode2( BST->rightChild, value );279 }280 else281 {282 removeNode1(BST);283 }284 }285 }286 287 void BSTree::deleteNode2_1( _BSTree &BST, elementType value ) //迭代删除指定结点,待调试!288 {289 BSTNode *target = NULL;290 while( BST || BST->data != value )291 {292 target = BST;293 if( value < target->data )294 //if( value < BST->data )295 BST = BST->leftChidld;296 else297 BST = BST->rightChild;298 }299 removeNode1(target);300 //removeNode1(BST);301 }302 303 void BSTree::deleteNode3( _BSTree &BST, elementType value )304 {305 if(BST)306 {307 if( value < BST->data )308 {309 deleteNode2( BST->leftChidld, value );310 }311 else if( value > BST->data )312 {313 deleteNode2( BST->rightChild, value );314 }315 else316 {317 removeNode2(BST);318 }319 }320 }321 /*322 在二叉查找树中删除一个给定的结点p有三种情况323 324 (1)结点p无左右子树,则直接删除该结点,修改父节点相应指针325 326 (2)结点p有左子树(右子树),则把p的左子树(右子树)接到p的父节点上327 328 (3)左右子树同时存在,则有三种处理方式329 330 a.找到结点p的中序直接前驱结点s,把结点s的数据转移到结点p,然后删除结点s,331 由于结点s为p的左子树中最右的结点,因而s无右子树,删除结点s可以归结到情况(2)。332 严蔚敏数据结构P230-231就是该处理方式。333 b.找到结点p的中序直接后继结点s,把结点s的数据转移到结点p,然后删除结点s,334 由于结点s为p的右子树总最左的结点,因而s无左子树,删除结点s可以归结到情况(2)。335 算法导论第2版P156-157该是该处理方式。336 c.到p的中序直接前驱s,将p的左子树接到父节点上,将p的右子树接到s的右子树上,然后删除结点p。337 */338 void BSTree::removeNode1( _BSTree &BST )339 {340 BSTNode *target = NULL;341 if( !BST->leftChidld )342 {343 target = BST;344 BST = BST->rightChild;345 delete target;346 }347 else if( !BST->rightChild )348 {349 target = BST;350 BST = BST->leftChidld;351 delete target;352 }353 else354 {355 BSTNode *newNode = NULL;356 target = BST;357 newNode = BST->leftChidld; //左子树根结点 358 while( newNode->rightChild ) //寻找 BST 结点的中序前驱结点,即以 BST->leftChild为根结点的子树中的最右结点359 {360 target = newNode; //*target 指向 *BST 的父结点 361 newNode = newNode->rightChild; //*newNode 指向 *BST 的中序前驱结点362 }363 BST->data = newNode->data; //*newNode 的数据传給 *BST 的数据,然后删除结点 *newNode364 if( target != BST ) //BST->leftChidld 的右子树非空,这句话等价于 if( !( target == BST ) )365 {366 target->rightChild = newNode->leftChidld; //*newNode 的左子树接到 *target 的右子树上 367 }368 else369 {370 target->leftChidld = newNode->leftChidld; //*newNode 的左子树接到 *target 的左子树上371 }372 delete newNode; //删除结点 *newNode373 }374 }375 376 //注意 while 循环体:377 //如果 BST 左子树为空,则 while 循环体不执行,那么 target 就不会发生改变。 378 //然而一开始 target == BST。379 //反过来说,如果 BST 左子树不为空,则 while 执行,那么 target 就会发生改变。380 //target 改变了,就和 BST 不一样。381 //所以就可以表明 BST 左子树非空。382 383 void BSTree::removeNode2( _BSTree &BST )384 {385 BSTNode *target = NULL;386 if( !BST->leftChidld )387 {388 target = BST;389 BST = BST->rightChild;390 delete target;391 }392 else if( !BST->rightChild )393 {394 target = BST;395 BST = BST->leftChidld;396 delete target;397 }398 else399 {400 BSTNode *newNode = NULL;401 target = BST;402 newNode = BST->rightChild; //右子树根结点403 while( newNode->leftChidld ) //寻找 BST 结点的中序前驱结点,即以 BST->leftChild为根结点的子树中的最左结点404 {405 target = newNode; //*target 指向 *BST 的父结点406 newNode = newNode->leftChidld; //*newNode 指向 *BST 的中序后继结点407 }408 BST->data = newNode->data; //*newNode 的数据传給 *BST 的数据,然后删除结点 *newNode409 if( target != BST ) //BST->leftChidld 的左子树非空,这句话等价于 if( !( target == BST ) )410 {411 target->leftChidld = newNode->rightChild; //*newNode 的右子树接到 *target 的左子树上 412 }413 else414 {415 target->rightChild = newNode->rightChild; //*newNode 的右子树接到 *target 的右子树上 416 }417 delete newNode; //删除结点 *newNode418 }419 }420 421 //注意 while 循环体:422 //如果 BST 右子树为空,则 while 循环体不执行,那么 target 就不会发生改变。 423 //然而一开始 target == BST。424 //反过来说,如果 BST 右子树不为空,则 while 执行,那么 target 就会发生改变。425 //target 改变了,就和 BST 不一样426 //所以就可以表明 BST 右子树非空。427 428 429 void BSTree::removeNode3( _BSTree &BST ) 430 {431 BSTNode *target = NULL;432 if( !BST->leftChidld )433 {434 target = BST;435 BST = BST->rightChild;436 delete target;437 }438 else if( !BST->rightChild )439 {440 target = BST;441 BST = BST->leftChidld;442 delete target;443 }444 else445 {446 BSTNode *newNode = NULL;447 target = BST;448 newNode = BST->leftChidld; //左子树根结点449 while( newNode->rightChild ) //寻找 BST 结点的中序前驱结点,即以 BST->leftChild为根结点的子树中的最右结点450 {451 //target = newNode;452 newNode = newNode->rightChild;453 }454 newNode->rightChild = target->leftChidld; //*target 的左子树接到 *newNode 的左子树上455 target = target->leftChidld; //*target 的左子树接到父结点上456 delete target; //删除结点 *target457 }458 }
1 // BinarySearchTree.cpp : Defines the entry point for the console application.  2 //  3   4 #include "stdafx.h"  5 #include "BSTree.h"  6   7 //这是EasyX的官方网站: https://www.easyx.cn/  8   9 void test1() 10 { 11     HANDLE hOut;  12   13     //  获取输出流的句柄 14     hOut = GetStdHandle(STD_OUTPUT_HANDLE); 15  16     BSTree BST1; 17     elementType value; 18     vector
VI; 19 while( cin >> value ) 20 { 21 if( (char)value == '#' && value != 35/*-999*/ ) //细节处理:一定要加 && value != 35,因为 # 的ASCII码是35, 22 { //不加的话在输入数字“35”而不是“#”时循环也会终止 23 break; 24 } 25 else 26 { 27 VI.push_back(value); 28 } 29 30 } 31 BST1.createBinarySearchTree( BST1.getRootNode(), VI ); 32 33 SetConsoleTextAttribute(hOut, 34 FOREGROUND_RED | // 前景色_红色 35 FOREGROUND_BLUE |// 前景色_蓝色 36 FOREGROUND_INTENSITY);// 加强 37 38 cout << "PreOrder:" << endl; 39 BST1.preOrderTraversal( BST1.getRootNode() ); 40 cout << endl; 41 cout << "InOrder:" << endl; 42 BST1.inOrderTraversal( BST1.getRootNode() ); 43 cout << endl; 44 cout << "PostOrder:" << endl; 45 BST1.postOrderTraversal( BST1.getRootNode() ); 46 cout << endl; 47 48 SetConsoleTextAttribute(hOut, 49 FOREGROUND_RED | // 前景色_红色 50 FOREGROUND_GREEN | // 前景色_绿色 51 FOREGROUND_BLUE ); // 前景色_蓝色 52 53 return; 54 } 55 56 void test2() 57 { 58 HANDLE hOut; 59 60 // 获取输出流的句柄 61 hOut = GetStdHandle(STD_OUTPUT_HANDLE); 62 63 BSTree BST1; 64 elementType value; 65 vector
VI; 66 67 while( cin >> value ) 68 { 69 if( (char)value == '#' && value != 35/*-999*/ ) //细节处理:一定要加 && value != 35,因为 # 的ASCII码是35, 70 { //不加的话在输入数字“35”而不是“#”时循环也会终止 71 break; 72 } 73 else 74 { 75 VI.push_back(value); 76 } 77 78 } 79 80 BST1.createBinarySearchTree( BST1.getRootNode(), VI ); 81 82 _BSTree index = NULL; 83 84 SetConsoleTextAttribute(hOut, 85 FOREGROUND_RED | // 前景色_红色 86 FOREGROUND_BLUE |// 前景色_蓝色 87 FOREGROUND_INTENSITY);// 加强 88 89 cout << "PreOrder:" << endl; 90 91 BST1.preOrderTraversal( BST1.getRootNode() ); 92 cout << endl; 93 cout << "InOrder:" << endl; 94 BST1.inOrderTraversal( BST1.getRootNode() ); 95 cout << endl; 96 cout << "PostOrder:" << endl; 97 BST1.postOrderTraversal( BST1.getRootNode() ); 98 cout << endl; 99 100 101 102 //elementType key = ;// = 545;103 //下面这句话不会运行104 //cin >> key;105 106 elementType Arr[] = { 150, 70, 160, 190, 10, 55, 175 };107 108 for( int j = 0; j < sizeof(Arr) / sizeof(elementType); j ++ )109 {110 if( BST1.search( BST1.getRootNode(), Arr[j], index ) )111 {112 SetConsoleTextAttribute(hOut, 113 FOREGROUND_BLUE | // 前景色_蓝色114 FOREGROUND_INTENSITY ); // 前景色_加强115 cout << Arr[j] << " is in the binary search tree." << endl;116 SetConsoleTextAttribute(hOut, 117 FOREGROUND_RED | // 前景色_红色118 FOREGROUND_GREEN | // 前景色_绿色119 FOREGROUND_BLUE ); // 前景色_蓝色120 }121 else122 {123 SetConsoleTextAttribute(hOut, 124 FOREGROUND_RED | // 前景色_红色125 FOREGROUND_INTENSITY ); // 前景色_加强126 cout << Arr[j] << " is not in the binary search tree." << endl;127 SetConsoleTextAttribute(hOut, 128 FOREGROUND_RED | // 前景色_红色129 FOREGROUND_GREEN | // 前景色_绿色130 FOREGROUND_BLUE ); // 前景色_蓝色131 }132 }133 134 //无法实现下面这样输入数值判断其是否存在135 /*136 BSTNode *father = NULL, *target = NULL;137 138 elementType key;139 while( cin >> key )140 {141 //target = NULL;142 if( (char)key == '#' && key != 35 ) 143 { 144 break;145 }146 else147 target = BST1.search( BST1.getRootNode(), key, father );148 149 if(!target)150 {151 cout << "No!" << endl;152 }153 else154 {155 cout << "Yes!" << endl;156 }157 158 }159 */ 160 161 return;162 }163 164 void test3()165 {166 HANDLE hOut; 167 168 // 获取输出流的句柄169 hOut = GetStdHandle(STD_OUTPUT_HANDLE); 170 171 BSTree BST1;172 elementType value;173 vector
VI;174 175 while( cin >> value )176 {177 if( (char)value == '#' && value != 35/*-999*/ ) //细节处理:一定要加 && value != 35,因为 # 的ASCII码是35,178 { //不加的话在输入数字“35”而不是“#”时循环也会终止179 break;180 }181 else182 {183 VI.push_back(value);184 }185 186 }187 188 BST1.createBinarySearchTree( BST1.getRootNode(), VI );189 190 _BSTree index = NULL; 191 192 SetConsoleTextAttribute(hOut, 193 FOREGROUND_BLUE | // 前景色_蓝色194 FOREGROUND_INTENSITY ); // 前景色_加强195 cout << "The origin binary search tree is as follow:" << endl;196 SetConsoleTextAttribute(hOut, 197 FOREGROUND_RED | // 前景色_红色198 FOREGROUND_BLUE |// 前景色_蓝色199 FOREGROUND_INTENSITY);// 加强200 201 cout << "PreOrder:" << endl;202 203 BST1.preOrderTraversal( BST1.getRootNode() );204 cout << endl;205 cout << "InOrder:" << endl;206 BST1.inOrderTraversal( BST1.getRootNode() );207 cout << endl;208 cout << "PostOrder:" << endl;209 BST1.postOrderTraversal( BST1.getRootNode() );210 211 cout << endl;212 213 214 215 elementType Arr[] = { 30, 150, 100 };216 for( int i = 0; i < sizeof(Arr) / sizeof(elementType); i ++ )217 { 218 _BSTree index = BST1.getRootNode();219 //BST1.deleteNode1( index, Arr[i] );220 BST1.deleteNode2( index, Arr[i] );221 SetConsoleTextAttribute(hOut, 222 FOREGROUND_BLUE | // 前景色_蓝色223 FOREGROUND_INTENSITY ); // 前景色_加强224 cout << "After deleting node " << Arr[i] << ", the current binary search tree is as follow:"<< endl;225 226 SetConsoleTextAttribute(hOut, 227 FOREGROUND_RED | // 前景色_红色228 FOREGROUND_BLUE |// 前景色_蓝色229 FOREGROUND_INTENSITY);// 加强230 231 cout << "PreOrder:" << endl;232 233 BST1.preOrderTraversal( BST1.getRootNode() );234 cout << endl;235 cout << "InOrder:" << endl;236 BST1.inOrderTraversal( BST1.getRootNode() );237 cout << endl;238 cout << "PostOrder:" << endl;239 BST1.postOrderTraversal( BST1.getRootNode() );240 cout << endl;241 242 }243 SetConsoleTextAttribute(hOut, 244 FOREGROUND_RED | // 前景色_红色245 FOREGROUND_GREEN | // 前景色_绿色246 FOREGROUND_BLUE ); // 前景色_蓝色247 return;248 }249 250 251 int main(int argc, char* argv[])252 {253 //test1();254 //test2();255 test3();256 return 0;257 }

 

AVL树:

1 // Tips for Getting Started:  2 //   1. Use the Solution Explorer window to add/manage files 3 //   2. Use the Team Explorer window to connect to source control 4 //   3. Use the Output window to see build output and other messages 5 //   4. Use the Error List window to view errors 6 //   5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project 7 //   6. In the future, to open this project again, go to File > Open > Project and select the .sln file 8  9 #ifndef PCH_H10 #define PCH_H11 12 #include 
13 #include
14 #include
15 #include
16 17 using namespace std;18 19 // TODO: add headers that you want to pre-compile here20 21 #endif //PCH_H

 

1 #pragma once 2 /* AVL node */ 3 template 
4 class AVLNode 5 { 6 public: 7 T key; 8 int balance; 9 AVLNode *leftChild, *rightChild, *parent;10 11 AVLNode(T k, AVLNode *p) : key(k), balance(0), parent(p),leftChild(NULL), rightChild(NULL) {}12 ~AVLNode();13 };
1 #pragma once 2 /* AVL tree */ 3  4 #include "AVLnode.h" 5 template 
6 class AVLTree 7 { 8 public: 9 AVLTree(void);10 ~AVLTree(void);11 bool insert(T key);12 void deleteKey(const T key);13 void printBalance();14 void inOrderTraverse();15 void preOrderTraverse();16 void postOrderTraverse();17 void display();18 19 AVLNode
* RR_Rotate(AVLNode
*AVLB); //rotate left20 //当在RR发生不平衡时需要进行左旋转21 AVLNode
* LL_Rotate(AVLNode
*AVLB); //rotate right22 //当在LL发生不平衡时需要进行右旋转23 AVLNode
* LR_Rotate(AVLNode
*AVLB); //rotate left then right24 AVLNode
* RL_Rotate(AVLNode
*AVLB); //rotate right then left25 AVLNode
* getRootNode();26 void reBalance(AVLNode
*AVLB);27 int height(AVLNode
*AVLB);28 void setBalance(AVLNode
*AVLB);29 void printBalance(AVLNode
*AVLB);30 void clearNode(AVLNode
*AVLB);31 void inOrderTraverse(AVLNode
*AVLB);32 void preOrderTraverse(AVLNode
*AVLB);33 void postOrderTraverse(AVLNode
*AVLB);34 35 void display(AVLNode
*AVLB, int space, int colour);36 37 private:38 AVLNode
*root;39 };

 

1 #include "pch.h" 2 #include "AVLnode.h" 3  4  5 template 
6 AVLNode
::~AVLNode() 7 { 8 delete leftChild; 9 delete rightChild;10 }
1 #include "pch.h"  2 #include "AVLtree.h"  3   4   5 template 
6 void AVLTree
::reBalance(AVLNode
*AVLB) 7 { 8 setBalance(AVLB); 9 10 if (AVLB->balance == -2) 11 { 12 if (height(AVLB->leftChild->leftChild) >= height(AVLB->leftChild->rightChild)) 13 AVLB = LL_Rotate(AVLB); 14 else 15 AVLB = LR_Rotate(AVLB); 16 } 17 else if (AVLB->balance == 2) 18 { 19 if (height(AVLB->rightChild->rightChild) >= height(AVLB->rightChild->leftChild)) 20 AVLB = RR_Rotate(AVLB); 21 else 22 AVLB = RL_Rotate(AVLB); 23 } 24 25 if (AVLB->parent != NULL) 26 { 27 reBalance(AVLB->parent); 28 } 29 else 30 { 31 root = AVLB; 32 } 33 } 34 35 template
36 AVLNode
* AVLTree
::RR_Rotate(AVLNode
*AVLB) 37 { 38 AVLNode
*tmp = AVLB->rightChild; 39 tmp->parent = AVLB->parent; 40 AVLB->rightChild = tmp->leftChild; 41 42 if (AVLB->rightChild != NULL) 43 AVLB->rightChild->parent = AVLB; 44 45 tmp->leftChild = AVLB; 46 AVLB->parent = tmp; 47 48 if (tmp->parent != NULL) 49 { 50 if (tmp->parent->rightChild == AVLB) 51 { 52 tmp->parent->rightChild = tmp; 53 } 54 else 55 { 56 tmp->parent->leftChild = tmp; 57 } 58 } 59 60 setBalance(AVLB); 61 setBalance(tmp); 62 return tmp; 63 } 64 65 template
66 AVLNode
* AVLTree
::LL_Rotate(AVLNode
*AVLB) 67 { 68 AVLNode
*tmp = AVLB->leftChild; 69 tmp->parent = AVLB->parent; 70 AVLB->leftChild = tmp->rightChild; 71 72 if (AVLB->leftChild != NULL) 73 AVLB->leftChild->parent = AVLB; 74 75 tmp->rightChild = AVLB; 76 AVLB->parent = tmp; 77 78 if (tmp->parent != NULL) 79 { 80 if (tmp->parent->rightChild == AVLB) 81 { 82 tmp->parent->rightChild = tmp; 83 } 84 else 85 { 86 tmp->parent->leftChild = tmp; 87 } 88 } 89 90 setBalance(AVLB); 91 setBalance(tmp); 92 return tmp; 93 } 94 95 template
96 AVLNode
* AVLTree
::LR_Rotate(AVLNode
*AVLB) 97 { 98 AVLB->leftChild = RR_Rotate(AVLB->leftChild); 99 return LL_Rotate(AVLB);100 }101 102 template
103 AVLNode
* AVLTree
::RL_Rotate(AVLNode
*AVLB)104 {105 AVLB->rightChild = LL_Rotate(AVLB->rightChild);106 return RR_Rotate(AVLB);107 }108 109 template
110 AVLNode
* AVLTree
::getRootNode()111 {112 return root;113 }114 115 template
116 int AVLTree
::height(AVLNode
*AVLB)117 {118 if (AVLB == NULL)119 return -1;120 return 1 + max(height(AVLB->leftChild), height(AVLB->rightChild));121 }122 123 template
124 void AVLTree
::setBalance(AVLNode
*AVLB)125 {126 AVLB->balance = height(AVLB->rightChild) - height(AVLB->leftChild);127 }128 129 template
130 void AVLTree
::printBalance(AVLNode
*AVLB)131 {132 ios::sync_with_stdio(false);133 if (AVLB != NULL)134 {135 printBalance(AVLB->leftChild);136 cout << AVLB->balance << " ";137 //std::cout << n->key << " ";138 printBalance(AVLB->rightChild);139 }140 }141 142 template
143 void AVLTree
::inOrderTraverse(AVLNode
*AVLB)144 {145 ios::sync_with_stdio(false);146 if (AVLB)147 {148 inOrderTraverse(AVLB->leftChild);149 cout << AVLB->key << " ";150 inOrderTraverse(AVLB->rightChild);151 }152 }153 154 template
155 void AVLTree
::preOrderTraverse(AVLNode
*AVLB)156 {157 if (AVLB)158 {159 cout << AVLB->key << " ";160 preOrderTraverse(AVLB->leftChild);161 preOrderTraverse(AVLB->rightChild);162 }163 }164 165 template
166 void AVLTree
::postOrderTraverse(AVLNode
*AVLB)167 {168 ios::sync_with_stdio(false);169 if (AVLB)170 {171 postOrderTraverse(AVLB->leftChild);172 postOrderTraverse(AVLB->rightChild);173 cout << AVLB->key << " ";174 }175 }176 177 template
178 void AVLTree
::display(AVLNode
*AVLB, int space, int colour )179 {180 ios::sync_with_stdio(false);181 HANDLE hConsole;182 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);183 if (AVLB)184 {185 display(AVLB->rightChild, space + 1, colour + 1);186 SetConsoleTextAttribute(hConsole, 0x0008 | colour);187 //colour++;188 cout << endl;189 if (AVLB == root)190 cout << " Root ----> ";191 for (int i = 0; i < space && AVLB != root; i++)192 cout << " ";193 cout << AVLB->key;194 display(AVLB->leftChild, space + 1, colour + 1);195 }196 }197 198 template
199 AVLTree
::AVLTree(void) : root(NULL) {}200 201 template
202 AVLTree
::~AVLTree(void)203 {204 delete root;205 }206 207 template
208 bool AVLTree
::insert(T key)209 {210 if (root == NULL)211 {212 root = new AVLNode
(key, NULL);213 }214 else215 {216 AVLNode
//这种风格我觉得不错217 //I appreciate this style of code218 *target = root, 219 *parent;220 221 while (1)222 {223 if (target->key == key)224 return false;225 226 parent = target;227 228 bool goLeft = target->key > key;229 target = goLeft ? target->leftChild : target->rightChild;230 231 if (target == NULL)232 {233 if (goLeft)234 {235 parent->leftChild = new AVLNode
(key, parent);236 }237 else238 {239 parent->rightChild = new AVLNode
(key, parent);240 }241 242 reBalance(parent);243 break;244 }245 }246 }247 248 return true;249 }250 251 template
252 void AVLTree
::deleteKey(const T delKey)253 {254 if (root == NULL)255 return;256 257 AVLNode
258 *target = root,259 *parent = root,260 *delNode = NULL,261 *child = root;262 263 while (child != NULL)264 {265 parent = target;266 target = child;267 child = delKey >= target->key ? target->rightChild : target->leftChild;268 if (delKey == target->key)269 delNode = target;270 }271 272 if (delNode != NULL)273 {274 delNode->key = target->key;275 276 child = target->leftChild != NULL ? target->leftChild : target->rightChild;277 278 if (root->key == delKey)279 {280 root = child;281 }282 else283 {284 if (parent->leftChild == target)285 {286 parent->leftChild = child;287 }288 else289 {290 parent->rightChild = child;291 }292 293 reBalance(parent);294 }295 }296 }297 298 template
299 void AVLTree
::printBalance()300 {301 ios::sync_with_stdio(false);302 printBalance(root);303 cout << endl;304 }305 306 template
307 void AVLTree
::inOrderTraverse()308 {309 ios::sync_with_stdio(false);310 inOrderTraverse(root);311 cout << endl;312 }313 314 template
315 void AVLTree
::preOrderTraverse()316 {317 ios::sync_with_stdio(false);318 preOrderTraverse(root);319 cout << endl;320 }321 322 template
323 void AVLTree
::postOrderTraverse()324 {325 ios::sync_with_stdio(false);326 postOrderTraverse(root);327 cout << endl;328 }329 330 template
331 void AVLTree
::display()332 {333 ios::sync_with_stdio(false);334 int color = 1;335 display(root, 1, color);336 cout << endl;337 }
1 // AVL_2.cpp : This file contains the 'main' function. Program execution begins and ends there.  2 //  3   4 #include "pch.h"  5 #include 
6 #include "AVLtree.h" 7 #include "AVLnode.h" 8 #include "AVLnode.cpp" 9 #include "AVLtree.cpp" 10 11 int main() 12 { 13 //std::cout << "Hello World!\n"; 14 ios::sync_with_stdio(false); 15 AVLTree
AVLBT; 16 HANDLE hConsole; 17 hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 18 cout << "Inserting integer values 1 to 26" << std::endl; 19 int Arr[] = { 1,3,6,10,15,21,28,36,45,55,66,78,91,105,120,136,153,171,190,210,231, 20 253,277,302,328 }; 21 for (int i = 0; i < sizeof(Arr) / sizeof(int); i++) 22 //for( int i = 0; Arr[i] != 0; i ++ ) 23 //AVLBT.insert(i); 24 AVLBT.insert(Arr[i]); 25 26 cout << "Printing the balance factor of each node: " << std::endl; 27 SetConsoleTextAttribute(hConsole, 12); 28 AVLBT.printBalance(); 29 SetConsoleTextAttribute(hConsole, 7); 30 cout << "Printing key: " << std::endl; 31 SetConsoleTextAttribute(hConsole, 0x0008 | 8); 32 AVLBT.inOrderTraverse(); 33 AVLBT.display(); 34 //AVLTree
*root = avl.getRootNode(); 35 while (1) 36 { 37 SetConsoleTextAttribute(hConsole, 7); 38 cout << "\n---------------------" << endl; 39 cout << "AVL tree implementation" << endl; 40 cout << "By Utah Xef developed" << endl; 41 cout << "\n---------------------" << endl; 42 cout << "1.insert element into the tree" << endl; 43 cout << "2.display balanced AVL tree" << endl; 44 cout << "3.preorder traversal" << endl; 45 cout << "4.inorder traversal" << endl; 46 cout << "5.postorder traversal" << endl; 47 cout << "6.delete key" << endl; 48 cout << "7.display the balance factor of each node" << endl; 49 cout << "8.exit" << endl; 50 cout << "enter your choice: "; 51 int choice; 52 cin >> choice; 53 54 switch (choice) 55 56 { 57 58 case 1: 59 60 cout << "enter value to be inserted: "; 61 int item; 62 cin >> item; 63 64 AVLBT.insert(item); 65 66 break; 67 68 case 2: 69 70 if (AVLBT.getRootNode() == nullptr) 71 72 { 73 74 cout << "tree is empty" << endl; 75 76 continue; 77 78 } 79 80 cout << "balanced avl tree:" << endl; 81 82 AVLBT.display(); 83 84 break; 85 86 case 3: 87 88 cout << "preorder traversal:" << endl; 89 SetConsoleTextAttribute(hConsole, 0x0008 | 9); 90 AVLBT.preOrderTraverse(); 91 92 cout << endl; 93 94 break; 95 case 4: 96 97 cout << "inorder traversal:" << endl; 98 SetConsoleTextAttribute(hConsole, 0x0008 | 10); 99 AVLBT.inOrderTraverse();100 101 cout << endl;102 103 break;104 105 106 107 case 5:108 109 cout << "postorder traversal:" << endl;110 SetConsoleTextAttribute(hConsole, 0x0008 | 11);111 AVLBT.postOrderTraverse();112 113 cout << endl;114 115 break;116 117 case 6:118 int value;119 cout << "Please input the value to delete:" << endl;120 cin >> value;121 AVLBT.deleteKey(value);122 break;123 124 case 7:125 cout << "The balance factor of each node:" << endl;126 SetConsoleTextAttribute(hConsole, 0x0008 | 14);127 AVLBT.printBalance();128 break;129 case 8:130 exit(1);131 132 break;133 default:134 135 cout << "Wrong choice" << endl;136 break;137 }138 139 }140 //std::cout << std::endl;141 std::cin.get();142 }143 144 // Run program: Ctrl + F5 or Debug > Start Without Debugging menu145 // Debug program: F5 or Debug > Start Debugging menu146 147 // Tips for Getting Started: 148 // 1. Use the Solution Explorer window to add/manage files149 // 2. Use the Team Explorer window to connect to source control150 // 3. Use the Output window to see build output and other messages151 // 4. Use the Error List window to view errors152 // 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project153 // 6. In the future, to open this project again, go to File > Open > Project and select the .sln file

 

转载于:https://www.cnblogs.com/25th-engineer/p/10105668.html

你可能感兴趣的文章
[RxJS] Filtering operator: single, race
查看>>
BZOJ1468: Tree
查看>>
数据比赛实现的细节
查看>>
准备工作
查看>>
【bzoj3998】弦论 后缀自动机
查看>>
积累_ZC_01
查看>>
操作系统启动
查看>>
JS中,关于数组的练习题
查看>>
页面关闭和刷新事件
查看>>
js经典代码技巧学习之一:使用三元运算符处理javascript兼容
查看>>
NOIP2013 华容道 (棋盘建图+spfa最短路)
查看>>
Javascript 操作select控件大全(新增、修改、删除、选中、清空、判断存在等)...
查看>>
后缀数组详解
查看>>
30岁前不要让人生留下遗憾笔记
查看>>
如何注册EPIMATE
查看>>
交易进行中买家申请退货退款操作流程
查看>>
常用技巧之JS判断数组中某元素出现次数
查看>>
【转】MySQL5安装的图解(mysql-5.0.27-win32.zip)
查看>>
【转】MYSQL入门学习之一:基本操作
查看>>
字体的设置 REM EM PX
查看>>