数据结构-无头链表 (结构体再封装)

        无头链表有两种,一种是二级指针形式,还有一种就是结构体再封装形式。结构体再封装通过抽象出链表的共有属性 即链表表头,表尾,和链表长度 来建立链表。

所以我们需要建立两个结构体。

其中一个结构体是节点结构体

typedef struct _Node{
	int data;
	struct _Node *next;
}Node;

另一个则是通过链表共有属性抽象出来的结构体 

typedef struct _List{
	Node* frontNode;        //表头结点指针 代表表头节点
	Node* tailNode;			//表尾节点指针 代表表尾节点
	int size;
}List;

       通过初始化链表共有属性抽象出来的结构体 ,我们就可以得到一个暂无节点的链表表头指针和表尾指针,然后通过创建节点不断的往链表中插入数据就可以得到链表。不过需要注意的是:在增删改查的过程中,表头节点指针必须永远指向表头节点,表尾节点的指针也必须永远指向表尾。

        这种方法的和采用二级指针的无头链表相比来说更容易理解(不过我觉得二级指针的看着亲切些哈哈)

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

typedef struct _Node{
	int data;
	struct _Node *next;
}Node;

typedef struct _List{
	Node* frontNode;        //表头结点指针 代表表头节点
	Node* tailNode;			//表尾节点指针 代表表尾节点
	int size;
}List;
//创建一个链表
List* createList(){
	List* list = (List*)malloc(sizeof(List));
	list->frontNode = NULL;
	list->tailNode = NULL;
	list->size = 0;
	return list;
}
Node* createNewNode(int data){                        //新建节点
	Node* newNode = (Node*)malloc(sizeof(Node));
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}
void insertNodeByHead(List* list, int data){          // 头插法
	Node* newNode = createNewNode(data);
	if (list->size == 0){
		list->frontNode = newNode;
		list->tailNode = newNode;
	}
	else{
		newNode->next = list->frontNode;     //新节点指向头节点
		list->frontNode = newNode;			//把新节点作为头节点
	}
	list->size++;
}
void insertNodeByTail(List* list, int data){			   //尾插
	Node* newNode = createNewNode(data);
	if (list->size == 0){
		list->frontNode = newNode;
		list->tailNode = newNode;
	}
	else{
		list->tailNode->next = newNode;
		list->tailNode = newNode;
	}
	list->size++;
}
void printList(List *list){								 //打印
	Node *pMoveNode = list->frontNode;	
	while (pMoveNode != NULL){
		printf("%d ", pMoveNode->data);
		pMoveNode = pMoveNode->next;
	}
}
void deleteNodeByHead(List* list){						  //头删
	if (list->frontNode == NULL){	
		printf("链表为空,无法删除!\n");
	}
	else{
		Node* deleteNode = list->frontNode;
		list->frontNode = list->frontNode->next;
		free(deleteNode);
		deleteNode = NULL;
		list->size--;
	}
}
void deleteNodeByTail(List* list){              //尾删
	int i = 0;
	if (list->tailNode == NULL){
		printf("链表为空,无法删除!\n");
	}
	else{
		Node* pMoveNode = list->frontNode;
		while (pMoveNode->next->next != NULL){
			pMoveNode = pMoveNode->next;
		}
		free(list->tailNode);
		list->tailNode = pMoveNode;
		list->tailNode->next = NULL;
		list->size--;
	}
}
int main(){
	List* list = createList();
	insertNodeByHead(list, 10);
	insertNodeByHead(list, 20);
	insertNodeByHead(list, 30);
	insertNodeByTail(list, -10);
	deleteNodeByHead(list);
	deleteNodeByTail(list);
	printList(list);
	return 0;
}

记录一下自己实现代码时犯的一些错误:实现尾删时错误的将 pMoveNode->next != NULL 当作是链表倒数第二个节点(实际是尾节点),导致打印时打印的是已经被释放的内存地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值