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 或程序缺陷, 请留言反馈, 谢谢。
C语言 线性表 双向链式结构 实现的更多相关文章
- C++线性表的链式存储结构
C++实现线性表的链式存储结构: 为了解决顺序存储不足:用线性表另外一种结构-链式存储.在顺序存储结构(数组描述)中,元素的地址是由数学公式决定的,而在链式储存结构中,元素的地址是随机分布的,每个元素 ...
- C 线性表的链式存储实现及插入、删除等操作示例
一.链式存储的优势 线性表的存储可以通过顺序存储或链式存储实现,其中顺序存储基于数组实现(见本人上一篇博客),在进行插入删除等操作时,需对表内某一部分元素逐个移动,效率较低.而链式结构不依赖于地址连续 ...
- C/C++编程笔记:C语言成绩管理系统!链式结构的管理系统源码分享
最近很多同学因为学校的要求,需要完成自己的那个C语言课程设计,于是就有很多人私信或者加我私聊我,问的最多的还是<学生成绩管理系统>,其实当你项目写多了你就会发现:其实各类的管理系统都离不开 ...
- C++编程练习(2)----“实现简单的线性表的链式存储结构“
单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素. 对于查找操作,单链表的时间复杂度为O(n). 对于插入和删除操作,单链表在确定位置后,插入和删除时间仅为O(1). 单链表不需要分配存储 ...
- 数据结构-线性表的链式存储相关算法(C语言实现)
链表的简单介绍 为什么需要线性链表 当然是为了克服顺序表的缺点,在顺序表中,做插入和删除操作时,需要大量的移动元素,导致效率下降. 线性链表的分类 按照链接方式: 按照实现角度: 线性链表的创建和简单 ...
- 数据结构算法C语言实现(二)---2.3线性表的链式表示和实现之单链表
一.简述 [暂无] 二.头文件 #ifndef _2_3_part1_H_ #define _2_3_part1_H_ //2_3_part1.h /** author:zhaoyu email:zh ...
- 线性表的链式存储——C语言实现
SeqList.h #ifndef _WBM_LIST_H_ #define _WBM_LIST_H_ typedef void List; typedef void ListNode; //创建并且 ...
- 线性表的链式实现(C++)
相关内容: 线性表的顺序实现 链式实现(C语言) (推荐在GitHub上查看,下面代码只是最初实现,后续如果有修改,由于太麻烦,不会再更改下文,仅仅更新Github上的代码文件) 结点以及链表类的定义 ...
- 线性表 顺序存储 链式存储 ---java实现
首先抽象出一个线性表抽象类(包括主要的增删操作) public abstract class MyAbstractList<E> { public abstract void add(E ...
随机推荐
- 让 Terminal/vim 使用 Solarized 配色
经过亲身体验,终于使用上了solarized的配色,之前配出来相差太多,于是找到这篇参考博文:http://blog.csdn.net/angle_birds/article/details/1169 ...
- css3颜色
镂空字的2种做法
- Java遍历JSON
JSONObject jsonObject = new JSONObject(s);然后用Iterator迭代器遍历取值,建议用反射机制解析到封装好的对象中 JSONObject jsonObject ...
- BSF、BSR: 位扫描指令
;BSF(Bit Scan Forward): 位扫描找1, 低 -> 高 ;BSR(Bit Scan Reverse): 位扫描找1, 高 -> 低 找到是 1 的位后, 把位置数给 ...
- 计算机病毒实践汇总四:netcat使用方法
在尝试学习分析的过程中,判断结论不一定准确,只是一些我自己的思考和探索.敬请批评指正! 1. netcat概述 (1)特性 "TCP/IP协议栈瑞士军刀",可以被用在支持端口扫描. ...
- smarty模板原理
smarty模板原理 模板主要是用来让前端和后端分离的,前台页面只是一个前台页面,后台页面用php代码写逻辑,写完逻辑拿到前台显示. 一.写法 一般需要以下:写3个页面: 1.显示页面aa.htm ...
- EF联合查询的新用法
用EF很多年了,做联合查询时,只知道linq和lambda两种语法,今天朋友发了一个链接,打开看后发现是EF内置的新的关于联合查询的方法,赶紧抄录下来,以备后用. 现在先把这几种方法,各写一个例子,便 ...
- iOS出现<object returned empty description>的解决方法
iOS出现<object returned empty description>的解决方法: 使用 [str length] <= 0 判断处理
- 改进的SQL Express LocalDBB
介绍一种改进的SQL Express LocalDB LocalDB专门为开发商.它是非常容易安装,无需管理,但它提供了相同的T-SQL语言,编程表面和客户端供应商定期的SQL Server Expr ...
- Selenium2+python自动化2-pip降级selenium3.0
selenium版本安装后启动Firefox出现异常:'geckodriver' executable needs to be in PATH selenium默默的升级到了3.0,然而网上的教程都是 ...