zoukankan      html  css  js  c++  java
  • C语言 线性表 双向链式结构 实现

    一个双向链式结构实现的线性表 duList (GCC编译)。

      1 /**
      2 * @brief 线性表双向链表结构
      3 * @author wid
      4 * @date 2013-10-28
      5 *
      6 * @note 若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢!
      7 */
      8 
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 
     12 #define TRUE 1
     13 #define FALSE 0
     14 
     15 typedef struct Point2D
     16 {
     17     int x;
     18     int y;
     19 }ElemType;      //数据元素结构
     20 
     21 typedef struct DUNODE
     22 {
     23     ElemType pt;            //数据元素
     24     struct DUNODE *next;     //后继节点
     25     struct DUNODE *prior;    //前驱节点
     26 }duNode;        //节点结构
     27 
     28 typedef struct DULIST
     29 {
     30     duNode *head;           //头结点
     31     duNode *foot;           //尾节点
     32     int len;                //链表长度
     33 }duList;        //链表结构
     34 
     35 
     36 // duList 方法声明
     37 duNode *MakeNode();         ///产生一个节点
     38 duList *CreateList();       ///生成一条空双向线性表
     39 void DestroyList( duList *pList );                  ///销毁线性表
     40 void ClearList( duList *pList );                    ///置空线性表
     41 int GetLength( duList *pList );                     ///获取线性表长度
     42 int IsEmpty( duList *pList );                       ///检测线性表是否为空
     43 int AppendElem( duList *pList, ElemType *pt );      ///向线性表末尾添加数据元素
     44 int InsertElem( duList *pList, int nPos, ElemType *pt );      ///向线性中插入数据元素
     45 int DeleteElem( duList *pList, int nPos );          ///从线性中删除数据元素
     46 int GetElem( duList *pList, int nPos, ElemType *pt );         ///获取线性表中某位置上的元素
     47 int FindElem( duList *pList, int nPos, ElemType *pt );        ///从某位置起查找某元素在线性表中第一次出现的位置
     48 int GetPriorElem( duList *pList, ElemType *pt, ElemType *prior_pt );     ///从线性表中获取 pt 的前驱节点到 prior_pt
     49 int GetNextElem( duList *pList, ElemType *pt, ElemType *next_pt );       ///从线性表中获取 pt 的后继节点到 next_pt
     50 void ForEachList( duList *pList, void (*func)(ElemType *pt) );           ///对线性表中每个元素从前向后依次执行 func 函数
     51 void ReForEachList( duList *pList, void (*func)(ElemType *pt) );         ///对线性表中每个元素从后向前依次执行 func 函数
     52 int ListCpy( duList *pDestList, duList *pSrcList );           ///将一线性表复制到另一线性表后
     53 int ListCat( duList *pDestList, duList *pSrcList );           ///将一线性表连接到另一线性表后
     54 
     55 
     56 // duList 方法实现
     57 
     58 /**
     59 * @brief 生成一个链表节点
     60 *
     61 * @return 指向生成的节点的指针
     62 */
     63 duNode *MakeNode()
     64 {
     65     duNode *pNode = (duNode *)malloc( sizeof(duNode) );
     66     pNode->next = NULL;
     67     pNode->prior = NULL;
     68 
     69     return pNode;
     70 }
     71 
     72 /**
     73 * @brief 创建一个空的双向线性表
     74 *
     75 * @return 返回指向生成的线性表的指针
     76 */
     77 duList *CreateList()
     78 {
     79     duList *pList = (duList *)malloc( sizeof(duList) );
     80     pList->head = pList->foot = MakeNode();
     81     pList->head->next = NULL;
     82     pList->foot->prior = NULL;
     83 
     84     pList->len = 0;
     85 
     86     return pList;
     87 }
     88 
     89 /**
     90 * @brief 销毁一条线性表
     91 *
     92 * @param 指向待销毁的线性表的指针
     93 *
     94 * @return void
     95 */
     96 void DestroyList( duList *pList )
     97 {
     98     duNode *pm = pList->head, *pn = NULL;
     99 
    100     while( pm != NULL )
    101     {
    102         pn = pm->next;
    103         free(pm);
    104         pm = pn;
    105     }
    106 
    107     free( pList );
    108     pList = NULL;
    109 }
    110 
    111 /**
    112 * @brief 置空一条线性表
    113 *
    114 * @param pList 指向待置空的线性表指针
    115 *
    116 * @return void
    117 */
    118 void ClearList( duList *pList )
    119 {
    120     duNode *pm = pList->head->next, *pn = NULL;
    121     while( pm != NULL )
    122     {
    123         pn = pm->next;
    124         free(pm);
    125         pm = pn;
    126     }
    127 
    128     pList->foot = pList->head;
    129     pList->head->next = NULL;
    130     pList->foot->prior = NULL;
    131     pList->len = 0;
    132 }
    133 
    134 /**
    135 * @brief 获取线性表长度
    136 *
    137 * @param pList 指向待获取长度的线性表指针
    138 *
    139 * @return 返回线性表长度
    140 */
    141 int GetLength( duList *pList )
    142 {
    143     return pList->len;
    144 }
    145 
    146 /**
    147 * @brief 检测线性表是否为空
    148 *
    149 * @param pList 指向待检测的线性表指针
    150 *
    151 * @return 为空返回 TRUE, 否则返回 FALSE
    152 */
    153 int IsEmpty( duList *pList )
    154 {
    155     return pList->len == 0 ? TRUE : FALSE;
    156 }
    157 
    158 /**
    159 * @brief 向线性表末尾添加数据元素
    160 *
    161 * @param pList 指向待添加数据元素的线性表指针
    162 * @param pt 指向数据元素的指针
    163 *
    164 * @return 返回成功添加后的线性表长度
    165 */
    166 int AppendElem( duList *pList, ElemType *pt )
    167 {
    168     duNode *pNode = MakeNode();
    169     pNode->pt.x = pt->x;
    170     pNode->pt.y = pt->y;
    171 
    172     pList->foot->next = pNode;
    173     pNode->next = NULL;
    174     pNode->prior = pList->foot;
    175     pList->foot = pNode;
    176 
    177     return ++pList->len;
    178 }
    179 
    180 /**
    181 * @brief 向线性表中插入数据元素
    182 *
    183 * @param nPos 元素插入的位置
    184 * @param pt 指向待插入的数据元素的指针
    185 *
    186 * @return 插入成功则返回成功插入后线性表的长度, 否则返回 -1
    187 *
    188 * @note 元素位置由0计起
    189 */
    190 int InsertElem( duList *pList, int nPos, ElemType *pt )
    191 {
    192     ///要插入的位置不在线性表中
    193     if( nPos < 0 || nPos > pList->len )
    194         return -1;
    195 
    196     duNode *pNode = MakeNode();
    197     pNode->pt.x = pt->x;
    198     pNode->pt.y = pt->y;
    199 
    200     duNode *pm = pList->head;
    201 
    202     if( nPos == pList->len )        ///插入到尾部, 特殊处理
    203     {
    204         pNode->next = NULL;
    205         pNode->prior = pList->foot;
    206         pList->foot->next = pNode;
    207         pList->foot = pNode;
    208 
    209         return ++pList->len;
    210     }
    211 
    212     int i = 0;
    213     for( i = 0; i < nPos; ++i, pm = pm->next );
    214     pNode->next = pm->next;
    215     pNode->prior = pm;
    216     pm->next->prior = pNode;
    217     pm->next = pNode;
    218 
    219     return ++pList->len;
    220 }
    221 
    222 /**
    223 * @brief 从线性表中删除一个节点元素
    224 *
    225 * @param pList 指向待删除元素的线性表指针
    226 * @param nPos 需要删除的元素位置
    227 *
    228 * @return 成功删除后返回删除后线性表的长度, 否则返回-1
    229 */
    230 int DeleteElem( duList *pList, int nPos )
    231 {
    232     ///需要删除的节点不在线性表中
    233     if( nPos < 0 || nPos > pList->len-1 )
    234         return -1;
    235 
    236     duNode *pm = pList->head, *pn = NULL;
    237 
    238     ///删除尾节点, 特殊处理
    239     if( nPos == pList->len-1 )
    240     {
    241         pn = pList->foot;
    242         pList->foot = pList->foot->prior;
    243         pList->foot->next = NULL;
    244         free(pn);
    245 
    246         return --pList->len;
    247     }
    248 
    249     int i = 0;
    250     for( i = 0; i < nPos; ++i, pm = pm->next );
    251 
    252     pn = pm->next;
    253     pm->next = pn->next;
    254     pn->prior = pm;
    255     free(pn);
    256 
    257     return --pList->len;
    258 }
    259 
    260 /**
    261 * @brief 获取线性表中某位置上的元素
    262 *
    263 * @param pList 指向待获取元素的线性表指针
    264 * @param nPos 元素在线性表中的位置
    265 * @param pt 指向存放获取到的元素的指针
    266 *
    267 * @return 若获取成功, 返回 TRUE, 否则返回 FALSE
    268 *
    269 * @note 元素位置从 0 计起
    270 */
    271 int GetElem( duList *pList, int nPos, ElemType *pt )
    272 {
    273     if( nPos < 0 || nPos > pList->len-1 )
    274         return FALSE;
    275 
    276     duNode *p = NULL;
    277     int i = 0;
    278     ///判断从哪端起获取元素更近
    279     if( pList->len / 2 > nPos )     //从首端取
    280     {
    281         p = pList->head;
    282         for( i = 0; i <= nPos; ++i, p = p->next );
    283     }
    284     else    //从尾端取
    285     {
    286         nPos = pList->len - nPos - 1;
    287         p = pList->foot;
    288         for( i = 0; i < nPos; ++i, p = p->prior );
    289     }
    290 
    291     pt->x = p->pt.x;
    292     pt->y = p->pt.y;
    293 
    294     return TRUE;
    295 }
    296 
    297 /**
    298 * @brief 从某位置起查找某元素在线性表中第一次出现的位置
    299 *
    300 * @param pList 指向待查找元素的线性表的指针
    301 * @param nPos 查找起始位置
    302 * @param pt 指向待查找的元素的指针
    303 *
    304 * @return 若找到, 则返回元素所在的位置, 否则返回 -1
    305 *
    306 * @note 起始位置由 0 计起
    307 */
    308 int FindElem( duList *pList, int nPos, ElemType *pt )
    309 {
    310     ///起始位置不在线性表内
    311     if( nPos < 0 || nPos > pList->len -1 )
    312         return -1;
    313 
    314     duNode *p = pList->head;
    315     int i = 0, ncnt = 0;
    316 
    317     for( i = 0; i < nPos; ++i, p = p->next );
    318     while( p->next != NULL && (p = p->next) )
    319     {
    320         if( p->pt.x == pt->x && p->pt.y == pt->y )
    321             return nPos + ncnt;
    322 
    323         ++ncnt;
    324     }
    325 
    326     return -1;
    327 }
    328 
    329 /**
    330 * @brief 获取某 pt 元素的前驱节点到 prior_pt
    331 *
    332 * @param pList 指向待获取前驱节点的线性表指针
    333 * @param pt 指向目标节点的指针
    334 * @param prior_pt 存放目标节点 pt 的前驱节点
    335 *
    336 * @return 若成功获取前驱节点, 返回该前驱节点在线性表中的位置, 否则返回 -1
    337 *
    338 * @note 元素位置从 0 计起
    339 */
    340 int GetPriorElem( duList *pList, ElemType *pt, ElemType *prior_pt )
    341 {
    342     duNode *p = pList->head;
    343     int ncnt = 0;
    344 
    345     while( p != NULL && (p = p->next) )
    346     {
    347         if( p->pt.x == pt->x && p->pt.y == pt->y )
    348         {
    349             if( ncnt == 0 )     ///pt为头结点, 不存在前驱节点
    350                 return -1;
    351 
    352             prior_pt->x = p->prior->pt.x;
    353             prior_pt->y = p->prior->pt.y;
    354 
    355             return ncnt - 1;
    356         }
    357 
    358         ++ncnt;
    359     }
    360 
    361     return -1;
    362 }
    363 
    364 /**
    365 * @brief 获取某 pt 元素的后继节点到 next_pt
    366 *
    367 * @param pList 指向待获取前后继点的线性表指针
    368 * @param pt 指向目标节点的指针
    369 * @param prior_pt 存放目标节点 pt 的后继节点
    370 *
    371 * @return 若成功获取后继节点, 返回该后继节点在线性表中的位置, 否则返回 -1
    372 *
    373 * @note 元素位置从 0 计起
    374 */
    375 int GetNextElem( duList *pList, ElemType *pt, ElemType *next_pt )
    376 {
    377     duNode *p = pList->head;
    378     int ncnt = 0;
    379 
    380     while( p != NULL && (p = p->next) )
    381     {
    382         if( p->pt.x == pt->x && p->pt.y == pt->y )
    383         {
    384             if( ncnt == pList->len-1 )    ///pt为尾节点, 不存在后继节点
    385                 return -1;
    386 
    387             next_pt->x = p->next->pt.x;
    388             next_pt->y = p->next->pt.y;
    389 
    390             return ncnt + 1;
    391         }
    392 
    393         ++ncnt;
    394     }
    395 
    396     return -1;
    397 }
    398 
    399 /**
    400 * @brief 对线性表中每个元素从前向后依次执行 func 函数
    401 *
    402 * @param pList 指向待处理的线性表的指针
    403 * @param func 传入的函数指针
    404 *
    405 * @return void
    406 */
    407 void ForEachList( duList *pList, void (*func)(ElemType *pt) )
    408 {
    409     duNode *p = pList->head;
    410     while( (p = p->next) != NULL )
    411     {
    412         func( &p->pt );
    413     }
    414 }
    415 
    416 /**
    417 * @brief 对线性表中每个元素从后向前依次执行 func 函数
    418 *
    419 * @param pList 指向待处理的线性表的指针
    420 * @param func 传入的函数指针
    421 *
    422 * @return void
    423 */
    424 void ReForEachList( duList *pList, void (*func)(ElemType *pt) )
    425 {
    426     duNode *p = pList->foot;
    427     while( p->prior != NULL )
    428     {
    429         func( &p->pt );
    430         p = p->prior;
    431     }
    432 }
    433 
    434  /**
    435 * @brief 将 pSrcList 性表复制到 pDestList 线性表后
    436 *
    437 * @param pDestList 指向目标线性表指针
    438 * @param pSrcList 指向源线性表指针
    439 *
    440 * @return 返回复制后目标线性表长度
    441 */
    442 int ListCpy( duList *pDestList, duList *pSrcList )
    443 {
    444     duNode *p = pSrcList->head, *tmp = NULL;
    445     while( p->next != NULL && (p = p->next) )
    446     {
    447         tmp = MakeNode();
    448         tmp->pt.x = p->pt.x;
    449         tmp->pt.y = p->pt.y;
    450 
    451         tmp->prior = pDestList->foot;
    452         pDestList->foot->next = tmp;
    453         pDestList->foot = tmp;
    454     }
    455     pDestList->foot->next = NULL;
    456     pDestList->len += pSrcList->len;
    457 
    458     return pDestList->len;
    459 }
    460 
    461 /**
    462 * @brief 将 pSrcList 性表连接到 pDestList 线性表后
    463 *
    464 * @param pDestList 指向目标线性表指针
    465 * @param pSrcList 指向源线性表指针
    466 *
    467 * @return 返回连接后目标线性表长度
    468 *
    469 * @note 连接后 pSrcList 线性表将被销毁
    470 */
    471 int ListCat( duList *pDestList, duList *pSrcList )
    472 {
    473     pDestList->foot->next = pSrcList->head->next;
    474     pSrcList->head->next->prior = pDestList->foot;
    475     pDestList->foot = pSrcList->foot;
    476     pDestList->len += pSrcList->len;
    477 
    478     free(pSrcList);
    479     pSrcList = NULL;
    480 
    481     return pDestList->len;
    482 }
    483 
    484 //测试 duList
    485 
    486 void display( ElemType *pt )
    487 {
    488     printf("(%d,%d) ", pt->x, pt->y);
    489 }
    490 
    491 int main()
    492 {
    493     ///创建双向线性表
    494     duList *plA = CreateList();
    495     duList *plB = CreateList();
    496 
    497     ElemType pt1, pt2;
    498 
    499     int i = 0, n = 0, pos = 0;
    500 
    501     ///向线性表中添加元素
    502     for( i = 0; i < 6; ++i )
    503     {
    504         pt1.x = pt1.y = i;
    505         AppendElem( plA, &pt1 );
    506     }
    507 
    508     for( i = 0; i < 4; ++i )
    509     {
    510         pt2.x = pt2.y = i;
    511         AppendElem( plB, &pt2 );
    512     }
    513 
    514     ///测试 IsEmpty、GetLength
    515     if( IsEmpty(plA) == FALSE )
    516         printf( "plA length = %d
    ", GetLength(plA) );
    517 
    518     ///测试 ForEachList、ReForEachList
    519     ForEachList( plA, display );      //测试迭代输出 plA 中元素
    520     putchar( '
    ' );
    521     ReForEachList( plA, display );    //测试反向迭代输出 plA 中元素
    522 
    523     printf( "
    
    " );
    524     ///测试 InsertElem
    525     pt1.x = pt1.y = 100;
    526     puts("plA测试InsertElem"); InsertElem( plA, 0, &pt1 );       //在 plA 位置 0 处插入元素(1, 1)
    527     ForEachList( plA, display );
    528 
    529     printf( "
    
    " );
    530     ///测试 DeletetElem
    531     puts("plA测试DeleteElem"); DeleteElem( plA, 1 );             //在 plA 位置 1 处的元素
    532     ForEachList( plA, display );
    533 
    534     printf( "
    
    " );
    535     ///测试 GetElem
    536     GetElem( plA, 3, &pt2 );
    537     printf( "plA 位置为 3 的元素为: (%d,%d)", pt2.x, pt2.y );
    538 
    539     printf( "
    
    " );
    540     ///测试 GetPriorElem
    541     GetPriorElem( plA, &pt2, &pt1 );
    542     printf( "plA 位置为 3 的元素(%d,%d)的前驱节点为(%d,%d)", pt2.x, pt2.y, pt1.x, pt1.y );
    543 
    544     printf( "
    
    " );
    545     ///测试 GetNextElem
    546     GetNextElem( plA, &pt2, &pt1 );
    547     printf( "plA 位置为 3 的元素(%d,%d)的后继节点为(%d,%d)", pt2.x, pt2.y, pt1.x, pt1.y );
    548 
    549     printf( "
    
    " );
    550     ///测试 FindElem
    551     pt1.x = pt1.y = 5;
    552     printf( "元素(5,5)在plA中的位置为: %d", FindElem( plA, 0, &pt1 ) );
    553 
    554     printf( "
    
    " );
    555     ///测试 ListCpy
    556     puts( "测试ListCpy plB到PlA: " );
    557     ListCpy( plA, plB );
    558     ForEachList( plA, display );
    559     printf( "
    复制后plA长度: %d", GetLength(plA) );
    560 
    561     printf( "
    
    " );
    562     ///测试 ListCpy
    563     puts( "测试ListCat plB到PlA: " );
    564     ListCat( plA, plB );
    565     ForEachList( plA, display );
    566     printf( "
    连接后plA长度: %d", GetLength(plA) );
    567 
    568     DestroyList( plA );
    569 
    570     return 0;
    571 }

    若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢。                                                                                                                                                                                                                                                                                                                                                            

  • 相关阅读:
    ORA-01536: 超出表空间 'tablespace_name' 的空间限额
    Oracle数据库表索引失效,解决办法:修改Oracle数据库优化器模式
    解决response.setHeader("Content-disposition" 中文乱码问题
    MyBatis配置:在控制台打印SQL语句
    JS 字符串转日期格式 日期格式化字符串
    远程桌面管理工具Remote Desktop Connection Manager
    调整Windows操作系统下时间同步的频率
    Oracle数据库中字符型字段按数字排序
    “Error:(1, 1) java: 非法字符: 'ufeff'”错误解决办法
    本次孩子流感总结
  • 原文地址:https://www.cnblogs.com/mr-wid/p/3392878.html
Copyright © 2011-2022 走看看