浅析双向链表结构

双向链表是最常用的数据类型了,这里就不过多解释,直接上图与代码。

一共有4个文件,代码如下:

1、list.h

#ifndef LIST_H_
#define LIST_H_

typedef void * List;                                // 链表对象
typedef int (*pForEach)(void *);                    // 链表遍历回调函数指针
#define list_create(type) (list_init(sizeof(type))) // 链表初始化宏替换

// 链表初始化
List list_init(int);

// 链表头插
int list_push_front(List,void *);

// 链表尾插
int list_push_back(List,void *);

// 链表删除
int list_erase(List,int);

// 链表大小
int list_size(List);

// 链表某节点数据
void *list_get(List,int);

// 链表遍历
void list_for_each(List,pForEach);

// 链表清空
int list_clear(List);

// 链表销毁
void list_destroy(List);

#endif

2、list.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"

// 链表节点
typedef struct _stu_node
{
	void *data;							// 本节点数据
	struct _stu_node *prev;				// 上节点指针
	struct _stu_node *next;				// 下节点指针
}stu_node;

// 链表
typedef struct _stu_list
{
	stu_node head;						// 头节点
	int size;							// 链表元素大小
	int dataSize;						// 节点数据所占内存大小
}stu_list;

// 链表初始化
List list_init(int dataSize)
{
	stu_list *pList = malloc(sizeof(stu_list));
	if(pList == NULL){return NULL;}
	
	pList->head.data = NULL;
	pList->head.prev = &pList->head;
	pList->head.next = &pList->head;
	pList->size = 0;
	pList->dataSize = dataSize;

	return pList;	
}

// 链表插入
static int list_push(stu_list *me,void *data,stu_node *node1,stu_node *node2)
{
	if(me == NULL || data == NULL){return -1;}

	// 新节点创建
	stu_node *newNode = malloc(sizeof(stu_node));
	if(newNode == NULL){return -1;}
	newNode->data = malloc(me->dataSize);	// 这里新复制对象而非存储原对象指针
	if(newNode->data == NULL){return -1;}
	memcpy(newNode->data,data,me->dataSize);
	newNode->prev = NULL;
	newNode->next = NULL;

	// 新节点插入
	newNode->prev = node1;
	newNode->next = node2;
	newNode->prev->next = newNode;
	newNode->next->prev = newNode;

	// 链表大小
	me->size++;

	return 0;
}

// 链表头插
int list_push_front(List me,void *data)
{
	if(me == NULL || data == NULL){return -1;}
	stu_list *pList = me;

	return list_push(pList,data,&pList->head,pList->head.next);
}

// 链表尾插
int list_push_back(List me,void *data)
{
	if(me == NULL || data == NULL){return -1;}
	stu_list *pList = me;

	return list_push(pList,data,pList->head.prev,&pList->head);
}

// 链表删除
int list_erase(List me,int pos)
{
	if(me == NULL){return -1;}
	stu_list *pList = me;
	if(pos >= pList->size){return -1;}
	// 移动到指定位置
	stu_node *curNode = &pList->head;
	int i;
	for(i=0;i<=pos;i++){curNode = curNode->next;}
	// 开始删除
	curNode->prev->next = curNode->next;
	curNode->next->prev = curNode->prev;
	free(curNode->data);
	free(curNode);
	// 链表大小
	pList->size--;

	return 0;
}

// 链表遍历
void list_for_each(List me,pForEach pFun)
{
	if(me == NULL){return;}
	stu_list *pList = me;
	if(pList->size == 0){return;}
	stu_node *curNode = pList->head.next;
	int i;
	for(i=0;i<=pList->size;i++)
	{
		if(pFun(curNode->data) == -1){break;}
		curNode = curNode->next;
	}
	
}

// 链表某节点数据
void *list_get(List me,int pos)
{
	if(me == NULL){return NULL;}
	stu_list *pList = me;
	if(pos >= pList->size){return NULL;}
	stu_node *curNode = &pList->head;
	int i;
	for(i=0;i<=pos;i++){curNode = curNode->next;}
	
	return curNode->data;	
}

// 链表大小
int list_size(List me)
{
	if(me == NULL){return -1;}
	stu_list *pList = me;

	return pList->size;
}

// 链表清空
int list_clear(List me)
{
	if(me == NULL){return -1;}
	stu_list *pList = me;
	if(pList->size == 0){return 0;}
	stu_node *curNode = pList->head.next;
	stu_node *tmpNode = NULL;
	int i;
	for(i=0;i<pList->size;i++)
	{
		tmpNode = curNode->next;
		free(curNode->data);
		free(curNode);
		curNode = tmpNode;
	}
	// 还原链表状态	
	pList->head.prev = &pList->head;
	pList->head.next = &pList->head;
	pList->size = 0;

	return 0;
}

// 链表销毁
void list_destroy(List me)
{
	if(me == NULL){return;}
	list_clear(me);
	stu_list *pList = me;
	free(pList);
}

3、main.c

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

// 测试数据
typedef struct _stu_person
{
	int id;
	char name[32];
	int age;
}stu_person;

// 链表遍历回调函数
int myPrint(void *data)
{
	if(data == NULL){return -1;}
	stu_person *p = data;
	printf("%d %s %d\n",p->id,p->name,p->age);

	return 0;
}

int main()
{
	// 变量定义
	int i;
	stu_person person;

	// 链表创建
	List list = list_create(stu_person);	// 宏替换后变为 List list = list_init(sizeof(stu_person));
	if(list == NULL){exit(1);}

	// 数据插入
	for(i=0;i<5;i++)
	{
		person.id = i;
		sprintf(person.name,"stu%d",i);
		person.age = random() % 100;
		list_push_back(list,&person);		// 尾插
		//list_push_front(list,&person);		// 头插
	}

	// 数据遍历
	for(i=0;i<list_size(list);i++)
	{
		stu_person *p = list_get(list,i);
		printf("%d %s %d\n",p->id,p->name,p->age);
	}

	// 删除数据
	printf("===删除第3条数据===\n");
	list_erase(list,2);

	// 数据遍历
	list_for_each(list,myPrint);
	
	// 链表清空
	list_clear(list);
	
	// 链表销毁
	list_destroy(list);

	exit(0);
}

4、makefile

CC = gcc
OBJ = main
OBJS = main.o list.o

$(OBJ):$(OBJS)
	$(CC) $^ -o $@
%.o:%.c
	$(CC) -c -Wall $^ -o $@

.PHONY:clean
clean:
	rm -rf *.o $(OBJ)

运行结果如下:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值