[算法天天练] - 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.银行家算法: 我们可以把操作系统看作是银行家,操 ...
随机推荐
- js获取上传的文件名称
<input name="file_" type="file" id="file_" size="100" /&g ...
- c++11中的线程、锁和条件变量
void func(int i, double d, const string& s) { cout << i << ", " << d ...
- formData 对象
(1)创建的formData打印为空? var edition=$("#edinum").val();//版本号 var uploader=$("#upman" ...
- Delphi中处理URL编码解码
Delphi中处理URL编码解码 一.URL简单介绍 URL是网页的地址,比方 http://www.shanhaiMy.com. Web 浏览器通过 URL 从 web server请求页面 ...
- luogu1941 飞扬的小鸟
题目大意 游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度).小鸟始终在游戏界面内移动.小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成.小鸟每个 ...
- SQL SERVER 安装软件 及导入项目流程
1.安装sqlsever2000及以上 数据库 (在百度上找安装文档) 创建账户 密码 2.解压SQL2000-KB884525-SP4-x86-CHS.EXE补丁 之后安装补丁 ,在安装补丁是会用到 ...
- makefile 参数
GNU Make make是负责从项目的源代码中生成最终可执行文件和其他非源代码文件的工具. make命令本身可带有四种参数:标志.宏定义.描述文件名和目标文件名. 其标准形式为:make [flag ...
- sql语句如何查询当天,一周,一月的数据的语句
sql查询当天,一周,一个月数据的语句 --查询当天: select * from info where DateDiff(dd,datetime,getdate())=0 --查询24小时内的: ...
- HDU 2544 最短路 (Floyd)
题意:略. 析:由于 n 比较小,所以我们可以用Floyd,完全不会超时. 代码如下: #pragma comment(linker, "/STACK:1024000000,10240000 ...
- 从缓冲上看阻塞与非阻塞socket在发送接收上的区别(转载)
转自:http://blog.chinaunix.net/uid-24517549-id-4044877.html 首先socket在默认情况下是阻塞状态的,这就使得发送以及接收操作处于阻塞的状态 ...