【数据结构】双向链表

1.LinkedList.h

#ifndef LINKED_LIST_H
#define LINKED_LIST_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//首先定义一个链表节点结构体
typedef struct LINKNODE{
	void* data;//表示节点中存储任意类型的数据
	struct LINKNODE* pre;//注意这种定义的方式啊
	struct LINKNODE* next;//注意这种定义的方式啊,前面是struct 后面是LINKNODE是最开始定义的结构体名称,LinkNode是另外定义的名称
}LinkNode;

//再定义链表结构体
typedef struct {
        //注意,下面的LinkNode可以不是指针就是LinkNode head,改成不是指针后可能还方便点,
        //如果head不是指针至少在初始化list的时候不用新开辟一片内存,同样也是作为头节点, 
        //而不是数据存储的第一个点,读者可以自行尝试把下面的指针改为不是指针
	LinkNode* head;//给链表定义一个头
	int size;//记录当前list存储的元素数量
}LinkList;

//打印函数指针
typedef void(*PRINTLINKNODE)(void*);

//初始化链表
LinkList* initLinkList();
//指定位置插入
void insertLinkList(LinkList* list, int pos, void* data);
//删除指定位置的值
void removeByPosLinkList(LinkList* list, int pos);
//获得链表的长度
int getLinkListSize(LinkList* list);
//查找
int findPosByData(LinkList* list, void* data);
//返回第一个结点
void* frontLinkList(LinkList* list);
//返回最后一个结点
void* backLinkList(LinkList* list);
//打印链表结点
void printLinkList(LinkList* list, PRINTLINKNODE print);
//释放链表内存
void freeSpaceLinkList(LinkList* list);
//从后面加入
void pushBack(LinkList* list, void* data);
//从后面弹出
void popBack(LinkList* list);
//从前面加入
void pushFront(LinkList* list, void* data);
//从前面弹出
void popFront(LinkList* list);
#endif // !LINKED_LIST_H

2.LinkedList.c

#include "LinkedList.h"
//初始化链表
LinkList* initLinkList() {
	LinkList* linkList = (LinkList*)malloc(sizeof(LinkList));
	//新建个数据节点,让list指向这个节点,这个节点作为list的头节点,不存储数据,只用next记录下真实的存储的第一个位置
	//这样做的目的是为了便于遍历
	linkList->head= (LinkNode*)malloc(sizeof(LinkNode));
	linkList->head->data = NULL;
	linkList->head->pre = NULL;
	linkList->head->next = NULL;
	linkList->size = 0;
	return linkList;
}
//指定位置插入
void insertLinkList(LinkList* list, int pos, void* data) {
	if (list == NULL) {
		return;
	}
	if (data == NULL) {
		return;
	}
	if (pos < 0 || pos >= list->size) {
		pos = list->size;
	}
	//创建新的结点
	LinkNode* newNode = (LinkNode*)malloc(sizeof(LinkNode));
	newNode->data = data;
	newNode->next = NULL;
	//辅助指针
	LinkNode* pCurrent = list->head;
	for (int i = 0; i < pos; i++) {
		pCurrent = pCurrent->next;
	}

	//将新节点加入链表
	newNode->pre = pCurrent;
	newNode->next = pCurrent->next;
	pCurrent->next = newNode;

	list->size++;
}
//删除指定位置的值
void removeByPosLinkList(LinkList* list, int pos) {
	if (list == NULL) {
		return;
	}
	if (pos < 0 || pos >= list->size) {
		return;
	}
	//辅助指针
	LinkNode* pCurrent = list->head;
	for (int i = 0; i < pos; i++) {
		pCurrent = pCurrent->next;
	}
	//缓存删除的节点
	LinkNode* pDel = pCurrent->next;
	pCurrent->next = pDel->next;
	//释放删除节点的内存
	free(pDel);
	list->size--;
}
//获得链表的长度
int getLinkListSize(LinkList* list) {
	return list->size;
}
//查找
int findPosByData(LinkList* list, void* data) {
	if (list == NULL) return -10086;
	if (data == NULL) return -10086;
	LinkNode* firstNode = list->head->next;
	int pos = 0;
	while (firstNode!= NULL) {
		if (firstNode->data == data) {
			return pos;
		}
		firstNode = firstNode->next;
		pos++;
	}
	return -10086;//表示没有找到
}
//返回第一个结点
void* frontLinkList(LinkList* list) {
	if (list == NULL) return NULL;
	return list->head->next->data;
}
//返回最后一个结点
void* backLinkList(LinkList* list) {
	if (list == NULL) return NULL;
	LinkNode* pCurrent = list->head;
	for (int i = 0; i < list->size; i++) {
		pCurrent = pCurrent->next;
	}
	return pCurrent->data;
}
//打印链表结点
void printLinkList(LinkList* list, PRINTLINKNODE print) {
	if (list == NULL) return;
	//辅助指针变量
	LinkNode* pCurrent = list->head->next;
	while (pCurrent != NULL) {
		print(pCurrent->data);
		pCurrent = pCurrent->next;
	}
}
//释放链表内存
void freeSpaceLinkList(LinkList* list){
	if (list == NULL) {
		return;
	}
	//辅助指针变量
	LinkNode* pCurrent = list->head;
	while (pCurrent != NULL) {
		//缓存下一个结点
		LinkNode* pNext = pCurrent->next;
		free(pCurrent);
		pCurrent = pNext;
	}

	//释放链表内存
	list->size = 0;
	free(list);
}
//从后面加入
void pushBack(LinkList* list, void* data) {
	if (list == NULL) {
		return;
	}
	if (data == NULL) {
		return;
	}
	insertLinkList(list, list->size, data);
}
//从后面弹出
void popBack(LinkList* list) {
	if (list == NULL) return;
	//获得最后一个指针
	LinkNode* pCurrent = list->head;
	while (pCurrent->next != NULL) {
		pCurrent = pCurrent->next;
	}
	//把最后一个的前一个的指针的next指向NULL
	pCurrent->pre->next = NULL;
	//释放掉最后一个指针
	free(pCurrent);
	list->size--;
}
//从前面加入
void pushFront(LinkList* list, void* data) {
	if (list == NULL) {
		return;
	}
	if (data == NULL) {
		return;
	}
	insertLinkList(list, 0, data);
}
//从前面弹出
void popFront(LinkList* list) {
	if (list == NULL) return;
	if (list->size == 0) return;
	//先保存第一个阶段的的指针
	LinkNode* firstNode = list->head->next;
	//再将头指针的下一个指针指向第一个的下一个
	list->head->next = firstNode->next;
	//再将第二个的pre设置为头指针
	firstNode->next->pre = list->head;
	//最后释放第一个指针
	free(firstNode);
	//size减小一个
	list->size--;
}

3.测试

#include "LinkedList.h"
//自定义数据类型
typedef struct PERSON {
	char name[64];
	int age;
	int score;
}Person;
//打印函数
void MyPrint(void* data) {
	Person* p = (Person*)data;
	printf("Name:%s Age:%d Score:%d\n", p->name, p->age, p->score);
}
void test01() {
	LinkList* list = initLinkList();
	Person p1 = { "xiaodong",20,56 };
	Person p2 = { "xiaoxiao",30,78 };
	Person p3 = { "dogndong",20,22 };
	Person p4 = { "kankan",46,13 };
	Person p5 = { "hehe",62,34 };
	Person p6 = { "lishang",67,55 };
	printf("size:%d\n", getLinkListSize(list));
	pushBack(list, &p1);
	printf("size:%d\n", getLinkListSize(list));
	pushBack(list, &p2);
	pushBack(list, &p3);
	pushBack(list, &p4);
	pushBack(list, &p5);
	pushFront(list, &p6);
	printLinkList(list, MyPrint);
	printf("size:%d\n", getLinkListSize(list));
	printf("-----------从后面弹出----------\n");
	popBack(list);
	printLinkList(list, MyPrint);
	printf("size:%d\n", getLinkListSize(list));
	printf("-----------从前面弹出----------\n");
	popFront(list);
	printLinkList(list, MyPrint);
	printf("size:%d\n", getLinkListSize(list));
	printf("-----------返回第一个节点数据----------\n");
	MyPrint(frontLinkList(list));
	printf("-----------返回最后一个节点数据----------\n");
	MyPrint(backLinkList(list));

}
int main(void) {
	test01();
	system("pause");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值