[算法天天练] - C语言实现双向链表(一)
双向链表是比较常见的,主要是在链表的基础上添加prev指针,闲话少说直接上代码吧(这个也是网上一个大神的思路,真心不错,条理清楚,逻辑缜密)
主要也是为了学习,贴上我所调试成功的代码(Linux环境下)
双向链表代码:
#include <stdio.h>
#include <stdlib.h> typedef struct NodeTag Node;
typedef struct LinkedListTag LinkedList; struct NodeTag
{
Node* prev;
Node* next;
void* data;
}; struct LinkedListTag
{
Node* head;
Node* tail;
Node* cur;
int size;
}; // 创建一个链表 成功返回该链表的指针 否则返回NULL
LinkedList* Create( void )
{
// 创建一个新节点
LinkedList* list = (LinkedList*)malloc(sizeof(LinkedList));
// 创建不成功,返回NULL
if(!list) return NULL; list->head = NULL;
list->tail = NULL;
list->cur = NULL;
list->size = ; // 初始化成功后,返回list
return list;
} // 将元素添加到链表的末尾,成功返回链表的size,失败返回-1
int AddBack(LinkedList* list, void* data)
{
// 创建一个新节点,创建不成功的话,返回-1
Node* node = (Node *)malloc(sizeof(Node));
if(!node) return -; // 为节点的数据域赋值
node->data = data;
// 如果为链表的末尾
if(list->tail)
{
list->tail->next = node; // 把新节点赋给链表末尾的下一个
node->prev = list->tail; // 新节点的前一个等于之前的末节点
node->next = NULL; // 新节点为末节点,把它下一个指向NULL
}
else // 如果不为末尾,其实就是空链表
{
node->next = NULL; // 新节点的下一个为NULL
node->prev = NULL; // 新节点的前一个为NULL
list->head = node; // 链表的头为新节点node
}
list->tail = node; // 链表的末尾指向node return ++list->size; // 返回链表的size
} // 将元素添加到链表前端,成功返回非0,否则返回0
int AddFront(LinkedList* list, void* data)
{
Node *node = (Node*)malloc(sizeof(Node));
if(!node) return ; node->data = data;
if(list->head)
{
list->head->prev = node;
node->next = list->head;
node->prev = NULL;
}
else
{
node->next = NULL;
node->prev = NULL;
list->tail = node;
}
list->head = node; return ++list->size;
} // 将元素从末端移除并返回该元素,如果链表为空则返回NULL
void* RemoveBack(LinkedList* list)
{
Node* temp;
void* data; if(!list->size) return NULL; temp = list->tail;
data = list->tail->data; if(list->head == list->tail)
{
list->head = NULL;
list->tail = NULL;
list->cur = NULL;
}
else
{
list->tail = list->tail->prev;
list->tail->next = NULL;
}
--list->size;
free(temp);
return data;
} // 将元素从前端移除并返回该元素,如果链表为空则返回NULL
void* RemoveFront(LinkedList* list)
{
Node* temp;
void* data; if(!list->size) return NULL; temp = list->head;
data = list->head->data; if(list->head == list->tail)
{
list->head = NULL;
list->tail = NULL;
list->cur = NULL;
}
else
{
list->head = list->head->next;
list->head->prev = NULL;
}
--list->size;
free(temp);
return data;
} /* 如果当前链表为空则返回非0,否则返回0 */
int IsEmpty(LinkedList* list)
{
return list->size == ;
} /* 获得链表的大小(元素总个数) */
int Size(LinkedList* list)
{
return list->size;
} /* 将当前位置移动到链表的开始 */
void Begin(LinkedList* list)
{
list->cur = list->head;
} /* 将当前位置移动到链表的最后 */
void End(LinkedList* list)
{
list->cur = list->tail;
}
/* 将当前位置向后移动一个位置 */
void MoveNext(LinkedList* list)
{
list->cur = list->cur->next;
} /* 将当前位置向后移动一个位置 */
void MovePrev(LinkedList* list)
{
list->cur = list->cur->prev;
} /* 清空链表中所有元素 */
void Clear(LinkedList* list)
{
while(RemoveBack(list));
} /* 销毁一个链表 */
void Destroy(LinkedList* list)
{
Clear(list);
free(list);
} /* 如果当前位置之后还有元素则返回非0,否则返回0 */
int HasNext(LinkedList* list)
{
if (!list->cur) return ;
if (list->cur == list->tail) return ;
return list->cur->next != NULL;
} /* 如果当前位置之前还有元素则返回非0,否则返回0 */
int HasPrev(LinkedList* list)
{
if (!list->cur) return ;
if (list->cur == list->head) return ;
return list->cur->prev != NULL;
} /* 返回当前位置的元素 */
void* Current(LinkedList* list)
{
return list->cur->data;
} // 正向打印链表
void Traverse(LinkedList* list)
{
for( Begin(list); HasNext(list); MoveNext(list) )
printf("%d ", *(int*)Current(list));
putchar('\n');
} // 反向打印链表
void RTraverse(LinkedList* list)
{
for (End(list); HasPrev(list); MovePrev(list))
printf("%d ", *(int*)Current(list));
putchar('\n');
} int main()
{
int i;
LinkedList* list = Create(); int array1[];
int array2[]; for(i=; i<; i++)
{
array1[i] = i+;
array2[i] = i++;
AddBack(list, &array1[i]);
} printf("链表大小(SIZE): %d\n", Size(list)); printf("正向打印链表:\n");
Traverse(list);
printf("反向打印链表:\n");
RTraverse(list); printf("添加array2[0]数\n");
AddBack(list, &array2[]); printf("链表大小(SIZE): %d\n", Size(list));
printf("正向打印链表:\n");
Traverse(list);
printf("反向打印链表:\n");
RTraverse(list); printf("调用AddFront函数,添加array2[0]数\n");
AddFront(list, &array2[]); printf("链表大小(SIZE): %d\n", Size(list));
printf("正向打印链表:\n");
Traverse(list);
printf("反向打印链表:\n");
RTraverse(list); printf("从末尾移除的元素是: %d\n", *(int *)RemoveBack(list));
printf("链表大小(SIZE): %d\n", Size(list));
printf("正向打印链表:\n");
Traverse(list);
printf("反向打印链表:\n");
RTraverse(list); printf("从开头移除的元素是: %d\n", *(int *)RemoveFront(list));
printf("链表大小(SIZE): %d\n", Size(list));
printf("正向打印链表:\n");
Traverse(list);
printf("反向打印链表:\n");
RTraverse(list); printf("清空链表,Clear(list)后\n");
Clear(list);
printf("链表大小(SIZE): %d\n", Size(list)); for(i=; i<; i++)
{
AddFront(list, &array2[i]);
}
printf("正向打印链表:\n");
Traverse(list);
printf("反向打印链表:\n");
RTraverse(list); Destroy(list);
printf("销毁链表Destroy(list)\n"); return ;
}
以下是执行结果:
链表大小(SIZE):
正向打印链表: 反向打印链表: 添加array2[]数
链表大小(SIZE):
正向打印链表: 反向打印链表: 调用AddFront函数,添加array2[]数
链表大小(SIZE):
正向打印链表: 反向打印链表: 从末尾移除的元素是:
链表大小(SIZE):
正向打印链表: 反向打印链表: 从开头移除的元素是:
链表大小(SIZE):
正向打印链表: 反向打印链表: 清空链表,Clear(list)后
链表大小(SIZE):
正向打印链表: 反向打印链表: 销毁链表Destroy(list)
在世界上,努力坚持的绝对不是自己一个人,好好努力会成功的。
[算法天天练] - C语言实现双向链表(一)的更多相关文章
- [算法天天练] - C语言实现约瑟夫环(2)
Linux下 #include <stdlib.h>#include <stdio.h> int main(){ int n,m,i,s = 0; printf("E ...
- C语言实现双向链表
目前我们所学到的链表,无论是动态链表还是静态链表,表中各节点中都只包含一个指针(游标),且都统一指向直接后继节点,通常称这类链表为单向链表(或单链表). 虽然使用单链表能 100% 解决逻辑关系为 & ...
- 用C语言把双向链表中的两个结点交换位置,考虑各种边界问题。
用C语言把双向链表中的两个结点交换位置,考虑各种边界问题. [参考] http://blog.csdn.net/silangquan/article/details/18051675
- 关于中值滤波算法,以及C语言实现(转)
源:关于中值滤波算法,以及C语言实现 1.什么是中值滤波? 中值滤波是对一个滑动窗口内的诸像素灰度值排序,用其中值代替窗口中心象素的原来灰度值,它是一种非线性的图像平滑法,它对脉冲干扰级椒盐噪声的抑制 ...
- 基于BP神经网络的简单字符识别算法自小结(C语言版)
本文均属自己阅读源代码的点滴总结.转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:gzzaigcn2009@163.com 写在前面的闲话: 自我感觉自己应该不是一个非常 ...
- FFT算法理解与c语言的实现
完整内容迁移至 http://www.face2ai.com/DIP-2-3-FFT算法理解与c语言的实现/ http://www.tony4ai.com/DIP-2-3-FFT算法理解与c语言的实现 ...
- 算法小练#1 - Dany Yang
开始记录每周做过的算法题,这是第一周,新的开始 1021. 删除最外层的括号 题目要求如下: 有效括号字符串为空 ("")."(" + A + ")& ...
- C++语言实现双向链表
这篇文章是关于利用C++模板的方式实现的双向链表以及双向链表的基本操作,在之前的博文C语言实现双向链表中,已经给大家分析了双向链表的结构,并以图示的方式给大家解释了双向链表的基本操作.本篇文章利用C+ ...
- 【操作系统】银行家算法实现(C语言)
[操作系统]银行家算法实现(C语言) 注意:本人编码水平很菜.算是自己的一个总结.可能会有我还没有发现的bug.如果有人发现后可以指出,不胜感激. 1.银行家算法: 我们可以把操作系统看作是银行家,操 ...
随机推荐
- HDD
硬盘 SCSI ★ Host adapter ★ SCSI standard ★ Bus socket ★ Signal fashion ★ SCAM ★ Bus main control ★ Dri ...
- vuex 存值 及 取值 的操作
1.传值 // 定义参数 let params = { workItemId: workItemId, flowInstId: flowInstId, itemStatus: itemStatus, ...
- 【SSO】--单点登录之过滤器(filter)
在单点登录的探索中.用到一个知识点:过滤器(filter).常见的几种验证:Authorization filters,验证用户是否有权限訪问页面:Action Filter,验证用户登录的时候是否用 ...
- 两个月后才更新一篇。。。。LIB和DLL的差别
共同拥有两种库: 一种是LIB包括了函数所在的DLL文件和文件里函数位置的信息(入口).代码由执行时载入在进程空间中的DLL提供,称为动态链接库dynamic link library. 一种是 ...
- Eclipse或SVN—怎样在Eclipse中安装SVNclient插件
1.下载SVN插件,下载地址:http://download.csdn.net/download/wangshuxuncom/7638615 2.解压下载下来的压缩文件然后依据里面名为"使用 ...
- MariaDB ----单表查询
1>按一定条件查询某字段的数据 (where) ; ( 查询 id > 的数据) #补充: ; 注意“ select * from students1: (此命令需谨慎使用, 数据量大 ...
- 【hdu3544】 Alice's Game
给一块n*m的巧克力,Alice只能垂直切,切成A*m和B*m,并且A+B=n,Bob只能横切,只能切成A*n和B*n,并且A+B=m. 对于n*n的这种巧克力,谁先切了第一刀,就直接让对方有切两刀的 ...
- java连接Oracle案例
首先来讲一下桥连接: 首先配置数据源:打开控制面板——管理工具——数据源(ODBC)——用户DSN——添加——找到Oracle驱动程序. //JDBC-ODBC桥连接public class Conn ...
- Python基础第六天
一.内容 二.练习 练习1 题目:文件的增删改查 图示: 代码: import os def add(data): content = data[1] # 文件内容 file_name = data[ ...
- Java 泛型 一
泛型在Java中有很重要的地位,网上很多文章罗列各种理论,不便于理解,本篇将立足于代码介绍.总结了关于泛型的知识. 先看下面的代码: List list = new ArrayList(); list ...