LinkList_以链表为核心的线性表的实现方法

#define _CRT_SECURE_NO_WARNINGS //屏蔽vscode2019中不可以使用scanf函数错误的
/*
	LinkList 以链表为核心
	离散存储[链表]

	链表的程序不仅要会还要能敲出来

	定义:
		1.n个节点离散分配
		2.彼此通过指针相连
		3.每个节点有一个前驱,一个后继
		4.首节点没有前驱,尾节点没有后继
	术语:
		——》头节点 _-> 首节点_ _-> _ _-> _ _-> _ _-> 尾节点_ ^

		头节点:第一个有效节点之前的节点
			   不存放有效数据
			   加头节点的目的是为了方便对链表操作
		首节点:第一个有效节点,存放有效数据
		尾节点:最后一个有效节点
		头指针:指向头节点的指针“  ——》 ”
		尾指针:指向尾节点的指针变量
	算法:
		狭义:算法是和数据的存储方式密切相关
		广义:算法和数据的存储方式无关,这就是泛型思想
		泛型:对于同一种逻辑结构,无论该逻辑结构的物理存储是什么
			 样子的,我们可以对它执行相同的操作

	节点类型:
		struct Node {
			int data; //数据域
			struct Node* next; //指针域
		};
*/

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

/*
typedef struct Node {
	int data;//数据域
	struct Node* next;//指针域
}*   是一个整体“struct Node *”
PNODE 将“struct Node *” 重命名为PNODE
*/
typedef struct Node {
	int data;//数据域
	struct Node* next;//指针域
} NODE, *PNODE;//NODE等价于struct Node,PNODE等价于struct Node *
//函数声明
PNODE creat_list(void);
void traverse_list(PNODE pHead);//遍历链表
bool is_empty(PNODE pHead);
int lenth_list(PNODE pHead);
bool insert_list(PNODE pHead, int pos, int val);
bool delete_list(PNODE pHead, int pos, int* pVal);
void sort_list(PNODE pHead);//冒泡排序

int main() {
	//链表的程序不仅要会还要能敲出来
	PNODE pHead = NULL;//等价于struct Node * pHead
	//头指针

	pHead = creat_list();//创建一个链表
	traverse_list(pHead);

	int lenth = lenth_list(pHead);
	printf("链表节点:%d \n",lenth);

	insert_list(pHead, 2, 30);
	traverse_list(pHead);
/*  sort_list(pHead);
	traverse_list(pHead);
	*/
	/*
	if (is_empty(pHead)) {
		printf("空\n");
	}
	else {
		printf("不空\n");
	}
	*/
	return 0;
}

PNODE creat_list(void) {
	int len;
	int val;

	printf("请输入你要生成节点个数\n");
	scanf("%d", &len);

	PNODE pHead/*头指针*/ = (PNODE)malloc(sizeof(NODE));//头节点
	if (pHead == NULL) {
		printf("分配失败,程序终止运行\n");//如果内存都分配失败了,
		//程序就没运行下去的必要了!
		exit(-1);
	}

	PNODE pLow = pHead;//pLow永远指向最后一个节点
	pHead->next = NULL;

	for (int i = 0; i < len; i++) {
		printf("请输入这个节点的值\n");
		scanf("%d", &val);
		PNODE pNew = (PNODE)malloc(sizeof(NODE));/*临时节点*/ 
		if (pNew == NULL) {
			printf("分配失败,程序终止运行\n");
			exit(-1);
		}
		pNew->data = val;//pNew数据域初始化
		pNew->next = NULL;//pNew指针域初始化
		/*这一步要好好理解一下(有一个永远指向最后一个节点的指针)*/
		pLow->next = pNew;//让pLow指向的节点的指针域等于新节点
		pLow = pNew;//让pLow永远指向尾节点
	}
	return pHead;
}

void traverse_list(PNODE pHead) {/*遍历*/
	PNODE p = pHead->next;//这是首节点
	//pHead是头指针 
	//pHead->next,是头结点的指针域是首节点

	/*
	链表为空的条件是:
		链表只有一个头节点并且头节点的指针域为^(NULL)
	所以现在p是头结点的指针域有可能为空

	p指向尾节点时p还不为空,当p = p->next;时p为空while结束
	*/
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

int lenth_list(PNODE pHead) {
	int len = 0;
	PNODE p = pHead->next;
	while (p != NULL) {
		len++;
		p = p->next;
	}
	return len;
}

bool is_empty(PNODE pHead) {
	if (pHead->next == NULL) {
		return true;
	}
	return false;
}

void sort_list(PNODE pHead) {/*排序*/
	int i, j, t;
	PNODE p, q;

	int len = lenth_list(pHead);
	//这里把链表看成数组
	/*i=0是数组的第一个元素,p = pHead->next是数组a[0]的地址
							p现在是头节点的指针域,指向首节点*/
	for (i = 0,p = pHead->next; i < len - 1; i++,p = p->next) {
								/*这里p=p->next指向数组的下一个地址*/
		/*j=i+1是数组的第二个元素,q=p->next指向首节点的下一个节点*/
		for (j = i + 1, q = p->next; j < len; j++, q = q->next) {
			if (p->data > q->data) {
				t = p->data;
				p->data = q->data;
				q->data = t;
			}
		}
	}
	/*	冒泡排序算法:
	*  由于n比真实数组下标大1
		int i, j, t;
		i < n - 1(n-1是最后一个元素,“小于”就是最后一个的前一个)
		for (i = 0; i < n - 1; ++i){
			j < n(n比最后一个还后一个,“小于”就是最后一个)
			for (j = i+1; j < n; ++j){
				if (a[i] < a[j]){
					t = a[i];
					a[i] = a[j];
					a[j] = t;
				}
			}
		}
	*/
}

/*插入和删除节点非常重要一定要看会,*/
bool insert_list(PNODE pHead, int pos, int val) {
	//pos的值要合理,要在合理节点范围
	int i = 0;
	PNODE p = pHead;
	while (p != NULL && i < pos - 1) {
		p = p->next;
		i++;
	}
	if (pos-1 < i || p == NULL) return false;
	PNODE pNew = (PNODE)malloc(sizeof(NODE));
	if (NULL == pNew) {
		printf("动态分配内存失败\n");
		exit(-1);
	}
	pNew->data = val;
	PNODE q = p->next;
	p->next = pNew;
	pNew->next = q;
	return true;
}

bool delete_list(PNODE pHead, int pos, int* pVal) {
	int i = 0;
	PNODE p = pHead;
	while (p->next != NULL && i < pos - 1) {
		p = p->next;
		i++;
	}
	if (pos - 1 < i || p->next == NULL) return false;
	
	PNODE q = p->next;
	*pVal = q->data;
	//删除p节点后面的节点
	p->next = p->next->next;
	free(q);
	q = NULL;

	return true;
}

个人觉得实现起来还是挺有成绩感的
有兴趣可以看一下我的另一篇ArrayList以数组为核心的线性表的实现方法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值