数据结构之无头链表

数据结构之无头鱼 咳咳无头链表
上次我介绍了有头链表,这次我来写无头链表,其中有两种形式——————1.二级指针 2.利用结构体封装
第一种用二级指针:顾名思义,利用一个node指针来充当一个头,然后就不用创建新的链表,只需要一个指针指向链表开始的地方:

struct node {
	int data;
	struct node* next;
};
struct node* creatnode(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->data = data;
	newnode->next = NULL;
	return newnode;
}
int main()
{
	struct node* list = NULL;
}

这样链表算是建好了,一个空链表,下面来实现在头部插入:

void insertbyhead(struct node** list, int data) {
	struct node* newnode = creatnode(data);
	newnode->next = (*list);
	(*list) = newnode;
}

(*list)代表的就是list指针指向的node,这就不用多说了,也就是链表开始的地方
然后是跟有头链表是一模一样的手法
下面是在尾部插入,也是比葫芦画瓢

void insertbytail(struct node** list, int data) {
	struct node* newnode = creatnode(data);
	struct node* ptail = (*list);
	while (ptail->next) {
		ptail = ptail->next;
	}
	ptail -> next = newnode;
}

跟有头链表也是一样的
哦,好像好多都一样的,那么我就直接上码理解吧,很多还是跟有头链表的写法是一样的,只不过list充当的就是个指向头部节点的指针罢了
我把我写的这个码完整的放上去,自行理解完善吧,如果不太理解还是建议看一下我的有头链表的那些图

#include<cstdio>
#include <iostream>
#include<cstring>
struct node {
	int data;
	struct node* next;
};
struct node* creatnode(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->data = data;
	newnode->next = NULL;
	return newnode;
}
void insertbyhead(struct node** list, int data) {
	struct node* newnode = creatnode(data);
	newnode->next = (*list);
	(*list) = newnode;
}
void insertbytail(struct node** list, int data) {
	struct node* newnode = creatnode(data);
	struct node* ptail = (*list);
	while (ptail->next) {
		ptail = ptail->next;
	}
	ptail -> next = newnode;
}
void insertbyself(struct node** list, int data,int pro) {
	if ((*list) == NULL)printf("空链表");
	struct node* pfro = (*list);
	struct node* pser = (*list)->next;
	while (pser != NULL && pser->data != pro) {
		pfro = pser;
		pser = pser->next;
	}
	if (pser == NULL) printf("无法找到相应的节点");
	else {
		struct node* newnode = creatnode(data);
		newnode->next = pser;
		pfro->next = newnode;
	}
}
void deletebyhead(struct node** list) {
	if ((*list) == NULL)printf("空链表");
	struct node* deletenode = (*list);
	(*list) = (*list)->next;
	free(deletenode);
}
void deletebytail(struct node** list) {
	if ((*list) == NULL)printf("空链表");
	struct node* ptail = (*list)->next;
	struct node* ptailfro = (*list);
	while (ptail->next) {
		ptailfro = ptail;
		ptail = ptail->next;
	}
	ptailfro->next = NULL;
	free(ptail);
}
void printlist(struct node* list) {
	struct node* pmove = list;
	while (pmove) {
		printf("%d\t", pmove->data);
		pmove=pmove->next;
	}
	printf("\n");
}
int main()
{
	struct node* list = NULL;
	insertbyhead(&list, 1);
	insertbyhead(&list, 2);
	printlist(list);
	insertbyself(&list, 5, 1);
	printlist(list);
	insertbytail(&list, 3);
	printlist(list);
	deletebyhead(&list);
	printlist(list);
	deletebytail(&list);
	printlist(list);
}

好,我们介绍第二种写法:封装成结构体
这里也是用到了一些面向对象的思想,将链表抽象化几个特点封装成结构体:
1.一个开头,一个结尾 2.大小
好封装开始

struct node {
	int data;
	struct node* next;
};
struct list {
	struct node* headnode;
	struct node* tailnode;
	int size;
};

这就是封装了链表
下面开始写链表的初始化函数,初始化,它是个空表,所以头尾都是空(NULL)大小也为零

struct list* createlist() {
	struct list* newlist = (struct list*)malloc(sizeof(struct list));
	newlist->headnode = NULL;
	newlist->tailnode = NULL;
	newlist->size = 0;
	return newlist;
}

下面就是开始插入的函数,在头部插入:

struct node* createnode(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->data = data;
	newnode->next = NULL;
	return newnode;
}
void insertbyhead(struct list* plist,int data) {
	struct node* newnode = createnode(data);
	if (plist->size == 0){
		plist->tailnode = newnode;
		plist->headnode = newnode;
		}
	else{
		newnode->next = plist->headnode;
		plist->headnode = newnode;
		}
	plist->size++;
}

一点强调的就是空链表的时候,也就是大小为零的时候,插入的话,尾结点和头节点都是这个新插入元素,所以分情况
然后这个可以简化,将相同的语句提出来,就是:

void insertbyhead(struct list* plist,int data) {
	struct node* newnode = createnode(data);
	if (plist->size == 0)
		plist->tailnode = newnode;
	else
		newnode->next = plist->headnode;
	plist->headnode = newnode;
	plist->size++;
}

在表尾同理得

void insertbytail(struct list* plist, int data) {
	struct node* newnode = createnode(data);
	if (plist->size == 0)
		plist->headnode = newnode;
	else
		plist->tailnode->next = newnode;
	plist->tailnode = newnode;
	plist->size++;
}

下面写删除:
头部删除:

void deletebyhead(struct list* plist) {
	if (plist->size == 0)printf("空链表");
	else {
		struct node* deletenode = plist->headnode;
		plist->headnode = plist->headnode->next;
		free(deletenode);
		plist->size--;
	}
}

尾部的删除有坑就是得多分一下情况,因为要找表尾的前一个元素所以,表只有一个元素的时候是表头表尾在一起,这时候就没有表尾的前一个元素,所以这是一个坑值得写出来:

void deletebytail(struct list* plist) {
	if (plist->size == 0)printf("空链表");
	else if (plist->size == 1) {
		struct node* deletenode = plist->tailnode;
		plist->headnode = NULL;
		plist->tailnode = NULL;
		free(deletenode);
	}
	else {
		struct node* deletenode = plist->tailnode;
		struct node* pmove = plist->headnode;
		while (pmove->next != deletenode) {
			pmove = pmove->next;
		}
		pmove->next = NULL;
		free(deletenode);
		plist->tailnode = pmove;
		plist->size--;
	}
}

无头链表的删除节点,一大特点,必须有一个容器去暂时收容要删除的节点,然后释放,自己可以画图理解一下,和有头链表对比一下
大致功能已完成
我的整体程序如下,添加了一个随处增添的一个函数,可以再添加一个随处减删的函数

//---------------------------------------------------------------------------------------------------------------------------
//另一种写法,有一些面对对象的思想:封装成结构体
#include<stdio.h>
#include<stdlib.h>
struct node {
	int data;
	struct node* next;
};
struct list {
	struct node* headnode;
	struct node* tailnode;
	int size;
};
struct node* createnode(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->data = data;
	newnode->next = NULL;
	return newnode;
}
struct list* createlist() {
	struct list* newlist = (struct list*)malloc(sizeof(struct list));
	newlist->headnode = NULL;
	newlist->tailnode = NULL;
	newlist->size = 0;
	return newlist;
}
void insertbyhead(struct list* plist,int data) {
	struct node* newnode = createnode(data);
	if (plist->size == 0)
		plist->tailnode = newnode;
	else
		newnode->next = plist->headnode;
	plist->headnode = newnode;
	plist->size++;
}
void insertbytail(struct list* plist, int data) {
	struct node* newnode = createnode(data);
	if (plist->size == 0)
		plist->headnode = newnode;
	else
		plist->tailnode->next = newnode;
	plist->tailnode = newnode;
	plist->size++;
}
void insertbyself(struct list* plist, int data, int posdata) {
	struct node* newnode = createnode(data);
	struct node* posfro = plist->headnode;
	if (plist->headnode == NULL) printf("空链表");
	else
	{
		struct node* pos = plist->headnode->next;
		while (pos != NULL && pos->data != posdata) {
			posfro = pos;
			pos = pos->next;
		}
		newnode->next = pos;
		posfro->next = newnode;
		plist->size++;
	}
}
void deletebyhead(struct list* plist) {
	if (plist->size == 0)printf("空链表");
	else {
		struct node* deletenode = plist->headnode;
		plist->headnode = plist->headnode->next;
		free(deletenode);
		plist->size--;
	}
}
void deletebytail(struct list* plist) {
	if (plist->size == 0)printf("空链表");
	else if (plist->size == 1) {
		struct node* deletenode = plist->tailnode;
		plist->headnode = NULL;
		plist->tailnode = NULL;
		free(deletenode);
	}
	else {
		struct node* deletenode = plist->tailnode;
		struct node* pmove = plist->headnode;
		while (pmove->next != deletenode) {
			pmove = pmove->next;
		}
		pmove->next = NULL;
		free(deletenode);
		plist->tailnode = pmove;
		plist->size--;
	}
}
void printlist(struct list* plist) {
	struct node* pmove = plist->headnode;
	while (pmove!=NULL) {
		printf("%d\t", pmove->data);
		pmove = pmove->next;
	}
	printf("\n");
}
int main() {
	struct list* mylist = createlist();
	insertbyhead(mylist, 1);
	insertbyhead(mylist, 2);
	insertbytail(mylist, 3);
	printlist(mylist);
	insertbyself(mylist, -1, 3);
	printlist(mylist);
	deletebyhead(mylist);
	deletebyhead(mylist);
	printlist(mylist);
	deletebyhead(mylist);
	printlist(mylist);
	deletebytail(mylist);
	printlist(mylist);
}

大概如此,实际上学习数据结构也就是理解他的逻辑思路和模型,只要了解,画画图
利用自己的知识化为实际,也就挺简单的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值