您的位置:首页 > 理论基础 > 数据结构算法

数据结构-单向链表两个版本

2017-09-14 14:04 417 查看
链表一

思路:用一个结构体做链表头,里面统计链表的大小,获取这个链表头就是获取整个链表



链表是一种常用的数据结构,它通过指针将一些列数据结点,连接成一个数据链。相对于数组,链表具有更好的动态性(非顺序存储)

链表的优点:

1 不需要一块连续的存储区域
2 删除和插入某个元素效率高
缺点:随机访问元素效率低

linklist.h

#pragma once
#include<stdlib.h>
//链表节点
typedef struct LINKNODE
{
void* data;//数据域
struct LINKNODE* next;//指针域
}LinkNode;

//链表
typedef struct LINKLIST
{
LinkNode header;//头节点
int size;//链表大小

}LinkList;

//比较函数指针
typedef int(*COMPARE)(void* data1, void* data2);
//打印函数指针
typedef void(*PRINT)(void* data);

//初始化
void* Init_ListLink();
//指定位置插入
void Inset_ListLink(void* list,int pos,void* data);
//头部插入操作
void PushFront_LinkList(void* list, void* data);
//尾部插入操作
void PushBack_LinkList(void* list, void* data);
//指定位置删除
void RemoveByPos_LinkList(void* list, int pos);
//头部删除操作
void PopFront_LinkList(void* list);
//尾部删除操作
void PopBack_LinkList(void* list);
//值删除
void RemoveByVal_LinkList(void* list, void* data, COMPARE compare);
//获得指定位置元素
void* Get_LinkList(void* list, int pos);
//链表大小
int Size_LinkList(void* list);
//遍历链表
void Print_LinkList(void* list, PRINT print);
//销毁链表
void Destroy_LinkList(void* list);


linklist.c

#include "linklist.h"

//初始化
void* Init_ListLink()
{
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
list->size = 0;
list->header.next = NULL;
return list;
}

//指定位置插入
void Inset_ListLink(void* list, int pos, void* data)
{
if (NULL == list)
{
return;
}
if (NULL == data)
{
return;
}
LinkList* linklist = (LinkList*)list;
//判断指定位置是否越界,越界默认尾部插入
if (pos<0 || pos>linklist->size)
{
pos = linklist->size;
}

//查找位置
LinkNode* pCurrent = &(linklist->header);
int i = 0;
for (; i < pos; ++i)
{
pCurrent = pCurrent->next;//跳到链表的下一个节点,直到指定位置
}

//创建新节点
LinkNode* NewNode = (LinkList*)malloc(sizeof(LinkNode));
NewNode->data = data;
NewNode->next = NULL;

//新节点入链表
NewNode->next = pCurrent->next;
pCurrent->next = NewNode;

++linklist->size;
}

//头部插入操作
void PushFront_LinkList(void* list, void* data)
{
if (NULL == list)
{
return;
}
if (NULL == data)
{
return;
}

Inset_ListLink(list, 0, data);

}
//尾部插入操作
void PushBack_LinkList(void* list, void* data)
{
if (NULL == list)
{
return;
}
if (NULL == data)
{
return;
}
LinkList* linklist = (LinkList*)list;
Inset_ListLink(linklist, linklist->size, data);

}

//指定位置删除
void RemoveByPos_LinkList(void* list, int pos)
{
if (NULL == list)
{
return;
}

LinkList*  linklist = (LinkList*)list;
if (po
4000
s < 0 || pos >= linklist->size)//第一个链表从0开始算
{
return;
}
//判断链表是否为空
if (linklist->size == 0){
return;
}

//查找删除节点的前一个节点
LinkNode* pCurrent = &(linklist->header);
int i = 0;
for (; i < pos; i++)
{
pCurrent = pCurrent->next;
}
//缓存待删除节点
LinkNode* pDel = pCurrent->next;
//重新连接被删除节点前驱和后继节点
pCurrent->next = pDel->next;
//释放被删除节点内存
free(pDel);
--linklist->size;

}

//头部删除操作
void PopFront_LinkList(void* list)
{
if (NULL == list)
{
return;
}
LinkList*  linklist = (LinkList*)list;
if (linklist->size == 0)
{
return;
}
RemoveByPos_LinkList(linklist, 0);

}

//尾部删除操作
void PopBack_LinkList(void* list)
{
if (NULL == list)
{
return;
}
LinkList*  linklist = (LinkList*)list;
if (linklist->size == 0)
{
return;
}
RemoveByPos_LinkList(linklist,linklist->size-1);

}

//值删除
void RemoveByVal_LinkList(void* list, void* data, COMPARE compare)
{
if (NULL == list)
{
return;
}
if (NULL == data )
{
return;
}
LinkList*  linklist = (LinkList*)list;
if (linklist->size == 0)
{
return;
}

LinkNode* pCurrent = linklist->header.next;
int i = 0;
for (; i < linklist->size;++i)
{
if (compare(pCurrent->data, data))
{
RemoveByPos_LinkList(list, i);
return;
}
pCurrent = pCurrent->next;
}

}
//获得指定位置元素,从0开始
void* Get_LinkList(void* list, int pos)
{
if (NULL == list)
{
return;
}
LinkList*  linklist = (LinkList*)list;
if (linklist->size == 0)
{
return;
}
//遍历到指定位置的前一个节点
LinkNode* pCurrent = &(linklist->header);
int i = 0;
for (; i < pos; ++i)
{
pCurrent = pCurrent->next;
}
return pCurrent->next->data;//返回指定位置

}
//链表大小
int Size_LinkList(void* list)
{
if (NULL == list)
{
return;
}
LinkList*  linklist = (LinkList*)list;
return linklist->size;

}

//销毁链表
void Destroy_LinkList(void* list)
{
if (NULL == list)
{
return;
}
LinkList*  linklist = (LinkList*)list;
if (linklist->size == 0)
{
return;
}
LinkNode* pCurrent = linklist->header.next;
while (pCurrent != NULL)
{
LinkNode* pnext = pCurrent->next;
free(pCurrent);
pCurrent = pnext;
}
free(linklist);
printf("链表内存释放\n");

}

//遍历链表
void Print_LinkList(void* list, PRINT print)
{
if (NULL == list)
{
return;
}
//拿到链表头
LinkList* linklist = (LinkList*)list;
LinkNode* pCurrent = linklist->header.next;//指向第一个链表
while (pCurrent != NULL)
{
print(pCurrent->data);
pCurrent = pCurrent->next;
}
}


main.c

#include "linklist.h"
#include<string.h>
typedef struct PERSON
{
char name[64];
int age;
}person;

void Print(void* data)
{
person* p = (person*)data;
printf("name:%s,age:%d\n",p->name,p->age);
}

int conpare(void* data1, void* data2)
{
person* p1 = (person*)data1;
person* p2 = (person*)data2;
return strcmp(p1->name, p2->name) == 0 && p1->age == p2->age;
}

int main()
{
person p1 = { "aaaa", 1 };
person p2 = { "bbbb", 2 };
person p3 = { "cccc", 3 };
person p4 = { "dddd", 4 };
person p5 = { "eeee", 5 };
person p6 = { "ffff", 6 };
LinkList* list = Init_ListLink();
//头部插入操作
PushFront_LinkList(list, &p3);
PushFront_LinkList(list, &p2);
PushFront_LinkList(list, &p1);
//指定位置插入
Inset_ListLink(list, 3, &p4);
Inset_ListLink(list, 4, &p5);
Inset_ListLink(list, 5, &p6);
//打印
Print_LinkList(list, Print);
printf("----------------------\n");
//指定位置删除
RemoveByPos_LinkList(list, 0);
RemoveByPos_LinkList(list, 1);
Print_LinkList(list, Print);
printf("----------------------\n");
//头部删除操作
PopFront_LinkList(list);
PopFront_LinkList(list);
Print_LinkList(list, Print);
printf("----------------------\n");

//值删除
RemoveByVal_LinkList(list, &p5, conpare);
Print_LinkList(list, Print);
printf("----------------------\n");
//获得指定位置元素
person* p= Get_LinkList(list, 0);
printf("name:%s,age:%d\n", p->name, p->age);
Destroy_LinkList(list);
getchar();
}


打印结果:



链表二

版本二比版本一好一些,版本一要每次都要在堆上开辟节点空间,而版本二不用,版本二是直接让节点的前四个字节保存下一个节点的地址,形成链表



LinkList.h

#pragma once
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
//链表小节点
typedef struct LINKNODE
{
struct LINKNODE* next;

}LinkNode;

//链表头节点
typedef struct LINKLIST
{
LinkNode header;//等价于struct LINKNODE* next;用结构体变量的话是为了更好的扩展性,如果是双向链表直接在结果体内加一个指针域
int size;

}LinkList;

typedef void* LLink;
//比较函数指针
typedef int(*DataCompare)(LinkNode* data1, LinkNode* data2);
//打印函数指针
typedef void(*DatePrint)(LinkNode* data);

//初始化链表头
LLink Init_LinkList();
//指定位置插入
void Inset_ListLink(LLink* list, int pos, LinkNode*data);
//头部插入操作
void PushFront_LinkList(LLink* list, LinkNode*data);
//尾部插入操作
void PushBack_LinkList(LLink* list, LinkNode*data);
//指定位置删除
void RemoveByPos_LinkList(LLink list, int pos);
//头部位置删除
void PopFront_LinkList(LLink list);
//尾部位置删除
void PopBack_LinkList(LLink list);
//根据值删除
void RemoveByVal_LinkList(LLink list, LinkNode* data, DataCompare compare);
//链表大小
int Size_LinkList(LLink list);
//打印链表
void Print_LinkList(LLink list, DatePrint Print);
//销毁链表
void Destroy_LinkList(LLink list);
LinkList.c

#include"LinkList.h"
//初始化链表头
LLink Init_LinkList()
{
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
if (NULL == list)
{
printf("list malloc error\n");
return NULL;
}
list->header.next = NULL;
list->size = 0;
return list;
}

//指定位置插入
void Inset_ListLink(LLink* list, int pos, LinkNode*data)
{
if (NULL == list)
{
printf("Inset_ListLink list is NULL\n");
return;
}
if (NULL == data)
{
printf("Inset_ListLink data is NULL\n");
return;
}
LinkList* link_list = (LinkList*)list;
if (pos<0 || pos>link_list->size)//如果越界就尾部插入
{
pos = link_list->size;
}

//判断数据是否重复插入
#if 0
LinkNode* PRepeat = link_list->header.next;
while (PRepeat != NULL)
{
if (PRepeat == data)
{
printf("数据重复插入\n");
return;
}
PRepeat = PRepeat->next;
}
#endif
//辅助指针变量
LinkNode* Pcurrent = &(link_list->header);
int i = 0;
for (; i < pos; ++i)
{
Pcurrent = Pcurrent->next;
}
//新节点入链表
data->next = Pcurrent->next;
Pcurrent->next = data;
++link_list->size;
}

//头部插入操作
void PushFront_LinkList(LLink* list, LinkNode*data)
{
if (NULL == list)
{
printf("PushFront_LinkList list is NULL\n");
return;
}
if (NULL == data)
{
printf("PushFront_LinkList data is NULL\n");
return;
}

Inset_ListLink(list, 0, data);

}

//尾部插入操作
void PushBack_LinkList(LLink* list, LinkNode*data)
{
if (NULL == list)
{
printf("PushBack_LinkList list is NULL\n");
return;
}
if (NULL == data)
{
printf("PushBack_LinkList data is NULL\n");
return;
}
LinkList* link_list = (LinkList*)list;
Inset_ListLink(link_list, link_list->size, data);
}

//指定位置删除
void RemoveByPos_LinkList(LLink list, int pos)
{
if (NULL == list)
{
printf("RemoveByPos_LinkList list is NULL\n");
return;
}
LinkList* link_list = (LinkList*)list;
if (pos < 0 || pos >= link_list->size)
{
printf("RemoveByPos_LinkList Transboundary\n");
return;
}
//辅助指针变量,找到删除节点的前一个节点,节点从0开始算
LinkNode* Pcurrent = &(link_list->header);
int i = 0;
for (; i < pos; ++i)
{
Pcurrent = Pcurrent->next;
}
//缓存要删除的节点
LinkNode* PDel = Pcurrent->next;
Pcurrent->next = PDel->next;
--link_list->size;

}

//头部位置删除
void PopFront_LinkList(LLink list)
{
if (NULL == list)
{
printf("PopFront_LinkList list is NULL\n");
return;
}
RemoveByPos_LinkList(list, 0);

}
//尾部位置删除
void PopBack_LinkList(LLink list)
{
if (NULL == list)
{
printf("PopBack_LinkList list is NULL\n");
return;
}
LinkList* link_list = (LinkList*)list;
RemoveByPos_LinkList(link_list, link_list->size - 1);

}
//根据值删除
void RemoveByVal_LinkList(LLink list, LinkNode* data, DataCompare compare)
{
if (NULL == list)
{
printf("RemoveByVal_LinkList list is NULL\n");
return;
}
if (NULL == data)
{
printf("RemoveByVal_LinkList data is NULL\n");
return;
}
LinkList* link_list = (LinkList*)list;
LinkNode* PDel = &(link_list->header);
LinkNode* Pcurrent = PDel->next;
while (Pcurrent != NULL)
{
if (compare(Pcurrent, data))
{
PDel->next = Pcurrent->next;
--link_list->size;
break;
}
PDel = Pcurrent;
Pcurrent = Pcurrent->next;
}

}
//链表大小
int Size_LinkList(LLink list)
{
if (NULL == list)
{
printf("Size_LinkList list is NULL\n");
return;
}
LinkList* link_list = (LinkList*)list;
return link_list->size;
}

//打印链表
void Print_LinkList(LLink list, DatePrint Print)
{
if (NULL == list)
{
printf("Print_LinkList list is NULL\n");
return;
}
LinkList* link_list = (LinkList*)list;
LinkNode* Pcurrent = link_list->header.next;
while (Pcurrent != NULL)
{
Print(Pcurrent);
Pcurrent = Pcurrent->next;
}

}

//销毁链表
void Destroy_LinkList(LLink list)
{
if (NULL == list)
{
printf(" Destroy_LinkList list is NULL\n");
return;
}
free(list);
}

main.c

#include"LinkList.h"
#include <stdio.h>
typedef struct PERSON
{
LinkNode header;//一定要有这个节点,这个变量保持下一个数据的地址,如果没有的话数据会错乱
char name[64];
int age;
}person;

//比较函数指针
int Compare(LinkNode* data1, LinkNode* data2)
{
person* p1 = (person*)data1;
person* p2 = (person*)data2;
return strcmp(p1->name, p2->name)==0 && p1->age == p2->age;
}
//打印函数指针
void Print_list(LinkNode* data)
{
person* p1 = (person*)data;
printf("Name:%s,Age:%d\n", p1->name, p1->age);

}

int main()
{
person p1 = { NULL, "aaa", 10 };
person p2 = { NULL, "bbb", 20 };
person p3 = { NULL, "ccc", 30 };
person p4 = { NULL, "ddd", 40 };
person p5 = { NULL, "eee", 50 };

LLink* list = Init_LinkList();
//指定位置删除
Inset_ListLink(list, 0, (LinkNode*)&p1);
Inset_ListLink(list, 1, (LinkNode*)&p2);
Inset_ListLink(list, 2, (LinkNode*)&p3);
Inset_ListLink(list, 3, (LinkNode*)&p4);
Inset_ListLink(list, 4, (LinkNode*)&p5);
Print_LinkList(list, Print_list);
printf("----------------------------------\n");
//指定位置删除
RemoveByPos_LinkList( list,2);
RemoveByPos_LinkList(list, 2);
//头部位置删除
PopFront_LinkList(list);
//根据值删除
RemoveByVal_LinkList(list, (LinkNode*)&p5, Compare);
Print_LinkList(list, Print_list);
//链表大小
int size=Size_LinkList(list);
printf("Size=%d\n",size);
Destroy_LinkList(list);
getchar();
return 0;
}


打印结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐