数据结构之无头鱼 咳咳无头链表
上次我介绍了有头链表,这次我来写无头链表,其中有两种形式——————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);
}
大概如此,实际上学习数据结构也就是理解他的逻辑思路和模型,只要了解,画画图
利用自己的知识化为实际,也就挺简单的。