链表(C语言)

前言

本次我们介绍链表的创建及增,删,改,及反转。

一、链表是什么?

首先我们来了解一下线性存储结构。线性存储结构是一种最常见的存储结构。其特点是数据元素之间存在一一对应的关系。线性存储结构又分为两种,即顺序存储结构链式存储结构
1.首先,我们来了解一下顺序存储结构。顺序存储的线性表称为顺序表(数组)。其原理是逻辑上相邻的元素在物理位置上也相邻。
我们可以理解为一堆按照一定顺序摆放的书。我们在知道它的排列规律之后就可以通过它的排列规律来找到我们想找到的那本书。我们也可以通过一本一本的去找,来找到我们想要找到的那本书。
我们可以很方便的理解,要在这一堆有顺序的书中放进去一本或者拿出来一本,我们必然要先找到要它的位置在进行操作,而且我们需要一个连续的地方来放这一堆书。

2.其次,我们来了解一下链式存储结构(链表)。它的特点是逻辑上不相邻的两个元素在物理位置上也相邻。我们可以理解为有一本书,这本书在你打开它之后会看到它本身的内容,也会得到第二本书所在的地址。你可以通过这个地址来寻找第二本书。
不难理解,如果我们要在这组书中加入一本书,只需要在某一本书后边加上这本书所在的地址,在在这本书后边加上原本那本书后边的地址即可。而且我们并不需要一块很大的连续的空间来存放这堆书。

链表是一种类似于数组又不同于数组的一种线性表。
链表(C语言)_第1张图片

二、单链表的初识

链表(C语言)_第2张图片

1.定义结构体

注意要包含头文件
#include

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

2.创建头节点

struct Node* CreatList () {
	struct Node* HeadNode = (struct Node*)malloc(sizeof(struct Node));
	//给HeadNode申请了一块大小为struct Node的空间,将它强制类型转换为struct Node*
	HeadNode->data = 1;
	//初始化HeadNode的值
	HeadNode->next = NULL;
	//置空HeadNode的下一个结构体变量
	return HeadNode;
}

3.写一个函数,用来创建结点

struct Node* CreatNode(int data) {
	struct Node* NewNode = (struct Node*)malloc(sizeof(struct Node));
	NewNode->data = data;
	//将要输入的数据存放到新节点中
	NewNode->next = NULL;
	//将新节点的next置空
	return NewNode;
}

4.头插法插入新结点

void InsertNodeByHead(struct Node* HeadNode, int data) {
	struct Node* NewNode = CreateNode(data);
	//调用函数创建节点
	NewNode->next = HeadNode->next;
	//新节点指向原来头结点的next
	HeadNode->next = NewNode;
	//原来的头结点的next指向新节点
}

}

链表(C语言)_第3张图片

5.尾插法插入新结点

void InsertNodeByTrall(struct Node* HeadNode, int data) {
	struct Node* NewNode = CreatNode(data);
	//同样使用函数创建一个新节点
	while (HeadNode->next) {
		HeadNode = HeadNode->next;
		//次循环用于找到链表的尾节点
	}
	HeadNode->next = NewNode;
	//此时的HeadNode即为尾节点,要使用尾插法即在HeadNode之后添加新节点
	NewNode->next = NULL;
	//此时的新节点即为链表的尾,置空它
}

链表(C语言)_第4张图片

6.删除指定节点

void DeleteNode(struct Node* HeadNode, int Deletedata) {
	struct Node* DeleteNode = HeadNode->next;
	struct Node* DeleteNodeFront = HeadNode;
	if (HeadNode->next == NULL) {
		printf("链表为空,删除失败");
		//如果头结点的next为空则说明链表为空,不可能存在要删除的节点
	} else {
		if (DeleteNode->data != Deletedata) {
			DeleteNode = DeleteNode->next;
			DeleteNodeFront = DeleteNodeFront->next;
		} else {
			DeleteNode = HeadNode->next;
			//此部分用于找到要删除的结点
		}
	}
	DeleteNodeFront->next = DeleteNode->next;
	//此时结点被删除
	free(DeleteNode);
	//free被删除的结点
}

链表(C语言)_第5张图片

7.打印节点

void PrintNode(struct Node* HeadNode) {
	while (HeadNode->next != NULL) {
		printf("%d ", HeadNode->next->data);
		HeadNode = HeadNode->next;
		//遍历链表,依次打印
	}
	printf("\n");
}

8.修改节点

void ChangeNode(struct Node* HeadNode, int data, int Changedata) {
	struct Node* ChangeNode = HeadNode->next;
	if (ChangeNode == NULL) {
	//如果HeadNode的next为空,则说明链表为空,不可能存在要修改的结点
		printf("链表为空,修改失败");
	} else {
		if (ChangeNode->data != data) {
			ChangeNode = ChangeNode->next;
			//找到要修改的数值对应的结点
		} else {
			ChangeNode->data = Changedata;
			//修改这个数值
		}
	}
}

9.反转链表

本次介绍反转链表中很常见的一种方法,三指针依次迭代

void ReverseList(struct Node* HeadNode) {
	struct Node* p = HeadNode->next;
	struct Node* q = p->next;
	struct Node* r = NULL;
	p->next = NULL;
	while (q) {
		r = q;
		q = r->next;
		r->next = p;
		p = r;
	}
	HeadNode->next = r;
	return HeadNode;
}

10.按顺序插入节点

void InserNodeByOrder(struct Node* HeadNode,int Insertdata) {
	struct Node* NewNode = CreatNode(Insertdata);
	struct Node* p = HeadNode->next;
	struct Node* q = p->next;
	if (p==NULL) {
		p = NewNode;
		NewNode->next = NULL;
	} while (p) {
		if ( (p->data<Insertdata) && (q->data>Insertdata) ) {
			p->next = NewNode;
			NewNode->next = q;
			break;
		} else {
			p = p->next;
			q = q->next;
		}
	}
}

三、应用

int main() {
	struct Node* List = CreatList();//先创建一个链表
	InsertNodeByHead(List, 1);
	InsertNodeByHead(List, 2);
	InsertNodeByHead(List, 3);//头插法依次插入1,2,3
	PrintNode(List);
	InsertNodeByTrall(List, 9);//尾插法插入9
	PrintNode(List);
	DeleteNode(List, 3);//删除链表中数值为3的结点
	PrintNode(List);
	ChangeNode(List, 2, 4);//将链表中数值为2的结点的数值改为4
	PrintNode(List);
}

在这里插入图片描述
第一个321表示使用头插法插入的123
然后的3219表示使用尾插法插入了9
219表式删除了3
419表示将2替换为4

你可能感兴趣的:(iOS,链表,数据结构,算法)