数据结构--C语言 单链表(细细细)

 1.头文件

#include<stdio.h>           
#include<stdlib.h>              //针对 malloc and free 的函数
#include <stdbool.h>            //针对与true and false 的头文件

注:如果将true 和 false 改为 1 和 0,就不需要#include<stdbool.h>;

 2.声明

有很对不同的写法,这里为大家提供了【两种】作为参考,这里来解释以下:

1.定义结构体,由于链表结点是由两部分组成,参数(data)以及指针(node),/*当然这个变量是自己定义的*/

2.定义一个指针Link ,表示 struct node*  ;

3.定义一个变量Node, 表示 struct node ;

/*为什么要定义Link 和 Node , 个人认为是为了接下来代码的书写,至少不用每次都来 struct node,看着也别扭;*/

/*定义指针,一部少分是为了方便书写。还有一部分,像头节点一些重要的结点不能丢失,重新定义新的结点来移动还有一大部分是为了起指路灯,方便查找;*/

//单链表节点结构   (习惯使用)
typedef struct node{
	int data;				//数据域
	struct node* next;		//指针域
}Node,*Link;
struct Node;
typedef struct Node* PNode;
struct Node {
	int info;
	PNode link;
};
typedef struct Node* LinkList;

 3.创建一个空链表

链表中最后一个元素都要指定为空(NULL),在创建链表的时候一定不能忘记,在【单链表中循环结束的条件一般都是指针指向NULL】

注:循环链表中循环结束的条件一般都是指针指向头结点(head),这也就是循环链表和单链表的差别,在创建链表时将NULL换成head指针就可以了,平时留心注意一下就可以;

这里有两种创建链表方式,其实说白了也就一种,他们的差别就在与:

第一种只创建了个头指针,插入链表for循环写在了main函数里面,可以查看下面的main函数;

第二种引用函数就可以创建完整的链表;

区别:第一种 + for循环 = 第二种;

 -----------------------------------------------------------第一种------------------------------------------------------------

//创建一个空链表
Link creatNullList_Link(void) {
	Link llist = (Link)malloc(sizeof(Node));            //给头结点赋予空间
	if (llist != NULL) {
		llist->next = NULL;                            //头结点的指针指向空(NULL)
	}                                                  //链表中最后一个元素都要指定为空
	else {
		printf("Out of space");
	}
	return llist;                                      //返回头结点
}

 -----------------------------------------------------------第二种------------------------------------------------------------

//创建一个单链表——头插法(数组反序)
Link newList_first(int a[], int n) {
	//创建头结点
	Link head = (Link)malloc(sizeof(Node));
	head->next = NULL;
	//创建后续结点
	for (int i = 0; i < n; i++) {                        //for循环将数组的元素插入链表
		Link node = (Link)malloc(sizeof(Node));
		node->data = a[i];
		node->next = head->next;
		head->next = node;
	}
	return head;
}

//创建一个单链表——尾插法(数组正序)
Link newList_post(int a[], int n) {
	Link head = (Link)malloc(sizeof(Node));
	head->next = NULL;
	Link rear = head;
	for (int i = 0; i < n; i++) {
		Link node = (Link)malloc(sizeof(Node));
		node->data = a[i];
		node->next = NULL;
		rear->next = node;
		rear = node;
	} 
	return head;
}

 4.打印链表

此方法用于将链表的元素输出;

//单链表遍历操作
void displayNode(Link head) {
	Link p = head->next;
	while (p != NULL) {
		printf("%d", p->data);
		p = p->next;
	}
}

4.链表结点的个数 

//求单链表的元素个数
int length(Link head) {
	Link p = head->next;
	int count = 0;
	while (p != NULL) {
		p = p->next;
		count++;
	}
	return count;
}

 5.单链表的查找操作

//单链表的查找操作
int queryNode(Link head, int x) {
	Link p = head->next;                //定义一个新结点用于向后移动
	int count = 0;
	while (p != NULL) {
		if (p->data == x) {
			printf("%d",count);			//找到则输出下标,
			return count;				//并提前返回true
		}
		count++;
		p = p->next;
	}
	//如果循环结束,说明没有找到,返回false
	return 0;
}

 6.单链表的插入操作

//单链表的插入操作
/*1.工作指针p初始化
* 2.查找第i-1个结点,并使工作指针p指向该结点
* 3.若查找不成功,则返回false
*		否则
*			生成一个元素为x的新节点s
*			将新结点s插入到结点p之后
*			返回true
*/
bool insertNode(Link head, int i, int x) {
	Link p = head;                              //定义一个新结点向后移动(头指针不能移动)
	int count = 0;
	while (p != NULL && count < i - 1) {
		p = p->next;
		count++;
	}
	if (p == NULL) {
		return false;
	}
	else {
		Link node = (Link)malloc(sizeof(Node));
		node->data = x;
		node->next = p->next;
		p->next = node;
		return true;
	}
}

 7.单链表结点的删除

//单链表结点的删除(有更新的做法)
/*
	1.判断链表是否是空表,如果是空表返回false
	2.工作指针p,q初始化
	3.若指针p不为空,则继续下列循环
		3.1
			如果找到数据x所在的p结点,将p结点从链表上摘下
			释放p结点
			提前返回true,删除成功
		否则
		3.2
			q移动到p所在的位置
			p移动到下一个结点
	4.循环结束,没有与x相等的结点,返回false
*/
bool deleteNode(Link head, int x) {
	if (head == NULL || head->next == NULL) {
		return false;
	}
	Link p, q;
	p = head->next;
	q = head;
	while (p != NULL) {
		if (p->data == x) {
			q->next = p->next;
			free(p);
			return true;
		}
		else {
			q = p;
			p = p->next;
		}
	}
	//如果循环结束
	return false;
}
//单链表结点的删除(不用移动q,比上一个快)
/*1.工作指针p,q初始化
* 2.p为移动结点,从头结点开始
* 3.p 的下一个结点等于 x ,或者为空,停止向后移动(找到x / x不存在链表(最后结点指向NULL))
* 4.在找到x的前提下,将q表示为待删结点
* 5.将q从链表上摘下,释放q
*/
bool deleteNode_1(Link head, int x) {
	Link p, q;
	p = head;
	if (p == NULL) {
		return false;
	}
	while (p->next != NULL && p->next->data != x) {
		p = p->next;
	}
	if (p->next != NULL) {
		q = p->next;
		p->next = q->next;
		free(q);
		return true;
	}
	return false;
}

8.单链表的释放 

将链表结点全部释放(包括头指针)

//单链表的释放
void clearLink(Link head) {
	Link q;
	while (head->next != NULL) {
		q = head;
		head = head->next;
		free(q);
	}
}

9.主函数 

int main() {
	Link head = creatNullList_Link();     //引用函数,创建一个空列表,头指针为head(自定义)
	Link rear = head;
	printf("请输入插入链表长度:");
	int n;
	scanf_s("%d", &n);
	printf("请输入插入链表的值:");
	for (int i = 0; i < n; i++) {         //应用了创建链表的第一种(分开写)
		int value;
		scanf_s("%d", &value);;
		Link node = (Link)malloc(sizeof(Node));
		node->data = value;
		node->next = NULL;
		rear->next = node;
		rear = node;
	}
	displayNode(head);
	// 插入一个结点
	printf("\n");
	printf("请输入插入结点位置:");
	int i;
	scanf_s("%d", &i);
	printf("请输入插入结点值:");
	int x;
	scanf_s("%d", &x);
	insertNode(head, i, x);
	displayNode(head);
	//删除一个结点   (//删除一个值)
	printf("\n");
	printf("请输入删除结点位置:");
	int s;
	scanf_s("%d", &s);
	deleteNode_1(head, s);
	displayNode(head);
	//查找一个结点
	printf("\n");
	printf("请输入查找结点值:");
	int v;
	scanf_s("%d", &v);
	queryNode(head, v);
}

注:由于里面包含很多种方法,小伙伴引用的时候注意以下,主要就是创建空链表部分!!!

10.学习路程

刚开始看书,有些蒙,只理解思路。后来理解了指针怎么淘气之后就可以自己慢慢写代码了,即使错了,也没关系,改呗,哈。

[小愿望]:如果你觉得有帮助的话,点一下下面的小赞赞吧,嘟嘟可会很开心的~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值