郝斌老师【数据结构入门】学习记录之链表

链表的定义:

线性结构【把所有的节点用一根直线穿起来】

连续存续[数组]
1.什么叫数组
元素类型相同,大小相等
2.数组的优缺点:

离散存储[链表]
定义:
n个结点离散分配;
彼此通过指针相连;
每个节点只有一个前驱节点,每个节点只有一个后续结点;
首节点没有前驱结点,尾节点没有后续结点。

专业术语:
首结点:第一个有效结点。
尾结点:最后一个有效结点。
头结点:第一个有效结点之前的那个结点,头结点并不存放有效数据,加头结点的目的主要是为了方便对链表的操作。
头指针:指向头结点的指针变量。
尾指针:指向尾结点的指针变量。

确定一个链表只需要一个参数:头指针。

分类:
单链表
双链表
循环链表

算法:
狭义的算法与数据的存储方式密切相关
广义的算法与数据存储的方式无关
泛型:
利用某种技术达到的效果就是:不同的存储方式,执行的操作一样的。

链表的实现:

如何表示一个链表结点

typedef struct Node
{
int data; //数据域
struct Node *pNext;  //指针域  指向另一个结点的整体
}NODE,*PNODE;  //NODE等价于struct Node,  PNODE等价于struct Node *

链表的创建(尾插法)与遍历

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

typedef struct Node
{
	int data; //数据域
	struct Node *pNext; //指针域
}NODE, *PNODE;


PNODE create_list(void);
void traverse_list(PNODE pHead);

int main()
{
	
	PNODE pHead = NULL;  //等价于 struct Node * pHead = NULL

	pHead = create_list();  //创建一个单链表,并将该链表的头结点赋给pHead
	traverse_list(pHead);

	return 0;
}

PNODE create_list(void)
{
	int len; //用来存放有效节点的个数
	int i;
	int val; //用来临时存放用户输入的节点的值

	//分配了一个不存放有效数据的头结点
	PNODE pHead = (PNODE)malloc(sizeof(NODE));
	if (NULL == pHead)
	{
		printf("分配失败,程序终止!\n");
		exit(-1);
	}
	PNODE pTail = pHead;
	pTail->pNext = NULL;

	printf("请输入您要生成链表节点的个数:len = ");
	scanf_s("%d", &len);

	for (i = 0; i < len; ++i)
	{
		printf("请输入第%d个节点的值: ", i + 1);
		scanf_s("%d", &val);

		PNODE pNew = (PNODE)malloc(sizeof(NODE));
		if (NULL == pNew)
		{
			printf("分配失败,程序终止!\n");
			exit(-1);
		}

		pNew->data = val;
		pTail->pNext = pNew;
		pNew->pNext = NULL;
		pTail = pNew;
	}

	return pHead;
}


void traverse_list(PNODE pHead)
{
	PNODE p = pHead->pNext;

	while (NULL != p)
	{
		printf("%d ", p->data);
		p = p->pNext;
	}
	printf("\n");  
}

注:由于我刚开始学习数据结构,对于这个尾插法不太好理解,刚开始一直没理解pTail->pNext = pNew和pTail = pNew,因为我刚开始把pTail看成一个结点,其实它是一个指向结点的指针,因为在给定义结点的时候还取了一个别名*PNODE,所以PONDE实例化的pTail是一个指向结构体的指针。下面是我对尾插法的理解,有不对的地方欢迎批评指正。

PNODE pTail = pHead;
pTail->pNext = NULL;

1.创建一个指向尾结点的指针pTail,因为此时只有一个头结点,所以此时头结点就是尾结点,然后把头结点指针域清空。

pNew->data = val;

2.给新插入的结点一个数据。

pTail->pNext = pNew;

3.把指向新结点的这个指针赋给尾结点的指针,这样pTail->pNext就指向了新插入的这个结点。

pNew->pNext = NULL;

4.把新插入的这个结点的指针域置空。

pTail = pNew;

5.让pTail指向新插入的节点,即始终让pTail指向尾结点。

判断链表是否为空
求链表长度
排序(选择排序)

//判断链表是否为空
bool is_empty(PNODE pHead)
{
	if (pHead->pNext == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//求链表长度
int length_list(PNODE pHead)
{
	PNODE p = pHead->pNext;
	int len = 0;
	while (p != NULL)
	{
		++len;
		p = p->pNext; 
	}
	return len;
}

//排序(选择排序)
void sort_list(PNODE pHead)
{
	int i, j, t;
	int len = length_list(pHead);
	PNODE p, q;

	for (i = 0, p = pHead->pNext; i < len - 1; ++i, p = p->pNext)
	{
		for (j = i + 1, q = p->pNext; j < len; ++j, q = q->pNext)
		{
			if (p->data > q->data) //类似于数组中的: a[i] > a[j]
			{
				t = p->data;  //类似于数组中的:t = a[i]
				p->data = q->data;  //类似于数组中的:a[i] = a[j]
				q->data = t;  //类似于数组中的: a[j] = t
			}
		}
	}
}

在链表的第pos个结点前面插入一个新结点
删除第pos个结点

//在pHead所指向链表的第pos个结点的前面插入一个新的结点
//该结点的值是val,并且pos的值是从1开始
bool insert_list(PNODE pHead, int pos, int val)
{
	int i = 0;
	PNODE p = pHead;

	//首先找到指向第pos-1个结点的指针p
	while (p != NULL && i < pos - 1)
	{
		p = p->pNext;
		++i;
	}

	if (i > pos - 1 || p == NULL)
	{
		return false;
	}

	//为要插入的节点开辟内存
	PNODE pNew = (PNODE)malloc(sizeof(PNODE));
	if (pNew == NULL)
	{
		printf("内存分配失败\n");
	}

	插入操作1
	//pNew->data = val;
	//PNODE q = p->pNext;
	//p->pNext = pNew;
	//pNew->pNext = q;

	//插入操作2
	pNew->data = val;
	pNew->pNext = p->pNext;
	p->pNext = pNew;



	return true;
}

bool delete_list(PNODE pHead, int pos, int* val)
{
	int i = 0;
	PNODE p = pHead;

	//首先找到指向第pos-1个结点的指针p
	while (p->pNext != NULL && i < pos - 1)
	{
		p = p->pNext;
		++i;
	}

	if (i > pos - 1 || p->pNext == NULL)
	{
		return false;
	}

	
	PNODE q = p->pNext;
	*val = q->data;

	//删除p结点后的结点
	p->pNext = p->pNext->pNext;
	free(q);
	q = NULL;

	return true;
}

以上所有操作代码

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

typedef struct Node
{
	int data; //数据域
	struct Node *pNext; //指针域
}NODE, *PNODE;


PNODE create_list(void);
void traverse_list(PNODE pHead);
bool is_empty(PNODE pHead);
int length_list(PNODE pHead);
bool insert_list(PNODE, int pos, int val);
bool delete_list(PNODE pHead, int pos, int* val);
void sort_list(PNODE);

int main()
{
	
	PNODE pHead = NULL;  //等价于 struct Node * pHead = NULL

	pHead = create_list();  //创建一个单链表,并将该链表的头结点赋给pHead
	traverse_list(pHead);

	/*if (is_empty(pHead))
	{
		printf("链表为空\n");
	}
	else
	{
		printf("链表不为空\n");
	}*/

	int len = length_list(pHead);
	printf("链表的长度是:%d\n", len);

	//sort_list(pHead);
	//traverse_list(pHead);

	//插入新结点
	//insert_list(pHead, 4, 5);
	//traverse_list(pHead);

	//删除pos位置的结点
	int val;
	if (delete_list(pHead, 3, &val))
	{
		printf("删除成功,您删除的元素是:%d\n", val);
	}
	else
	{
		printf("删除失败\n");
	}
	traverse_list(pHead);

	return 0;
}

PNODE create_list(void)
{
	int len; //用来存放有效节点的个数
	int i;
	int val; //用来临时存放用户输入的节点的值

	//分配了一个不存放有效数据的头结点
	PNODE pHead = (PNODE)malloc(sizeof(NODE));
	if (NULL == pHead)
	{
		printf("分配失败,程序终止!\n");
		exit(-1);
	}
	PNODE pTail = pHead;
	pTail->pNext = NULL;

	printf("请输入您要生成链表节点的个数:len = ");
	scanf_s("%d", &len);

	for (i = 0; i < len; ++i)
	{
		printf("请输入第%d个节点的值: ", i + 1);
		scanf_s("%d", &val);

		PNODE pNew = (PNODE)malloc(sizeof(NODE));
		if (NULL == pNew)
		{
			printf("分配失败,程序终止!\n");
			exit(-1);
		}

		pNew->data = val;
		pTail->pNext = pNew;
		pNew->pNext = NULL;
		pTail = pNew;
	}

	return pHead;
}

//遍历链表
void traverse_list(PNODE pHead)
{
	PNODE p = pHead->pNext;

	while (NULL != p)
	{
		printf("%d ", p->data);
		p = p->pNext;
	}
	printf("\n");  
}

//判断链表是否为空
bool is_empty(PNODE pHead)
{
	if (pHead->pNext == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//求链表长度
int length_list(PNODE pHead)
{
	PNODE p = pHead->pNext;
	int len = 0;
	while (p != NULL)
	{
		++len;
		p = p->pNext; 
	}
	return len;
}

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

	for (i = 0, p = pHead->pNext; i < len - 1; ++i, p = p->pNext)
	{
		for (j = i + 1, q = p->pNext; j < len; ++j, q = q->pNext)
		{
			if (p->data > q->data) //类似于数组中的: a[i] > a[j]
			{
				t = p->data;  //类似于数组中的:t = a[i]
				p->data = q->data;  //类似于数组中的:a[i] = a[j]
				q->data = t;  //类似于数组中的: a[j] = t
			}
		}
	}
}

//在pHead所指向链表的第pos个结点的前面插入一个新的结点
//该结点的值是val,并且pos的值是从1开始
bool insert_list(PNODE pHead, int pos, int val)
{
	int i = 0;
	PNODE p = pHead;

	//首先找到指向第pos-1个结点的指针p
	while (p != NULL && i < pos - 1)
	{
		p = p->pNext;
		++i;
	}

	if (i > pos - 1 || p == NULL)
	{
		return false;
	}

	//为要插入的节点开辟内存
	PNODE pNew = (PNODE)malloc(sizeof(PNODE));
	if (pNew == NULL)
	{
		printf("内存分配失败\n");
	}

	插入操作1
	//pNew->data = val;
	//PNODE q = p->pNext;
	//p->pNext = pNew;
	//pNew->pNext = q;

	//插入操作2
	pNew->data = val;
	pNew->pNext = p->pNext;
	p->pNext = pNew;



	return true;
}

bool delete_list(PNODE pHead, int pos, int* val)
{
	int i = 0;
	PNODE p = pHead;

	//首先找到指向第pos-1个结点的指针p
	while (p->pNext != NULL && i < pos - 1)
	{
		p = p->pNext;
		++i;
	}

	if (i > pos - 1 || p->pNext == NULL)
	{
		return false;
	}

	
	PNODE q = p->pNext;
	*val = q->data;

	//删除p结点后的结点
	p->pNext = p->pNext->pNext;
	free(q);
	q = NULL;

	return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值