数据结构~~单向链表

//链表结构的数据格式存储
#include "stdafx.h"//把这行放在最开始。

#include<string.h>
#include<iostream>
using namespace std;

typedef struct
{
	char key[10];
	char name[20];
	int age;
}Data;
typedef struct Node//这里与上面的不同是多了Node,注意如果没有这个Node,下面的struct Node*nextNode;就会报错说找不到这个Node。
{
	Data nodeData;
	struct Node*nextNode;//与上面的Node是配合用的。
}CLType;//这里的数据结构类型是CLType与上面的Data一样,而不该是Node!
CLType* CLAddEnd(CLType*head,Data nodeData);
void CLAllNode(CLType*head);
CLType*CLAddFirst(CLType*head,Data nodeData);
CLType*CLDeleteNode(CLType*head,char*key);
int CLLength(CLType*head);
CLType*CLInsertNode(CLType*head,char *findkey,Data nodeData);
CLType*CLFindNode(CLType*head,char*key);

int main()
{
	CLType*node,*head=NULL;//将头结点初始化为NULL,事实上这里是指向空内存。
	Data nodeData;
	char key[10];
	char findkey[10];
	int len=0;
	printf("链表测试。先输入链表中的数据,格式为:关键字 姓名 年龄\n");
	do
	{
		fflush(stdin);
		cin>>nodeData.key;
		if(strcmp(nodeData.key,"0")==0)
		{
			break;//输入了0则跳出do while(1)循环
		}
		else
		{
			cin>>nodeData.name>>nodeData.age;
			head=CLAddEnd(head,nodeData);//可以用指针作为左值,可见CLAddEnd(head,nodeData)必然是一个指针类型函数
		}
	}while(1);
	CLAllNode(head);//链表都是从头结点开始一个个去寻找的。
	
	
	printf("\n演示插入结点,输入插入位置的关键字:");
	cin>>findkey;
	printf("\n输入插入点的数据(关键字 姓名 年龄):");
	cin>>nodeData.key>>nodeData.name>>nodeData.age;
	head=CLInsertNode(head,findkey,nodeData);
	CLAllNode(head);
	
	printf("\n演示删除结点,输入要删除的关键字:");
	fflush(stdin);
	cin>>key;
	head=CLDeleteNode(head,key);//注意不是CLType*head
	CLAllNode(head);
	
	printf("\n演示插入头结点,输入插入点的数据(关键字 姓名 年龄):");
	fflush(stdin);
	cin>>nodeData.key>>nodeData.name>>nodeData.age;
	head=CLAddFirst(head,nodeData);
	CLAllNode(head);
	
	printf("\n演示计算结点长度:");
	
	len=CLLength(head);
	cout<<len;
	return 0;
}
CLType* CLAddEnd(CLType*head,Data nodeData)//返回一个CTLype类型的指针
{
	CLType*node,*htemp;//一个中间存储的指针node,一个暂时性头指针htmep;
	if(!(node=(CLType*)malloc(sizeof(CLType))))//sizeof(CLType)计算CLType这种数据结构需要多少内存,malloc(sizeof(CLType)),从内存池里面给划出一块内存
												//(CTLype*)初始化这块内存池,使之为CLType类型。node=(CTLype*)malloc(sizeof(CLType))把这一块内存池的地址赋给node;
												//!(node=(CTLype*)malloc(sizeof(CLType)))如果node等于0的时候进入if而当没有分配到内存的时候,就node就为0.
												//或者这里直接用if(!(malloc(sizeof(CLType))))就可以了。
	{
		printf("申请内存失败!\n");
		return NULL;//这个NULL 是返回给CTLype*CLAddEnd(CTLype*head,Data nodeData)的,可以理解为这个函数一直在等一个返回值,如果现在返回了,有值了就跳出。
		
	}
	else//其实这里是等效于if((node=(CTLype*)malloc(sizeof(CLType))))就是说能到这里说明malloc分配到了一块内存,并且这块内存叫node;
	{
		node->nodeData=nodeData;//函数第二个参数传递到这里
		node->nextNode=NULL;//因为这里是在最后添加的结点,所以这应该是最后一个结点,下一结点的地址理应是指向NULL
		if(head==NULL)//说明这个head来的时候,指向的是NULL 也就是它是头指针
		{
			head=node;//现在开始head有跟班了,它指向的地址是node不再是NULL,而node指向的是NULL;
			return head;//一直在等待返回一个地址值
		}
		//重要的代码,演示如何查找响应的信息。
		htemp=head;//让htemp来取代head,其实这里是等同于b=3;a=b;作用当head是头结点但不尾结点,也就是这不是空链表的时候。那么就该找到最后一个结点,标志就是nextNode=NULL
		while(htemp->nextNode!=NULL)//查找尾结点,当nextNode指向的不是NULL的时候,就不是尾结点,为了要继续查找,所以让遍历一般
		{
			htemp=htemp->nextNode;//把htemp指向的下一节点的地址赋给它本身,也就是约等于++htemp一样,指针往后移一个单位。
		}
		htemp->nextNode=node;//node是现在存放着尾结点的新添加结点,要把node所代表的地址传给原来链表的尾结点并取代掉所指向的地址NULL,
							//切注意这里不能用htemp=node,如此会是把原来的最后一个结点丢失,变成把node的地址传给原来的倒数第二个结点的nextNode
		return head;//还是要返回头结点,链表的特性就是要知道任何一个结点的位置都要从头结点开始,如此就需要返回头结点。
	}
}
void CLAllNode(CLType*head)
{
	CLType*htemp;
	htemp=head;//这里只是给以了头结点
	//while(htemp=htemp->nextNode)//这样会导致头结点不能被打印出来,因为一进来就是把第二个结点的地址发给htemp了,而头结点已经被过掉了.
	//{
	//	printf("结点(%s,%s,%d)\n",htemp->nodeData.key,htemp->nodeData.name,htemp->nodeData.age);
	//}
	while(htemp)
	{
		printf("结点(%s,%s,%d)\n",htemp->nodeData.key,htemp->nodeData.name,htemp->nodeData.age);
		htemp=htemp->nextNode;//把下结点的地址给htemp,但尾结点的地址不是NULL,所以能把尾结点打印出来,但打印出来后就结束了。
	}
}
//插入结点
CLType*CLInsertNode(CLType*head,char *findkey,Data nodeData)//插入结点,但要先分配内存,和查询是不是有这个结点,有这个结点时候再移动。
{
	CLType*node,*nodetemp;
	if(!(node=(CLType*)malloc(sizeof(CLType))))
	{
		printf("申请内存失败!\n");
		return 0;//这个情况下,整个函数到此结束	,不再往下进行。事实上我觉得这里应该是要返回head
	}
	node->nodeData=nodeData;//把新添加的数据放到新增加的内存的数据域里面(能运行到这里说明已经分配好内存了),
							//对于node这个内存而言,有两个域一个是放数据,一个放下一节点的地址,现在已经放了数据,但地址域还是空的
	nodetemp=CLFindNode(head,findkey);//上面步骤已经完成了申请内存和把数据存入新增加的内存中。接下来是要把这个内存放到链表中。
	if(nodetemp)//说明不为NULL 的情况下,那么就是找到了该节点,接下来就是要把node的地址放到nodetemp的nextNode中。注意node的地址域还是空的
	{
			node->nextNode=nodetemp->nextNode;//因为node是新申请的内存,其中node->nextNode还是空的,可以用来存放地址,
											//而且它现在插入来就是要取代tempnode的位置,原来由nodetemp->nextNode存放的地址现在该是转给它了。
			
			nodetemp->nextNode=node;//经过上一步,nodetemp->nextNode已经空了,而且它现在要做node前面的结点,
									//那么nodetemp->nextNode就该保存的是node的地址,注意千万不要把node与node->nextNode搞混淆
									//node代表的是当前结点的地址,而node->nextNode代表的是存放在node里的下一节点的地址
	}
	else//如果说没能找到这个结点
	{
		cout<<"未能找到该结点";
		free(node);//因为没有找到能插入的结点,数据无法插入,所以由上面申请到的结点该被释放掉。
	}
	return head;//返回头指针,
	
}
//查找结点
CLType*CLFindNode(CLType*head,char*key)//从头开始查找,查找无法是找到了,那么返回该结点的地址,要么没有找到返回一个NULL 或者是0
{
	CLType*htemp;//一般内部都是需要再定义一个临时指针,用来作为循环用
	htemp=head;//可以理解为初始化int a=3;
	while(htemp)
	{
		if(strcmp(htemp->nodeData.key,key)==0)//注意这里后面的key不用“key”是因为这里都是形参不是直接找“abs”之类
		{
			return htemp;
		}
		//能到这里说明strcmp(htemp->nodeData.key,key)已经搜过了,但不对。
		htemp=htemp->nextNode;//常用的循环方法,可以把htemp->nextNode去覆盖掉htemp里面的nextNode地址值,这样就能保证一直往下搜索
	}
	return NULL;//如果不能从if里面返回,那么到这里就说明没找到,要返回NULL
}
//删除结点
CLType*CLDeleteNode(CLType*head,char*key)//要删除结点,首先得确定有没有这个结点,有这个结点的情况下,
								//把它删除后,那么它保存的nextNode要给到他前面的结点,如果可以直接覆盖那么就不需要再申请指针。但是要循环就得暂时指针
{
	CLType*htemp;
	CLType*node;
	htemp=head;
	node=head;
	while(htemp)
	{
		if(strcmp(htemp->nodeData.key,key)==0)//注意这里后面的key不用“key”是因为这里都是形参不是直接找“abs”之类
		{
			node->nextNode=htemp->nextNode;//找到了这个结点,就是htemp,但是不能直接删除,要先把保留在它那里的地址拿出来。存放中中间量中
											//真的从这里看出来,node=head只是初始化,而且可以被覆盖。而且如果第一次就进来只能说明
			free(htemp);
			return head;
		}
		node=htemp;//不断更新htemp前结点,这里是用node来存放要删除结点前面的一个结点的。
		htemp=htemp->nextNode;
	
	}
	return head;
}
//计算链表长度
int CLLength(CLType*head)//拿一个来计算,然后遍历一遍就好了
{
	CLType*htmep;
	int i=0;
	htmep=head;
	while(htmep)
	{
		i++;
		htmep=htmep->nextNode;
	}
	return i;
}
//插入头结点
CLType*CLAddFirst(CLType*head,Data nodeData)//插入头结点,那么就需要先分配一块内存,然后再把头结点的内存给到它就好了。
{		
	CLType*node;
	if(!(node=(CLType*)malloc(sizeof(CLType))))
	{
		printf("申请内存失败!\n");
		return NULL;//这个情况下,整个函数到此结束	,不再往下进行。事实上我觉得这里应该是要返回head
	}
	
	node->nodeData=nodeData;
	node->nextNode=head;
	return node;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值