C语言之链表探究之单向链表(List)、附双向循环链表参考博文地址

在这里插入图片描述
参考博文:C语言数据结构-创建链表的四种方法

链表结构图一
在这里插入图片描述
链表结构图二
在这里插入图片描述
链表结构图三
在这里插入图片描述
链表结构图四
在这里插入图片描述

一.静态链表

例1:
在这里插入图片描述
附例1代码:

#include <stdio.h>

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

int main()
{
    
    
	//2.链表内容
	Node a,b,c;
	a.data = 10;
	b.data = 20;
	c.data = 30;
	//3.链表链接
	a.next = &b;
	b.next = &c;
	c.next = NULL;   //4.链表结尾
	
	Node * head = &a;//1.链表开头
	while(head != NULL) 
	{
    
    
		printf("data = %d\n",head->data);
		head = head->next;
	}
	return 0;	
}

二.动态链表

  静态链表的意义不是很大,主要原因,数据存储在栈上,栈的存储空间有限, 不能动态分配。所以空链表要实现存储的自由,要动态的申请堆里的空间。
在这里插入图片描述
例2:
在这里插入图片描述
在这里插入图片描述
运行:
在这里插入图片描述
附例2代码:

#include <stdio.h>
#include <stdlib.h>
//这里创建一个结构体用来表示链表的结点类型
struct node {
    
    
	int data;
	struct node *next;
};
int main()
{
    
    
	struct node *head,*p,*q,*t;
	int i,n,a;
	scanf("%d",&n);
	head = NULL;//头指针初始为空
	for(i=1; i<=n; i++) {
    
     //循环读入n个数
		scanf("%d",&a);
//动态申请一个空间,用来存放一个结点,并用临时指针p指向这个结点
		p=(struct node *)malloc(sizeof(struct node));
		p->data=a;//将数据存储到当前结点的data域中
		p->next=NULL;//设置当前结点的后继指针指向空,也就是当前结点的下一个结点为空
		if(head==NULL)
			head=p;//如果这是第一个创建的结点,则将头指针指向这个结点
		else
			q->next=p;//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点
		q=p;//指针q也指向当前结点
	}
//输出链表中的所有数
	t=head;
	while(t!=NULL) {
    
    
		printf("%d ",t->data);
		t=t->next;//继续下一个结点
	}
	getchar();
	getchar();
	return 0;
}

2.1尾插法(略)

2.2头插法

例3
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行结果:
在这里插入图片描述
附例3代码:

#include <stdio.h>
#include <stdlib.h>
//这里创建一个结构体用来表示链表的结点类型
struct node {
    
    
	int data;
	struct node *next;
};
int main()
{
    
    
	struct node *head,*p,*q,*t;
	int i,n,a;
	scanf("%d",&n);
	head = NULL;//头指针初始为空
	for(i=1; i<=n; i++) {
    
     //循环读入n个数
		scanf("%d",&a);
//动态申请一个空间,用来存放一个结点,并用临时指针p指向这个结点
		p=(struct node *)malloc(sizeof(struct node));
		p->data=a;//将数据存储到当前结点的data域中
		p->next=NULL;//设置当前结点的后继指针指向空,也就是当前结点的下一个结点为空
		if(head==NULL)
			head=p;//如果这是第一个创建的结点,则将头指针指向这个结点
		else
			q->next=p;//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点
		q=p;//指针q也指向当前结点
	}
	scanf("%d",&a);//读入待插入的数
	t=head;//从链表头部开始遍历
	while(t!=NULL) {
    
     //当没有到达链表尾部的时候循环
		if(t->next->data > a) {
    
     //如果当前结点下一个结点的值大于待插入数,将数插入到中间
			p=(struct node *)malloc(sizeof(struct node));//动态申请一个空间,
			用来存放新增结点
			p->data=a;
			p->next=t->next;//新增结点的后继指针指向当前结点的后继指针所指向的结点
			t->next=p;//当前结点的后继指针指向新增结点
			break;//插入完毕退出循环
		}
		t=t->next;//继续下一个结点
	}
//输出链表中的所有数
	t=head;
	while(t!=NULL) {
    
    
		printf("%d ",t->data);
		t=t->next;//继续下一个结点
	}
	getchar();
	getchar();
	return 0;
}

例:创建,打印,插入,删除节点;模块化编程
本例来自:https://www.bilibili.com/video/BV1Rb411F738?t=1904

打印节点:
在这里插入图片描述
插入节点:
在这里插入图片描述
删除节点:
在这里插入图片描述
在这里插入图片描述
附上例代码:

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

struct Node
{
    
    
	int data;//数据域
	struct Node* next;//指针域
};

//创建一个链表
struct Node* createList()
{
    
    
	struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));
	//headNode成为了结构体变量
	//变量使用之前必须被初始化
	//headNode->data=1;
	headNode->next=NULL;
	return headNode;
}

//创建一个节点
struct Node* createNode(int data)
{
    
    
	struct Node* newNode=(struct Node*)malloc(sizeof(struct Node));
	newNode->data=data;
	newNode->next=NULL;
	return newNode;
}

//打印节点
void printList(struct Node* headNode)
{
    
    
	struct Node* pMove=headNode->next;
	while(pMove)
	{
    
    
		printf("%d\t",pMove->data);
		pMove=pMove->next;
	}
	printf("\n");
}

//插入节点,参数:插入那个链表,插入节点的数据是多少
void insertNodeByhead(struct Node* headNode,int data)
{
    
    
	//1.创建插入的节点
	struct Node* newNode=createNode(data);
	newNode->next=headNode->next;
	headNode->next=newNode;
}

//删除节点(指定位置删除)
void deleteNodeByAppoin(struct Node* headNode,int posData)
{
    
    
	struct Node* posNode=headNode->next;
	struct Node* posNodeFront=headNode;
	if(posNode==NULL)
		printf("无法删除链表为空\n");
	else
	{
    
    
		while(posNode->data!=posData)
		{
    
    
			posNodeFront=posNode;
			posNode=posNodeFront->next;
			if(posNode==NULL)
			{
    
    
				printf("没有找到相关信息,无法删除\n");
				return;
			}
		}
		posNodeFront->next=posNode->next;
		free(posNode);
	}
}

int main()
{
    
    
	struct Node* list=createList();
	insertNodeByhead(list,1);
	insertNodeByhead(list,2);
	insertNodeByhead(list,3);
	printList(list);
	deleteNodeByAppoin(list,2);
	printList(list);
	return 0;
}

例:同样来自:https://www.bilibili.com/video/BV1Rb411F738?t=1904
在这里插入图片描述
附上例代码:

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

struct student
{
    
    
	char name[20];
	int num;
	int math;
};

struct Node
{
    
    
	struct student data;//数据域
	struct Node* next;//指针域
};

//创建一个链表
struct Node* createList()
{
    
    
	struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));
	//headNode成为了结构体变量
	//变量使用之前必须被初始化
	//headNode->data=1;
	headNode->next=NULL;
	return headNode;
}

//创建一个节点
struct Node* createNode(struct student data)
{
    
    
	struct Node* newNode=(struct Node*)malloc(sizeof(struct Node));
	newNode->data=data;
	newNode->next=NULL;
	return newNode;
}

//打印节点
void printList(struct Node* headNode)
{
    
    
	struct Node* pMove=headNode->next;
	printf("name\tnum\tmath\n");
	while(pMove)
	{
    
    
		printf("%s\t%d\t%d\n",pMove->data.name,pMove->data.num,pMove->data.math);
		pMove=pMove->next;
	}
	printf("\n");
}

//插入节点,参数:插入那个链表,插入节点的数据是多少
void insertNodeByhead(struct Node* headNode,struct student data)
{
    
    
	//1.创建插入的节点
	struct Node* newNode=createNode(data);
	newNode->next=headNode->next;
	headNode->next=newNode;
}

//删除节点(指定位置删除)
void deleteNodeByAppoinNum(struct Node* headNode,int num)
{
    
    
	struct Node* posNode=headNode->next;
	struct Node* posNodeFront=headNode;
	if(posNode==NULL)
		printf("无法删除链表为空\n");
	else
	{
    
    
		while(posNode->data.num!=num)
		{
    
    
			posNodeFront=posNode;
			posNode=posNodeFront->next;
			if(posNode==NULL)
			{
    
    
				printf("没有找到相关信息,无法删除\n");
				return;
			}
		}
		posNodeFront->next=posNode->next;
		free(posNode);
	}
}

int main()
{
    
    
	struct Node* list=createList();
	struct student info;
	while(1)
	{
    
    
		printf("请输入学生的姓名 学号 数学成绩:");
		scanf("%s%d%d",info.name,&info.num,&info.math);
		insertNodeByhead(list,info);
		printf("(continue(Y/N))?");
        setbuf(stdin,NULL);
        int choice=getchar();
		if(choice=='N'||choice=='n')
		{
    
    
			break;
		}
	}
	printList(list);

	return 0;
}

3.链表反转

在这里插入图片描述

在这里插入图片描述

4.链表销毁

在这里插入图片描述
附代码:

//链表销毁
void destroyList(Node * head)
{
    
    
	Node * p = NULL;
	while(head) {
    
     //有多少个malloc就有多少个free
		p = head->next;
		free(head);
		head = p;
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

C语言之双向循环链表参考博文:数据结构——双向循环链表的结构与实现(C语言)

猜你喜欢

转载自blog.csdn.net/weixin_43297891/article/details/114218067