C语言 线性表 双向链式结构 实现

时间:2023-03-09 04:49:07
C语言 线性表 双向链式结构 实现

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

 /**
* @brief 线性表双向链表结构
* @author wid
* @date 2013-10-28
*
* @note 若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢!
*/ #include <stdio.h>
#include <stdlib.h> #define TRUE 1
#define FALSE 0 typedef struct Point2D
{
int x;
int y;
}ElemType; //数据元素结构 typedef struct DUNODE
{
ElemType pt; //数据元素
struct DUNODE *next; //后继节点
struct DUNODE *prior; //前驱节点
}duNode; //节点结构 typedef struct DULIST
{
duNode *head; //头结点
duNode *foot; //尾节点
int len; //链表长度
}duList; //链表结构 // duList 方法声明
duNode *MakeNode(); ///产生一个节点
duList *CreateList(); ///生成一条空双向线性表
void DestroyList( duList *pList ); ///销毁线性表
void ClearList( duList *pList ); ///置空线性表
int GetLength( duList *pList ); ///获取线性表长度
int IsEmpty( duList *pList ); ///检测线性表是否为空
int AppendElem( duList *pList, ElemType *pt ); ///向线性表末尾添加数据元素
int InsertElem( duList *pList, int nPos, ElemType *pt ); ///向线性中插入数据元素
int DeleteElem( duList *pList, int nPos ); ///从线性中删除数据元素
int GetElem( duList *pList, int nPos, ElemType *pt ); ///获取线性表中某位置上的元素
int FindElem( duList *pList, int nPos, ElemType *pt ); ///从某位置起查找某元素在线性表中第一次出现的位置
int GetPriorElem( duList *pList, ElemType *pt, ElemType *prior_pt ); ///从线性表中获取 pt 的前驱节点到 prior_pt
int GetNextElem( duList *pList, ElemType *pt, ElemType *next_pt ); ///从线性表中获取 pt 的后继节点到 next_pt
void ForEachList( duList *pList, void (*func)(ElemType *pt) ); ///对线性表中每个元素从前向后依次执行 func 函数
void ReForEachList( duList *pList, void (*func)(ElemType *pt) ); ///对线性表中每个元素从后向前依次执行 func 函数
int ListCpy( duList *pDestList, duList *pSrcList ); ///将一线性表复制到另一线性表后
int ListCat( duList *pDestList, duList *pSrcList ); ///将一线性表连接到另一线性表后 // duList 方法实现 /**
* @brief 生成一个链表节点
*
* @return 指向生成的节点的指针
*/
duNode *MakeNode()
{
duNode *pNode = (duNode *)malloc( sizeof(duNode) );
pNode->next = NULL;
pNode->prior = NULL; return pNode;
} /**
* @brief 创建一个空的双向线性表
*
* @return 返回指向生成的线性表的指针
*/
duList *CreateList()
{
duList *pList = (duList *)malloc( sizeof(duList) );
pList->head = pList->foot = MakeNode();
pList->head->next = NULL;
pList->foot->prior = NULL; pList->len = ; return pList;
} /**
* @brief 销毁一条线性表
*
* @param 指向待销毁的线性表的指针
*
* @return void
*/
void DestroyList( duList *pList )
{
duNode *pm = pList->head, *pn = NULL; while( pm != NULL )
{
pn = pm->next;
free(pm);
pm = pn;
} free( pList );
pList = NULL;
} /**
* @brief 置空一条线性表
*
* @param pList 指向待置空的线性表指针
*
* @return void
*/
void ClearList( duList *pList )
{
duNode *pm = pList->head->next, *pn = NULL;
while( pm != NULL )
{
pn = pm->next;
free(pm);
pm = pn;
} pList->foot = pList->head;
pList->head->next = NULL;
pList->foot->prior = NULL;
pList->len = ;
} /**
* @brief 获取线性表长度
*
* @param pList 指向待获取长度的线性表指针
*
* @return 返回线性表长度
*/
int GetLength( duList *pList )
{
return pList->len;
} /**
* @brief 检测线性表是否为空
*
* @param pList 指向待检测的线性表指针
*
* @return 为空返回 TRUE, 否则返回 FALSE
*/
int IsEmpty( duList *pList )
{
return pList->len == ? TRUE : FALSE;
} /**
* @brief 向线性表末尾添加数据元素
*
* @param pList 指向待添加数据元素的线性表指针
* @param pt 指向数据元素的指针
*
* @return 返回成功添加后的线性表长度
*/
int AppendElem( duList *pList, ElemType *pt )
{
duNode *pNode = MakeNode();
pNode->pt.x = pt->x;
pNode->pt.y = pt->y; pList->foot->next = pNode;
pNode->next = NULL;
pNode->prior = pList->foot;
pList->foot = pNode; return ++pList->len;
} /**
* @brief 向线性表中插入数据元素
*
* @param nPos 元素插入的位置
* @param pt 指向待插入的数据元素的指针
*
* @return 插入成功则返回成功插入后线性表的长度, 否则返回 -1
*
* @note 元素位置由0计起
*/
int InsertElem( duList *pList, int nPos, ElemType *pt )
{
///要插入的位置不在线性表中
if( nPos < || nPos > pList->len )
return -; duNode *pNode = MakeNode();
pNode->pt.x = pt->x;
pNode->pt.y = pt->y; duNode *pm = pList->head; if( nPos == pList->len ) ///插入到尾部, 特殊处理
{
pNode->next = NULL;
pNode->prior = pList->foot;
pList->foot->next = pNode;
pList->foot = pNode; return ++pList->len;
} int i = ;
for( i = ; i < nPos; ++i, pm = pm->next );
pNode->next = pm->next;
pNode->prior = pm;
pm->next->prior = pNode;
pm->next = pNode; return ++pList->len;
} /**
* @brief 从线性表中删除一个节点元素
*
* @param pList 指向待删除元素的线性表指针
* @param nPos 需要删除的元素位置
*
* @return 成功删除后返回删除后线性表的长度, 否则返回-1
*/
int DeleteElem( duList *pList, int nPos )
{
///需要删除的节点不在线性表中
if( nPos < || nPos > pList->len- )
return -; duNode *pm = pList->head, *pn = NULL; ///删除尾节点, 特殊处理
if( nPos == pList->len- )
{
pn = pList->foot;
pList->foot = pList->foot->prior;
pList->foot->next = NULL;
free(pn); return --pList->len;
} int i = ;
for( i = ; i < nPos; ++i, pm = pm->next ); pn = pm->next;
pm->next = pn->next;
pn->prior = pm;
free(pn); return --pList->len;
} /**
* @brief 获取线性表中某位置上的元素
*
* @param pList 指向待获取元素的线性表指针
* @param nPos 元素在线性表中的位置
* @param pt 指向存放获取到的元素的指针
*
* @return 若获取成功, 返回 TRUE, 否则返回 FALSE
*
* @note 元素位置从 0 计起
*/
int GetElem( duList *pList, int nPos, ElemType *pt )
{
if( nPos < || nPos > pList->len- )
return FALSE; duNode *p = NULL;
int i = ;
///判断从哪端起获取元素更近
if( pList->len / > nPos ) //从首端取
{
p = pList->head;
for( i = ; i <= nPos; ++i, p = p->next );
}
else //从尾端取
{
nPos = pList->len - nPos - ;
p = pList->foot;
for( i = ; i < nPos; ++i, p = p->prior );
} pt->x = p->pt.x;
pt->y = p->pt.y; return TRUE;
} /**
* @brief 从某位置起查找某元素在线性表中第一次出现的位置
*
* @param pList 指向待查找元素的线性表的指针
* @param nPos 查找起始位置
* @param pt 指向待查找的元素的指针
*
* @return 若找到, 则返回元素所在的位置, 否则返回 -1
*
* @note 起始位置由 0 计起
*/
int FindElem( duList *pList, int nPos, ElemType *pt )
{
///起始位置不在线性表内
if( nPos < || nPos > pList->len - )
return -; duNode *p = pList->head;
int i = , ncnt = ; for( i = ; i < nPos; ++i, p = p->next );
while( p->next != NULL && (p = p->next) )
{
if( p->pt.x == pt->x && p->pt.y == pt->y )
return nPos + ncnt; ++ncnt;
} return -;
} /**
* @brief 获取某 pt 元素的前驱节点到 prior_pt
*
* @param pList 指向待获取前驱节点的线性表指针
* @param pt 指向目标节点的指针
* @param prior_pt 存放目标节点 pt 的前驱节点
*
* @return 若成功获取前驱节点, 返回该前驱节点在线性表中的位置, 否则返回 -1
*
* @note 元素位置从 0 计起
*/
int GetPriorElem( duList *pList, ElemType *pt, ElemType *prior_pt )
{
duNode *p = pList->head;
int ncnt = ; while( p != NULL && (p = p->next) )
{
if( p->pt.x == pt->x && p->pt.y == pt->y )
{
if( ncnt == ) ///pt为头结点, 不存在前驱节点
return -; prior_pt->x = p->prior->pt.x;
prior_pt->y = p->prior->pt.y; return ncnt - ;
} ++ncnt;
} return -;
} /**
* @brief 获取某 pt 元素的后继节点到 next_pt
*
* @param pList 指向待获取前后继点的线性表指针
* @param pt 指向目标节点的指针
* @param prior_pt 存放目标节点 pt 的后继节点
*
* @return 若成功获取后继节点, 返回该后继节点在线性表中的位置, 否则返回 -1
*
* @note 元素位置从 0 计起
*/
int GetNextElem( duList *pList, ElemType *pt, ElemType *next_pt )
{
duNode *p = pList->head;
int ncnt = ; while( p != NULL && (p = p->next) )
{
if( p->pt.x == pt->x && p->pt.y == pt->y )
{
if( ncnt == pList->len- ) ///pt为尾节点, 不存在后继节点
return -; next_pt->x = p->next->pt.x;
next_pt->y = p->next->pt.y; return ncnt + ;
} ++ncnt;
} return -;
} /**
* @brief 对线性表中每个元素从前向后依次执行 func 函数
*
* @param pList 指向待处理的线性表的指针
* @param func 传入的函数指针
*
* @return void
*/
void ForEachList( duList *pList, void (*func)(ElemType *pt) )
{
duNode *p = pList->head;
while( (p = p->next) != NULL )
{
func( &p->pt );
}
} /**
* @brief 对线性表中每个元素从后向前依次执行 func 函数
*
* @param pList 指向待处理的线性表的指针
* @param func 传入的函数指针
*
* @return void
*/
void ReForEachList( duList *pList, void (*func)(ElemType *pt) )
{
duNode *p = pList->foot;
while( p->prior != NULL )
{
func( &p->pt );
p = p->prior;
}
} /**
* @brief 将 pSrcList 性表复制到 pDestList 线性表后
*
* @param pDestList 指向目标线性表指针
* @param pSrcList 指向源线性表指针
*
* @return 返回复制后目标线性表长度
*/
int ListCpy( duList *pDestList, duList *pSrcList )
{
duNode *p = pSrcList->head, *tmp = NULL;
while( p->next != NULL && (p = p->next) )
{
tmp = MakeNode();
tmp->pt.x = p->pt.x;
tmp->pt.y = p->pt.y; tmp->prior = pDestList->foot;
pDestList->foot->next = tmp;
pDestList->foot = tmp;
}
pDestList->foot->next = NULL;
pDestList->len += pSrcList->len; return pDestList->len;
} /**
* @brief 将 pSrcList 性表连接到 pDestList 线性表后
*
* @param pDestList 指向目标线性表指针
* @param pSrcList 指向源线性表指针
*
* @return 返回连接后目标线性表长度
*
* @note 连接后 pSrcList 线性表将被销毁
*/
int ListCat( duList *pDestList, duList *pSrcList )
{
pDestList->foot->next = pSrcList->head->next;
pSrcList->head->next->prior = pDestList->foot;
pDestList->foot = pSrcList->foot;
pDestList->len += pSrcList->len; free(pSrcList);
pSrcList = NULL; return pDestList->len;
} //测试 duList void display( ElemType *pt )
{
printf("(%d,%d) ", pt->x, pt->y);
} int main()
{
///创建双向线性表
duList *plA = CreateList();
duList *plB = CreateList(); ElemType pt1, pt2; int i = , n = , pos = ; ///向线性表中添加元素
for( i = ; i < ; ++i )
{
pt1.x = pt1.y = i;
AppendElem( plA, &pt1 );
} for( i = ; i < ; ++i )
{
pt2.x = pt2.y = i;
AppendElem( plB, &pt2 );
} ///测试 IsEmpty、GetLength
if( IsEmpty(plA) == FALSE )
printf( "plA length = %d\n", GetLength(plA) ); ///测试 ForEachList、ReForEachList
ForEachList( plA, display ); //测试迭代输出 plA 中元素
putchar( '\n' );
ReForEachList( plA, display ); //测试反向迭代输出 plA 中元素 printf( "\n\n" );
///测试 InsertElem
pt1.x = pt1.y = ;
puts("plA测试InsertElem"); InsertElem( plA, , &pt1 ); //在 plA 位置 0 处插入元素(1, 1)
ForEachList( plA, display ); printf( "\n\n" );
///测试 DeletetElem
puts("plA测试DeleteElem"); DeleteElem( plA, ); //在 plA 位置 1 处的元素
ForEachList( plA, display ); printf( "\n\n" );
///测试 GetElem
GetElem( plA, , &pt2 );
printf( "plA 位置为 3 的元素为: (%d,%d)", pt2.x, pt2.y ); printf( "\n\n" );
///测试 GetPriorElem
GetPriorElem( plA, &pt2, &pt1 );
printf( "plA 位置为 3 的元素(%d,%d)的前驱节点为(%d,%d)", pt2.x, pt2.y, pt1.x, pt1.y ); printf( "\n\n" );
///测试 GetNextElem
GetNextElem( plA, &pt2, &pt1 );
printf( "plA 位置为 3 的元素(%d,%d)的后继节点为(%d,%d)", pt2.x, pt2.y, pt1.x, pt1.y ); printf( "\n\n" );
///测试 FindElem
pt1.x = pt1.y = ;
printf( "元素(5,5)在plA中的位置为: %d", FindElem( plA, , &pt1 ) ); printf( "\n\n" );
///测试 ListCpy
puts( "测试ListCpy plB到PlA: " );
ListCpy( plA, plB );
ForEachList( plA, display );
printf( "\n复制后plA长度: %d", GetLength(plA) ); printf( "\n\n" );
///测试 ListCpy
puts( "测试ListCat plB到PlA: " );
ListCat( plA, plB );
ForEachList( plA, display );
printf( "\n连接后plA长度: %d", GetLength(plA) ); DestroyList( plA ); return ;
}

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