赞
踩
链表是一种常见的数据结构了,我们希望实现类似如下的双向链表(图片来源网络):
如下定义:
typedef struct DoubleLinkList
{
DLNode* head; // 链表头
DLNode* back; // 链表尾
size_t size; //链表包含的元素的个数 typedef unsigned int size_t;
}DLlist; // 双链表
每个元素或节点如下(图片来源网络):
如下定义:
typedef struct DoubleLinkListNode
{
struct DoubleLinkListNode* pPre; // 前一个节点指针
struct DoubleLinkListNode* pNext; // 后一个节点指针
_TYPE value;
}DLNode; // 节点
结构体不熟悉的可以参考:C语言 结构体与共用体
编写如下doublelinklist.h头文件
#pragma once
#define _ASC 1 // 升序排序
#define _DESC 0 // 降序排序
typedef int _TYPE; // 数据类型
typedef struct DoubleLinkListNode
{
struct DoubleLinkListNode* pPre; // 前一个节点指针
struct DoubleLinkListNode* pNext; // 后一个节点指针
_TYPE value;
}DLNode; // 节点
typedef struct DoubleLinkList
{
DLNode* head; // 链表头
DLNode* back; // 链表尾
size_t size; //链表包含的元素的个数 typedef unsigned int size_t;
}DLlist; // 双链表
// 对一个新链表进行初始化
void init(DLlist* pList);
// 快速创建一个空的双链表
DLlist* _createList();
// 使用可变参数来创建一个链表
DLlist* _createListWithValues(int length, ...);
// 使用数组来创建一个链表
DLlist* _createListWithArrayValues(_TYPE array[], int length);
// 插入到头部,返回1插入成功
int addToHead(DLlist* pList, _TYPE value);
// 插入到尾部,返回1插入成功
int addToBack(DLlist* pList, _TYPE value);
// 将一维数组的值添加到链表头部,返回1插入成功
int addToHeadWithArrayValues(DLlist* pList, _TYPE array[], int length);
// 将一维数组的值添加到链表尾部,返回1插入成功
int addToBackWithArrayValues(DLlist* pList,_TYPE array[], int length);
// 插入到指定元素的后面,返回1插入成功
int insertAfter(DLlist* pList, _TYPE curValue, _TYPE newValue);
// 插入到指定元素的后面,返回1插入成功,改进版
int insertAfter2(DLlist* pList, _TYPE curValue, _TYPE newValue);
// 插入到指定元素的前面,返回1插入成功
int insertBefore(DLlist* pList, _TYPE curValue, _TYPE newValue);
// 插入到指定元素的前面,返回1插入成功,改进版
int insertBefore2(DLlist* pList, _TYPE curValue, _TYPE newValue);
// 删除第一个节点,并返回它
DLNode* removeFirst(DLlist* pList);
// 删除最后一个节点,并返回它
DLNode* removeLast(DLlist* pList);
// 正向显示所有
void showAll(DLlist* pList);
// 使用递归正向显示所有
void showAllWithRecursion(DLNode* head);
// 反向显示所有
void showAllReverse(DLlist* pList);
// 使用递归反向显示所有
void showAllReverseWithRecursion(DLNode* back);
// 删除指定元素,返回1删除成功
int deleteNode(DLlist* pList, _TYPE value);
// 删除指定元素,返回1删除成功,deleteNode改进版
int deleteNode2(DLlist* pList, _TYPE value);
// 删除一个范围的元素,从fromValue的节点开始删除,删除count个
int deleteRange(DLlist* pList, _TYPE fromValue,int count);
// 检查是否为空
int checkNull(void* p);
// 修改指定的值,返回1修改成功
int modify(DLlist* pList, _TYPE oldValue, _TYPE newValue);
// 释放所有元素,清空链表,返回1则成功
int freeAll(DLlist* pList);
// 从第一个匹配元素开始释放,返回1删除成功
int freeFrom(DLlist* pList, _TYPE value);
// 通过值找到指定匹配的第一个节点
DLNode* findByValue(DLlist* pList, _TYPE value);
// 将一个链表插入当前链表的尾部
int addListToBack(DLlist* pList, DLlist* addingList);
// 获取指定值的节点在链表中的深度
int getDepth(DLlist* pList, _TYPE value);
// 是否为空,返回1则为空
int isEmpty(DLlist* pList);
// 对链表值进行排序,asc为0则降序序排,否则升序。可以使用_ASC(升序) , _DESC(降序)
void sort(DLlist* pList,int asc);
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
在DoubleLinkList.c中实现。下面将函数分个显示
用于给通过DoubleLinkList创建的新链表进行初始化
void init(DLlist* pList)
{
pList->head = pList->back = NULL;
pList->size = 0;
}
快速创建一个双链表
DLlist* _createList()
{
DLlist* pList = (DLlist*)malloc(sizeof(DLlist));
pList->head = pList->back = NULL;
pList->size = 0;
return pList;
}
使用可变参数来创建一个链表,需要声明头文件#include<stdarg.h>
DLlist* _createListWithValues(int length, ...)
{
DLlist* pList = _createList();
va_list ap; // 参数指针
va_start(ap, length); // 第一个元素
for (int i = 0; i < length; i++)
{
addToBack(pList,va_arg(ap, _TYPE)); // 返回对应类型的数据,并添加到链表
}
va_end(ap);
return pList;
}
使用数组的元素来创建一个链表,length表示要添加到链表的个数
DLlist* _createListWithArrayValues(_TYPE array[], int length)
{
if (checkNull(array)|| 0==length)
{
return NULL;
}
DLlist* pList = _createList();
if (checkNull(pList))
{
return NULL;
}
if (addToBackWithArrayValues(pList, array, length))
{
return pList;
}
return NULL;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
插入双链表的头部,返回1则表示插入成功
int addToHead(DLlist* pList, _TYPE value)
{
if (checkNull(pList))
{
return 0;
}
DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
if (checkNull(newNode))
{
return 0; // 创建新节点失败,则返回
}
newNode->pNext = newNode->pPre = NULL;
newNode->value = value;
if (pList->head==NULL) // 若头节点为空,则新节点置为头节点
{
pList->head = newNode;
pList->back = newNode;
pList->size++;
}
else // 添加到头部
{
newNode->pNext = pList->head;
pList->head->pPre = newNode;
pList->head = newNode; // 将链表的头部设为新节点
pList->size++;
}
return 1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
插入到双链表的尾部,返回1插入成功
int addToBack(DLlist* pList, _TYPE value)
{
if (checkNull(pList))
{
return 0;
}
DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
if (checkNull(newNode))
{
return 0; // 创建新节点失败,则返回
}
newNode->pNext = newNode->pPre = NULL;
newNode->value = value;
if (NULL == pList->head) // 若头节点为空,则新节点置为头节点
{
pList->head = newNode;
pList->back = newNode;
pList->head->pNext = pList->back->pNext = NULL;
pList->size++;
}
else if (pList->size == 1) // 只有一个元素,头尾都指向它,链接好头部与下一个节点
{
newNode->pPre = pList->head;
pList->head->pNext = newNode;
pList->back = newNode;
pList->size++;
}
else // 添加到尾部
{
newNode->pPre = pList->back;
pList->back->pNext = newNode;
pList->back = newNode;
pList->size++;
}
return 1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
将一维数组的值添加到链表头部,返回1插入成功
int addToHeadWithArrayValues (DLlist* pList, _TYPE array[], int length)
{
if (checkNull(pList) || checkNull(array) || length == 0)
{
return 0;
}
for (int i = 0; i < length; i++)
{
if (!addToHead(pList, array[i]))
{
return 0;
}
}
return 1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
将一维数组的值添加到链表尾部,返回1插入成功
int addToBackWithArrayValues(DLlist* pList, _TYPE array[], int length)
{
if (checkNull(pList) || checkNull(array) || length == 0)
{
return 0;
}
for (int i = 0; i < length; i++)
{
if (!addToBack(pList, array[i]))
{
return 0;
}
}
return 1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
插入到指定值curValue的节点元素的后面,返回1则插入成功
int insertAfter(DLlist* pList, _TYPE curValue, _TYPE newValue)
{
if (checkNull(pList))
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:插入指定节点后面失败,空链表\n");
return 0;
}
DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
if (checkNull(newNode))
{
return 0; // 创建新节点失败,则返回
}
newNode->pNext = newNode->pPre = NULL;
newNode->value = newValue;
if (pList->head->value==curValue) // 头节点满足
{
DLNode* next = pList->head->pNext;
next->pPre = newNode;
newNode->pNext = next;
newNode->pPre = pList->head;
pList->head->pNext = newNode;
pList->size++;
return 1;
}
else if (pList->back->value == curValue) // 尾节点满足,防止要遍历一遍,浪费时间
{
pList->back->pNext = newNode;
newNode->pPre = pList->back->pNext;
pList->back;
pList->size++;
return 1;
}
else // 其他
{
DLNode* p = pList->head->pNext;
while (p)
{
if (p->value==curValue)
{
DLNode* next = p->pNext;
next->pPre = newNode;
newNode->pNext = next;
newNode->pPre = p;
p->pNext = newNode;
pList->size++;
return 1;
}
p = p->pNext;
}
}
return 0;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
插入到指定值curValue的节点元素的后面,返回1插入成功,insertAfter改进版
int insertAfter2(DLlist* pList, _TYPE curValue, _TYPE newValue)
{
if (checkNull(pList))
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:插入指定节点后面失败,空链表\n");
return 0;
}
DLNode* curNode = findByValue(pList, curValue); // 查找指定节点
if (checkNull(pList))
{
printf("\n插入失败,目标节点value=%d不存在\n", curNode);
return 0;
}
DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
if (checkNull(newNode))
{
return 0;
}
newNode->pNext = newNode->pPre = NULL;
newNode->value = newValue;
if (curNode==pList->back)
{
pList->back->pNext = newNode;
newNode->pPre = pList->back;
pList->back = newNode;
pList->size++;
}
else
{
DLNode* nextNode = curNode->pNext;
newNode->pPre = curNode;
newNode->pNext = nextNode;
curNode->pNext = newNode;
nextNode->pPre = newNode;
pList->size++;
}
return 1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
插入到指定值curValue的节点元素的前面,返回1则插入成功
int insertBefore(DLlist* pList, _TYPE curValue, _TYPE newValue)
{
if (checkNull(pList))
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:插入指定节点前面失败,空链表\n");
return 0;
}
DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
if (checkNull(newNode))
{
return 0;
}
newNode->pNext = newNode->pPre = NULL;
newNode->value = newValue;
if (curValue == pList->head->value) // 头节点满足
{
newNode->pNext = pList->head;
pList->head->pPre = newNode;
pList->head = newNode;
pList->size++;
return 1;
}
else if(pList->back->value == curValue) // 尾节点满足
{
newNode->pNext = pList->back;
newNode->pPre = pList->back->pPre;
pList->back->pPre->pNext = newNode; // 改变尾节点前面一个节点的指向,到newNode
pList->back->pPre = newNode;// 添加到尾节点前面
pList->size++;
return 1;
}
else
{
DLNode* curNode = pList->head->pNext;
while (curNode)
{
if (curNode->value == curValue)
{
DLNode* preNode = curNode->pPre;
newNode->pNext = curNode;
newNode->pPre = preNode;
curNode->pPre = newNode; // 添加到当前结点前面
preNode->pNext = newNode;
pList->size++;
return 1;
}
curNode = curNode->pNext;
}
}
return 0;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
插入到指定值curValue的节点元素的前面,返回1则插入成功,insertBefore改进版
int insertBefore2(DLlist* pList, _TYPE curValue, _TYPE newValue)
{
if (checkNull(pList))
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:插入指定节点后面失败,空链表\n");
return 0;
}
DLNode* curNode = findByValue(pList, curValue); // 查找指定节点
if (checkNull(pList))
{
printf("\n插入失败,目标节点value=%d不存在\n", curNode);
return 0;
}
DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
if (checkNull(newNode))
{
return 0;
}
newNode->pNext = newNode->pPre = NULL;
newNode->value = newValue;
if (curNode==pList->head)
{
newNode->pNext = pList->head;
pList->head->pPre = newNode;
pList->head = newNode;
pList->size++;
}
else
{
DLNode* preNode = curNode->pPre;
newNode->pNext = curNode;
newNode->pPre = preNode;
curNode->pPre = newNode;
preNode->pNext = newNode;
pList->size++;
}
return 1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
删除第一个节点,并返回它
DLNode* removeFirst(DLlist* pList)
{
if (checkNull(pList))
{
return NULL;
}
if (isEmpty(pList))
{
printf("\nlog:空链表\n");
return NULL;
}
if (pList->head->pNext==NULL) // 只有head
{
DLNode* head = pList->head;
pList->head = NULL;
pList->size--;
return head;
}
else
{
DLNode* head = pList->head;
DLNode* next = head->pNext;
head->pNext = NULL;
next->pPre = NULL;
pList->head = next;
pList->size--;
return head;
}
return NULL;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
删除最后一个节点,并返回它
DLNode* removeLast(DLlist* pList)
{
if (checkNull(pList))
{
return NULL;
}
if (isEmpty(pList))
{
printf("\nlog:空链表\n");
return NULL;
}
if (pList->back==pList->head)
{
return removeFirst(pList);
}
else
{
DLNode* back = pList->back;
DLNode* preNode = back->pPre;
back->pPre = NULL;
preNode->pNext = NULL;
pList->back = preNode;
pList->size--;
return back;
}
return NULL;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
正向显示所有节点值
void showAll(DLlist* pList)
{
if (checkNull(pList))
{
return;
}
else
{
if (isEmpty(pList))
{
printf("\nlog:showAll 空链表\n");
return;
}
printf("\n[ ");
DLNode* p = pList->head;
while (p!=NULL)
{
printf("%d ", p->value);
p = p->pNext; // 往后遍历
}
printf("]\n");
}
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
使用递归正向显示所有节点的值
void showAllWithRecursion(DLNode* head)
{
static count = 0;
if (NULL==head)
{
printf("]\n"); // 打印结束 ]
count = 0;
return;
}
else
{
if (count == 0) // 打印起始 [
{
printf("\n[ ");
}
count++;
printf("%d ", head->value);
showAllWithRecursion(head->pNext); // 递归调用,打印后面一个
}
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
反向显示所有节点的值
void showAllReverse(DLlist* pList)
{
if (checkNull(pList))
{
return;
}
if (isEmpty(pList))
{
printf("\nlog:空链表\n");
return 0;
}
printf("\n[ ");
DLNode* p = pList->back;
while (p!=NULL)
{
printf("%d ", p->value);
p = p->pPre; // 往前遍历
}
printf("]\n");
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
使用递归反向显示所有节点的值
void showAllReverseWithRecursion(DLNode* back)
{
if (NULL ==back)
{
printf("\n");
return;
}
else
{
printf("%d\t", back->value);
showAllReverseWithRecursion(back->pPre); // 递归调用,打印前一个
}
}
删除第一个指定元素的节点,返回1则删除成功
int deleteNode(DLlist* pList, _TYPE value)
{
if (checkNull(pList))
{
printf("\nlog:删除节点失败\n");
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:删除节点失败,空链表\n");
return 0;
}
DLNode* findNode = findByValue(pList, value);
if (checkNull(findNode))
{
printf("\nlog:要删除的节点不存在,value=%d\n", value);
return 0;
}
if (value == pList->head->value) // 头节点满足
{
if (pList->head->pNext==NULL) // 只有head时
{
DLNode* curNode = pList->head;
pList->head = pList->back = NULL; // 删除所有节点后将head与back都赋值NULL
free(curNode);
}
else
{
DLNode* curNode = pList->head;
pList->head = curNode->pNext; // 头节点后移
free(curNode);
}
pList->size--;
return 1;
}
else if (value == pList->back->value) // 尾节点满足
{
DLNode* curNode = pList->back;
pList->back = curNode->pPre;
pList->back->pNext = NULL;
free(curNode);
pList->size--;
return 1;
}
else
{
DLNode* curNode = pList->head->pNext;
while (curNode!=NULL) // 下面可以调用findByValue来查找指定节点
{
if (curNode->value==value) // 删除满足条件的节点
{
DLNode* preNode = curNode->pPre;
DLNode* nextNode = curNode->pNext;
preNode->pNext = nextNode;
nextNode->pPre = preNode;
free(curNode); // 释放内存
pList->size--;
return 1;
}
curNode = curNode->pNext;
}
}
return 0;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
删除指定元素,返回1删除成功,deleteNode改进版
int deleteNode2(DLlist* pList, _TYPE value)
{
if (checkNull(pList))
{
printf("\nlog:删除节点失败\n");
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:删除节点失败,空链表\n");
return 0;
}
DLNode* findNode = findByValue(pList, value);
if (checkNull(findNode))
{
printf("\nlog:要删除的节点不存在,value=%d\n", value);
return 0;
}
if (findNode==pList->head)
{
DLNode* curNode = pList->head;
pList->head = curNode->pNext;
pList->head->pPre = NULL;
free(curNode);
pList->size--;
}
else
{
DLNode* preNode = findNode->pPre;
DLNode* next = findNode->pNext;
preNode->pNext = next;
next->pPre = preNode; // 上一个节点与下一个节点连接起来
free(findNode);
pList->size--;
}
return 0;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
删除一个范围的元素节点,从fromValue值的节点开始删除,删除count个。返回1表示删除成功
int deleteRange(DLlist* pList, _TYPE fromValue, int count)
{
if (checkNull(pList))
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:空链表\n");
return 0;
}
DLNode* curNode = findByValue(pList,fromValue);
if (checkNull(curNode))
{
return 0;
}
int num = 0;
if (curNode==pList->head) // 如果是头节点
{
while (num < count && deleteNode(pList, pList->head->value)) // 从头部开始删除count个
{
++num;
}
return 1;
}
else
{
DLNode* preNode = curNode->pPre;
while (curNode)
{
if (num<count)
{
preNode->pNext = curNode->pNext;
curNode->pPre = preNode;
free(curNode);
++num;
}
else
{
break;
}
curNode = preNode->pNext;
}
}
if (num == count || NULL == curNode) // 如果删除了指定数量或已经是尾节点下一个了
{
pList->size -= (num==count)? count: num;
return 1;
}
return 0;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
检查指针是否为空
int checkNull(void* p)
{
if (NULL == p)
{
printf("\nlog: null pointer\n");
return 1;
}
return 0;
}
修改指定的值的节点,返回1表示修改成功
int modify(DLlist* pList, _TYPE oldValue, _TYPE newValue)
{
if (checkNull(pList) )
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:空链表\n");
return 0;
}
DLNode* curNode = pList->head;
while (curNode)
{
if (curNode->value==oldValue)
{
curNode->value = newValue;
return 1;
}
curNode = curNode->pNext;
}
return 0;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
释放所有元素,清空链表,返回1则成功
int freeAll(DLlist* pList)
{
if (checkNull(pList))
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:空链表\n");
return 0;
}
DLNode* curNode = pList->head->pNext;
while (curNode) // 循环删除头节点的下一个节点
{
pList->head->pNext = curNode->pNext;
free(curNode);
curNode = pList->head->pNext;
}
free(pList->head); // 删除头节点
pList->head = pList->back = NULL;
pList->size = 0;
return 1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
从第一个匹配值的节点开始释放,截断并丢弃从指定值节点开始到结尾的链。返回1删除成功
int freeFrom(DLlist* pList, _TYPE value)
{
if (checkNull(pList))
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:空链表\n");
return 0;
}
DLNode* curNode = findByValue(pList, value);
if (curNode==NULL)
{
printf("\nlog: 要删除value=%d的起始节点不存在\n",value);
return 0;
}
if (curNode==pList->head)
{
return freeAll(pList);
}
else
{
DLNode* preNode = curNode->pPre;
int depth = getDepth(pList, preNode->value);
DLlist* dyingList = (DLlist*)malloc(sizeof(DLlist)); // 将要被删除的链表
if (checkNull(dyingList))
{
return 0;
}
dyingList->head = curNode;
freeAll(dyingList); // 调用freeAll来删除
free(dyingList);
preNode->pNext = NULL; // 将curNode的上一个节点的pNext置NULL
pList->back = preNode; // 重新设置尾节点
pList->size = depth;
}
return 1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
通过值找到指定匹配的第一个节点
DLNode* findByValue(DLlist* pList, _TYPE value)
{
if (checkNull(pList))
{
return 0;
}
if (isEmpty(pList))
{
printf("\nlog:空链表\n");
return 0;
}
DLNode* curNode = pList->head;
while (curNode)
{
if (curNode->value==value)
{
return curNode;
}
curNode = curNode->pNext;
}
return NULL; // 没有找到还回空
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
将一个链表插入当前链表的尾部
int addListToBack(DLlist* pList, DLlist* addingList)
{
if (checkNull(pList)|| checkNull(addingList)||isEmpty(addingList))
{
return 0;
}
DLNode* curNode = addingList->head;
while (curNode)
{
addToBack(pList, curNode->value); // 添加到尾部
curNode = curNode->pNext;
}
return 1;
}
获取指定值的节点在链表中的深度
int getDepth(DLlist* pList, _TYPE value)
{
if (checkNull(pList))
{
return -1;
}
if (isEmpty(pList))
{
return 0;
}
DLNode* curNode = pList->head;
int depth = 0;
while (curNode)
{
depth++;
if (curNode->value==value)
{
return depth;
}
curNode = curNode->pNext;
}
return -1;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
判断链表是否为空,返回1则为空
int isEmpty(DLlist* pList)
{
if (checkNull(pList))
{
return 1;
}
return pList->size == 0;
}
使用选择排序法对链表值进行排序,asc为0则降序序排,否则升序。可以使用_ASC(升序) , _DESC(降序)
void sort(DLlist* pList, int asc)
{
if (checkNull(pList) || isEmpty(pList))
{
return;
}
for (DLNode *pi = pList->head; pi->pNext!=NULL; pi = pi->pNext)
{
DLNode *pk = pi;
for (DLNode *pj = pi->pNext; pj!= NULL; pj = pj->pNext)
{
if (asc && pk->value > pj->value) // 排升序
{
pk = pj;
}
if (!asc && pk->value < pj->value) // 排降序
{
pk = pj;
}
}
if (pk!=pi)
{
_TYPE value = pk->value;
pk->value = pi->value;
pi->value = value;
}
}
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
void main()
{
DLlist* pList = _createList(); // 创建一个双链表
addToHead(pList, 1); // 插入数据到头
addToHead(pList, 2);
addToHead(pList, 3);
addToHead(pList, 4);
addToHead(pList, 5);
addToBack(pList, 11); // 插入数据到尾
addToBack(pList, 22);
addToBack(pList, 33);
addToBack(pList, 44);
addToBack(pList, 55);
showAll(pList); // 正向显示所有
showAllReverse(pList); // 反向显示所有
modify(pList, 11, 66); // 将11修改为66
showAll(pList); // 正向显示所有
printf("size=%d\n", pList->size);
deleteNode(pList, 33);
showAll(pList); // 正向显示所有
printf("size=%d\n", pList->size); // 双链表的大小
system("pause");
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
输出:
[ 5 4 3 2 1 11 22 33 44 55 ]
[ 55 44 33 22 11 1 2 3 4 5 ]
[ 5 4 3 2 1 66 22 33 44 55 ]
size=10
[ 5 4 3 2 1 66 22 44 55 ]
size=9
void main()
{
DLlist* pList = (DLlist*)malloc(sizeof(DLlist));
init(pList);
addToHead(pList, 1);
addToHead(pList, 2);
addToHead(pList, 3);
addToHead(pList, 4);
addToHead(pList, 5);
addToHead(pList, 6);
addToHead(pList, 7);
addToHead(pList, 8);
addToHead(pList, 9);
addToHead(pList, 10);
showAll(pList);
printf("size=%d\n", pList->size); // 大小
freeFrom(pList, 3); // 从3开始,删除后面所有
showAll(pList);
printf("size=%d\n", pList->size);
deleteRange(pList, 9, 3); // 从9开始删除3个元素
showAll(pList);
printf("size=%d\n", pList->size);
freeAll(pList); // 清空链表
showAll(pList);
printf("size=%d\n", pList->size);
system("pause");
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
输出:
[ 10 9 8 7 6 5 4 3 2 1 ]
size=10
[ 10 9 8 7 6 5 4 ]
size=7
[ 10 6 5 4 ]
size=4
log:showAll 空链表
size=0
void main()
{
DLlist* pList = (DLlist*)malloc(sizeof(DLlist));
init(pList);
addToHead(pList, 1);
addToHead(pList, 2);
addToHead(pList, 3);
addToHead(pList, 4);
addToHead(pList, 5);
addToHead(pList, 6);
showAll(pList);
printf("size=%d\n", pList->size);
//int ib = insertBefore(pList, 5, 66);
int ib = insertBefore2(pList, 5, 66); // 在5前面插入66
if (ib)
{
printf("\n前插成功\n");
showAll(pList);
printf("size=%d\n", pList->size);
}
int ia = insertAfter(pList, 3, 26); // 在3后面插入26
if (ia)
{
printf("\n后插成功\n");
showAll(pList);
printf("size=%d\n", pList->size);
}
DLNode* find = findByValue(pList, 6); // 查找6
if (find)
{
printf("\nfind ,value=%d,depth=%d\n", find->value, getDepth(pList, find->value));
}
DLNode* first = removeFirst(pList); // 删除第一个节点并返回它
if (first)
{
printf("\nfirst value=%d\n", first->value);
showAll(pList);
printf("size=%d\n", pList->size);
}
DLNode* last = removeLast(pList); // 删除最后一个节点并返回它
if (last)
{
printf("\nlast value=%d\n", last->value);
showAll(pList);
printf("size=%d\n", pList->size);
}
system("pause");
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
输出:
[ 6 5 4 3 2 1 ]
size=6
前插成功
[ 6 66 5 4 3 2 1 ]
size=7
后插成功
[ 6 66 5 4 3 26 2 1 ]
size=8
find ,value=6,depth=1
first value=6
[ 66 5 4 3 26 2 1 ]
size=7
last value=1
[ 66 5 4 3 26 2 ]
size=6
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
void main()
{
DLlist* pList = _createListWithValues(5, 2, 3, 4, 5, 6);
DLlist* pnewList = _createListWithValues(5,11,22,33,44,55);
showAll(pList);
showAll(pnewList);
if (!checkNull(pList)&& !checkNull(pnewList))
{
addListToBack(pList, pnewList); // 将pnewList添加到pList尾部
}
showAll(pList);
printf("size=%d\n", pList->size);
system("pause");
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
输出:
[ 2 3 4 5 6 ]
[ 11 22 33 44 55 ]
[ 2 3 4 5 6 11 22 33 44 55 ]
size=10
void main()
{
// DLlist* pList = _createListWithValues(5, 2 ,8 , 4, 9, 7); // 创建一个包还5个元素(2 ,8 , 4, 9, 7)的链表
int arr[5] = { 2 ,8 , 4, 9, 7 };
DLlist* pList = _createListWithArrayValues(arr, 5);
//showAllReverse(pList);
sort(pList, _DESC); // 降序
showAll(pList);
sort(pList, _ASC); // 升序
showAll(pList);
// addToBackWithArrayValues(pList, arr, 3); // 将一个数组的值添加到链表尾部
//showAll(pList);
system("pause");
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
输出:
[ 9 8 7 4 2 ]
[ 2 4 7 8 9 ]
在上面的例子中,使用链表的相关函数进行操作时,会感覚很凌乱,有时可能会令人困惑,这到底是对谁进行的操作。在Java中,使用集合类时,都是通过对象来调用方法,比如如下代码:
List<String> mylist = new ArrayList<>();
mylist.add("hello");
mylist.add("world");
mylist.add("haha");
mylist.add("hi");
mylist.remove(1);
我们可以很清楚的知道,是对list进行的操作,而且使用list进行调用会很方便,编译器会显示出所有可以被调用的方法。
为了实现类似这样的功能,我们需要对双链表的结构体定义进行改造,给其添加相关的函数指针成员,当创建双链表时,对这些函数指针进行初始化,指向之前调用的相应函数,这样当我们使用双链表时,就可以方便的进行调用了。函数指针相关知识可以参考 C语言 指针的细枝末节相关部分。
对双链表结构体添加相关函数指针成员,如下所示:
注意:在函数指针的形参为链表结构体时,需要使用struct DoubleLinkList,而不能使用DLlist,因为这时候DLlist还未定义。
typedef struct DoubleLinkList
{
DLNode* head; // 链表头
DLNode* back; // 链表尾
size_t size; //链表包含的元素的个数 typedef unsigned int size_t;
// pointers
void (*init)(struct DoubleLinkList* pList);
int (*addToHead)(struct DoubleLinkList* pList, _TYPE value);
int (*addToBack)(struct DoubleLinkList* pList, _TYPE value);
int (*addToHeadWithArrayValues)(struct DoubleLinkList* pList, _TYPE array[], int length);
int (*addToBackWithArrayValues)(struct DoubleLinkList* pList, _TYPE array[], int length);
int (*insertAfter)(struct DoubleLinkList* pList, _TYPE curValue, _TYPE newValue);
int (*insertAfter2)(struct DoubleLinkList* pList, _TYPE curValue, _TYPE newValue);
int (*insertBefore)(struct DoubleLinkList* pList, _TYPE curValue, _TYPE newValue);
int (*insertBefore2)(struct DoubleLinkList* pList, _TYPE curValue, _TYPE newValue);
DLNode* (*removeFirst)(struct DoubleLinkList* pList);
DLNode* (*removeLast)(struct DoubleLinkList* pList);
void(*showAll)(struct DoubleLinkList* pList);
void(*showAllWithRecursion)(DLNode* head);
void(*showAllReverse)(struct DoubleLinkList* pList);
void(*showAllReverseWithRecursion)(DLNode* back);
int(*deleteNode)(struct DoubleLinkList* pList, _TYPE value);
int(*deleteNode2)(struct DoubleLinkList* pList, _TYPE value);
int(*deleteRange)(struct DoubleLinkList* pList, _TYPE fromValue, int count);
int(*checkNull)(void* p);
int(*modify)(struct DoubleLinkList* pList, _TYPE oldValue, _TYPE newValue);
int(*freeAll)(struct DoubleLinkList* pList);
int(*freeFrom)(struct DoubleLinkList* pList, _TYPE value);
DLNode* (*findByValue)(struct DoubleLinkList* pList, _TYPE value);
int(*addListToBack)(struct DoubleLinkList* pList, struct DoubleLinkList* addingList);
int(*getDepth)(struct DoubleLinkList* pList, _TYPE value);
int(*isEmpty)(struct DoubleLinkList* pList);
void(*sort)(struct DoubleLinkList* pList, int asc);
}DLlist; // 双链表
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
在创建链表的函数,需要对相关的函数指针成员进行初始化,赋值对应的函数地址。如下代码:
// 给函数指针赋值
void initRefs(DLlist* pList){
pList->init = init;
pList->addToHead = addToHead;
pList->addToBack = addToBack;
pList->addToHeadWithArrayValues = addToHeadWithArrayValues;
pList->addToBackWithArrayValues = addToBackWithArrayValues;
pList->insertAfter = insertAfter;
pList->insertAfter2 = insertAfter2;
pList->insertBefore = insertBefore;
pList->insertBefore2 = insertBefore2;
pList->removeFirst = removeFirst;
pList->removeLast = removeLast;
pList->showAll = showAll;
pList->showAllWithRecursion = showAllWithRecursion;
pList->showAllReverse = showAllReverse;
pList->showAllReverseWithRecursion = showAllReverseWithRecursion;
pList->deleteNode = deleteNode;
pList->deleteNode2 = deleteNode2;
pList->deleteRange = deleteRange;
pList->checkNull = checkNull;
pList->modify = modify;
pList->freeAll = freeAll;
pList->freeFrom = freeFrom;
pList->findByValue = findByValue;
pList->addListToBack = addListToBack;
pList->getDepth = getDepth;
pList->isEmpty = isEmpty;
pList->sort = sort;
}
//用于给通过DoubleLinkList创建的新链表进行初始化
void init(DLlist* pList)
{
pList->head = pList->back = NULL;
pList->size = 0;
initRefs(pList); // 初始化
}
//快速创建一个双链表
DLlist* _createList()
{
DLlist* pList = (DLlist*)malloc(sizeof(DLlist));
init(pList);
return pList;
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
这样就完成了改造,其他代码不需要进行修改。下面我们进行一下测试。
#include"doublelinklist2.h"
void main(){
DLlist* pList = _createList();
pList->addToHead(pList, 1); // 插入数据到头
pList->addToHead(pList, 2);
pList->addToHead(pList, 3);
pList->addToHead(pList, 4);
pList->addToHead(pList, 5);
pList->addToBack(pList, 11); // 插入数据到尾
pList->addToBack(pList, 22);
pList->addToBack(pList, 33);
pList->addToBack(pList, 44);
pList->addToBack(pList, 55);
pList->showAll(pList); // 正向显示所有
pList->showAllReverse(pList); // 反向显示所有
pList->modify(pList, 11, 66); // 将11修改为66
pList->showAll(pList); // 正向显示所有
printf("size=%d\n", pList->size);
pList->deleteNode(pList, 33);
pList->showAll(pList); // 正向显示所有
printf("size=%d\n", pList->size); // 双链表的大小
system("pause");
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
现在,我们就可以轻松的通过链表来进行相关函数的调用,感覚还是很不错的。
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。