链表结构及操作

什么是链表结构:

  链表结构是由许多节点构成的,每个节点都包含两部分:

  1.   数据部分:保存该节点的实际数据。
  2.   地址部分:保存的是下一个节点的地址。

链表的特点:

  1. 结点在存储器中的位置是任意的,即逻辑上相邻的数 据元素在物理上不一定相邻
  2. 访问时只能通过头指针进入链表,并通过每个结点的 指针域向后扫描其余结点,所以寻找第一个结点和最后一 个结点所花费的时间不等

链表的优点:

  1. 数据元素的个数可以自由扩充 、插入、删除等操作不必移动数据,只需 修改链接指针,修改效率较

 

链表的缺点:

  1. 存储密度小 、存取效率不高,必须采用顺序存取,即存 取数据元素时,只能按链表的顺序进行访问 

 

 

在进行链表操作时,首先需要定义一个头指针变量(head表示),该指针变量指向链表的第一个节点。

最后一个节点不再指向其他节点(单链表),称为表尾。

 

单链表:

  1. 像上面的链式结构一样,每个节点包含一个指针指向下一个节点。

链表数据表示:

typedef struct
{
	char key[10];              //关键字
	char name[20];
	int age;
}Data;                         //数据节点类型

typedef struct Node
{
	Data nodeData;             //数据域
	struct Node *nextNode;     //指针域
}CLType;

 

添加节点步骤:

  1. 单链表节点添加可以在任意位置插入,且不需要移动数据元素,只需修改链表的指针域即可。插入时间复杂度为O(1)。
  2. 首先分配内存空间,保存新增节点。
  3. 从头指针 head 开始逐个检查,直到找到要插入的位置。
  4. 将插入节点前一个节点指针指向要插入的节点地址,在修改当前节点指针域指向下一个节点地址,把链表连接起来。
  5. 若插入位置为表尾,则把节点指针域置为空(NULL)。

   添加链表实现代码:

//在链表尾添加节点
CLType *CLAddEnd(CLType *head, Data nodeData)
{
	CLType *node, *htemp;
	node = new CLType;
	if (!node)
	{
		std::cout << "内存申请失败." << std::endl;
		return NULL;
	}
	else
	{
		node->nodeData = nodeData;      //保存数据
		node->nextNode = nullptr;       //将节点置为NULL,当前插入位置为表尾
		if (head == nullptr)
		{
			head = node;                
			return head;
		}
		htemp = head;
		while (htemp->nextNode != nullptr)      //查找链表的末尾
		{
			htemp = htemp->nextNode;
		}
		htemp->nextNode = node;                 //修改指针域把链表连接起来
		return head;
	}
}

在链表头插入头节点步骤:

  1 .首先分配内存空间,保存新增节点。

  2 .使新增节点指向头指针 head所指向的节点。

  3 .然后使头指针 head指向新增节点。

//在链表头插入节点
CLType *CLAddFirst(CLType *head, Data nodedata)
{
	CLType *node = new CLType;
	if (!node)                              //内存分配失败
	{
		std::cout << "内存申请失败!" << std::endl;
		return nullptr;
	}
	else
	{
		node->nodeData = nodedata;           //保存数据
		node->nextNode = head;               //指向头指针所指节点
		head = node;                         //头指针指向新增节点
		return head;
	}
}

 

查找节点:

  

 

//查找节点
CLType *CLFindNode(CLType *head, char *key)
{
	CLType *htemp;
	htemp = head;                                //保存链表头指针
	while (htemp)                                //若节点有效,则进行循环查找
	{
		if (strcmp(htemp->nodeData.key, key) == 0)     //若节点关键字与传入关键字相同
		{
			return htemp;                     //return 该节点指针
		}
		htemp = htemp->nextNode;                //进行迭代查找
	}
	return nullptr;                             //不存在,返回空指针
}

 

随机插入节点步骤:

 1 .首先分配内存,保存新增节点。

 2 .找到要插入的逻辑位置,也就是要插入某两个节点之间。

 3 .修改插入位置的节点指针,使其指向新增节点,而使新增节点指向原插入位置所指向的节点

 

//随机插入节点
CLType *CLinsertNode(CLType *head, char *findkey, Data nodedata)
{
	CLType *node, *nodetemp;                  
	node = new CLType;                 //分配保存的节点内存
	if (!node)                         //内存分配失败
	{
		std::cout << "内存申请失败." << std::endl;   
		return nullptr;
	}
	node->nodeData = nodedata;         //保存节点中的数据
	nodetemp = CLFindNode(head, findkey);         
	if (nodetemp)                      //若找到要插入的节点
	{
		node->nextNode = nodetemp->nextNode;      //新插入节点指向关键节点的下一节点
		nodetemp->nextNode = node;                //设置关键节点指向新插入节点
	}
	else
	{
		std::cout << "未找到正确的插入位置." << std::endl;
		delete node;                  //释放内存
	}
	return head;                      //返回头指针
}

 删除节点步骤:

 1 .查找要删除的节点

 2 .使前一节点指向当前节点下一节点

 3 .删除节点

//删除节点
int CLDeleteNode(CLType *head, char *key)
{
	CLType *node, *htemp;       //node保存删除节点的前一节点
	htemp = head;
	node = head;
	while (htemp)
	{
		if (strcmp(htemp->nodeData.key, key) == 0)   //找到关键字,执行删除操作
		{
			node->nextNode = htemp->nextNode;        //使前一节点指向当前节点的下一节点
			delete htemp;                            //释放内存
			return 1;
		}
		else
		{
			node = htemp;                  //指向当前节点
			htemp = htemp->nextNode;      //指向下一节点
		}
	}
	return 0;                            //删除失败
}

 

计算链表长度


//计算链表长度
int CLLength(CLType *head)
{
	CLType *htemp;
	int len = 0;
	htemp = head;
	while (htemp)    //遍历链表
	{
		len++;       //累计节点数
		htemp = htemp->nextNode;   //处理下一节点
	}
	return len;          //return 节点数
}

 

显示所有节点:

//显示所有节点
void CLAllNode(CLType *head)
{
	CLType *htemp;
	Data nodeData;
	htemp = head;
	std::cout << "当前链表共有: " << CLLength(head) << "个节点,链表数据如下: "<<std::endl;
	while (htemp)
	{
		nodeData = htemp->nodeData;
		std::cout << "节点: " << nodeData.key << " " << nodeData.name << "  " << nodeData.age << std::endl;
		htemp = htemp->nextNode;
	}
}

 

main 函数:

int main()
{
	CLType *node, *head = nullptr;
	Data nodeData;
	char key[10], findkey[10];

	cout << "请输入链表中的数据,格式为: 关键字 姓名 年龄 " << endl;
	do {
		cin >> nodeData.key;
		if (strcmp(nodeData.key, "0") == 0)
			break;              //若输入为0,则退出
		else
		{
			cin >> nodeData.name>>nodeData.age;
			head = CLAddEnd(head, nodeData);
		}
	} while (1);
	CLAllNode(head);

	cout << " 输入插入位置的关键字: ";
	cin >> findkey;
	cout << "输入插入节点的数据(关键字 姓名 年龄 ): \n";
	cin >> nodeData.key >> nodeData.name >> nodeData.age;
	head = CLinsertNode(head, findkey, nodeData);
	CLAllNode(head);

	cout << "删除节点,输入要删除的关键字: " << endl;
	cin >> key;
	CLDeleteNode(head, key);
	CLAllNode(head);

	cout << "查找关键字,输入要查找的关键字: " << endl;
	cin >> key;
	node = CLFindNode(head, key);
	if (node)
	{
		nodeData = node->nodeData;
		cout << "关键字" << key << " 对应的节点为" << key << nodeData.key << nodeData.name << nodeData.age;
	}
	else
	{
		cout << "未找到关键字";
	}

	cout << endl;
	system("pause");
	return 0;
}

 

测试结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值