数据结构(C语言版)
参考郝斌老师C语言版数据结构笔记
链表
离散存储【链表】
定义:
n个节点离散分配
彼此通过指针相连
每个节点只有一个前驱节点,每个节点只有一个后续节点
首节点没有前驱节点,尾节点没有后续节点。
专业术语:
首节点:
第一个有效节点
尾节点:
最后一个有效节点
头结点:
头结点的数据类型和首节点的类型一样
没有存放有效数据,最最前面的,是在
首节点之前的,主要是为了方便对链表
的操作。
头指针:(指向头)
指向头节点的指针变量
尾指针:
指向尾节点的指针
(头结点有可能很大,占的内存可能大,假设我想造一个函数
输出所有链表的值,那你如果不用头指针类型做形参,那由于
不同链表的头节点不一样大小,这样就没办法找出形参)
确定一个链表需要几个参数:(或者说如果期望一个函数对链表进行操作
我们至少需要接收链表的那些信息???)
只需要一个参数:头指针,因为通过它我们可以推出
链表的所有信息。
(链表的程序最好一定要自己敲出来)
分类:单链表 双链表:每一个节点有两个指针域 循环链表:能通过任何一个节点找到其他所有的节点 非循环链表
(java中变成垃圾内存则会自动释放,但是C和C++则不会,所以要 手动释放,否则会引起内存泄露。delete等于free)
算法:遍历 查找 清空 销毁 求长度 排序 删除节点 插入节点算法:狭义的算法是与数据的存储方式密切相关
广义的算法是与数据的存储方式无关
泛型:(给你一种假象,只不过牛人从内部都弄好了)
利用某种技术达到的效果就是:不同的存储方式,执行的操作是一样的
算法的真正学法:很多算法你根本解决不了!因为很多都属于数学上的东西,所以我们把答案找出来,如果能看懂就行,但是大部分人又看不懂,分三步,按照流程,语句,试数。这个过程肯定会不断地出错,所以不断出错,不断改错,这样反复敲很多次,才能有个提高。实在看不懂
就先背会。
链表的优缺点:
优点:
空间没有限制
插入删除元素很快
缺点:
存取速度很慢。
单向链表
本人在学习郝斌老师数据结构后进行了单链表代码的敲写,功能和函数以及代码与老师的可能稍有不同,本人在Microsoft Visual c++ 2010 的环境上相关操作均测试通过,相关操作和代码如下:
链表相关操作:
1、初始化一个链表
2、在链表末尾添加节点
3、在指定的位置插入结点
4、删除链表末尾节点
5、删除指定位置的节点
6、修改指定节点的值
7、链表的遍历
8、获取链表长度
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
author:喜庆
date:2021年5月31日 16点58分
*/
struct Node
{
int value;
struct Node * Next;
};
typedef struct Node NODE;
//链表的创建
NODE * createList();
//在指定的位置插入结点
void insert(NODE * pHead,int pos,int nValue);
//在链表末尾添加节点
void append(NODE * pHead,int value);
//删除指定位置的节点
int deleteNode(NODE * pHead,int pos);
//删除链表末尾节点
int pop(NODE * pHead);
//修改指定节点的值
int alterNodeValue(NODE * pHead,int pos,int nValue);
//链表的遍历
void traverseList(NODE * pHead);
//获取链表长度
int len(NODE * pHead);
int main(void)
{
//链表的创建
NODE * pHead = createList();
//查看链表长度
printf("链表长度len=%d\n",len(pHead));
//链表的遍历
traverseList(pHead);
//insert(pHead,2,6);
append(pHead,6);
append(pHead,6);
traverseList(pHead);
printf("deleteValue:%d\n",deleteNode(pHead,3));
traverseList(pHead);
//删除链表末尾节点
printf("popValue:%d\n",pop(pHead));
traverseList(pHead);
printf("preValue:%d\n",alterNodeValue(pHead,3,3));
traverseList(pHead);
return 0;
}
//链表的创建
NODE * createList()
{
int len = -1;
int i;
NODE * pHead = (NODE *) malloc(sizeof(NODE));
NODE * p1 = NULL;
NODE * p2 = NULL;
pHead->Next = NULL;
pHead->value = NULL;
printf("请输入要创建的链表的大小:\n");
scanf("%d",&len);
for(i=0;i<len;i++)
{
int value;
p1 = (NODE *) malloc(sizeof(NODE));
if(p1 == NULL)
{
printf("分配内存失败,请重试!");
exit(-1);
}
printf("输入%d个节点的值:\n",i+1);
scanf("%d",&value);
p1->value = value;
if(NULL == pHead->Next)
{
pHead->Next = p1;
//将链表的大小存放到头结点的值中
pHead->value = len;
p2 = p1;
}else{
p2->Next = p1;
p2 = p1;
}
value = NULL;
}
p2->Next = NULL;
return pHead;
}
//在指定的位置插入结点
void insert(NODE * pHead,int pos,int nValue)
{
int i ;
int size = len(pHead);
NODE * p1 = NULL;
NODE * p2 = NULL;
//创建新的节点
NODE * pNew = (NODE *) malloc(sizeof(NODE));
pNew->value = nValue;
p1 = pHead;
if (pHead == NULL || pos == NULL|| nValue == NULL){
printf("头结点或者插入指定位置或者插入值不能为空!");
exit(-1);
}
for (i=0;i<size;i++){
//获取当前节点
p1 = p1->Next;
if (i == pos-1){
//上个节点p2指向新节点pNew
p2->Next = pNew;
//当前节点向后移,新节点插入到当前位置并指向当前节点。
pNew->Next = p1;
//头节点存储的链表长度加一
++pHead->value;
}
if(i > pos-1){
break;
}
//将当前节点作为上个节点赋值给p2
p2 = p1;
}
}
//在链表末尾添加节点
void append(NODE * pHead,int value)
{
int size = -1;
int i;
NODE * p1 = NULL;
NODE * pNew = (NODE * )malloc(sizeof(NODE));
p1 = pHead;
pNew->value = value;
size = len(pHead);
for (i=0;i<size;i++)
{
p1 = p1->Next;
if(p1->Next == NULL)
{
p1->Next = pNew;
pNew->Next = NULL;
++pHead->value;
}
}
}
//在指定位置删除节点
int deleteNode(NODE * pHead,int pos)
{
int i ;
int size = -1;
int deleteValue = -1;
NODE * p1 = NULL;
NODE * p2 = NULL;
p1 = pHead;
if (pHead == NULL || pos == NULL){
printf("头结点或者删除节点的位置不能为空!");
exit(-1);
}
size = len(pHead);
for (i=0;i<size;i++){
//获取当前节点
p1 = p1->Next;
if (i == pos-1){
//上个节点p2指向当前要删除节点的下一个节点
p2->Next = p1->Next;
//释放掉当前节点内存
deleteValue = p1->value;
free(p1);
//头节点存储的链表长度减一
--pHead->value;
}
if(i > pos-1){
break;
}
//将当前节点作为上个节点赋值给p2
p2 = p1;
}
return deleteValue;
}
//删除链表末尾节点
int pop(NODE * pHead)
{
NODE * p1 = NULL;
NODE * p2 = NULL;
int popValue = -1;
int i;
int size = len(pHead);
p1 = pHead;
for (i=0;i<size;i++)
{
p1 = p1->Next;
if(p1->Next == NULL)
{
p2->Next = NULL;
popValue = p1->value;
free(p1);
--pHead->value;
}
p2 = p1;
}
return popValue;
}
//修改指定节点的值
int alterNodeValue(NODE * pHead,int pos,int nValue)
{
int i ;
int preValue = -1;
int size = -1;
NODE * p1 = NULL;
p1 = pHead;
if (pHead == NULL || pos == NULL|| nValue == NULL){
printf("头结点或者修改节点的位置或新更新的值不能为空!");
exit(-1);
}
size = len(pHead);
for (i=0;i<size;i++){
//获取当前节点
p1 = p1->Next;
if (i == pos-1){
preValue = p1->value;
p1->value = nValue;
}
if(i > pos-1){
break;
}
}
return preValue;
}
//链表的遍历
void traverseList(NODE * pHead)
{
NODE * p = NULL;
p = pHead->Next;
printf("链表的大小为:%d\n",pHead->value);
while(p != NULL)
{
printf("%d ",p->value);
p = p->Next;
}
printf("\n");
}
//获取链表长度
int len(NODE * pHead)
{
int len = 0;
NODE * p1 = pHead;
if(pHead == NULL)
{
printf("头结点不能为空");
exit(-1);
}
while(p1->Next != NULL)
{
p1=p1->Next;
len++;
}
return len;
}
这段代码是本人在学习数据结构过程中为方便以后复习所记录的一篇笔记,如果笔记中有疏漏之处还请各位同学提醒,以便及时改正!
本文介绍了C语言中链表数据结构的基础知识,包括链表的定义、分类和常见操作如遍历、查找、插入、删除等。提供了一段完整的单链表实现代码,包括链表初始化、在指定位置插入、删除节点、修改节点值等功能,并附带了测试用例。文章强调了链表在内存管理和操作效率上的优缺点,以及手动内存管理的重要性。
&spm=1001.2101.3001.5002&articleId=117420926&d=1&t=3&u=b8a56b5308ff44e491f4074a42aa857c)

被折叠的 条评论
为什么被折叠?



