详解C++中链表的基本操作

利用链表操作实现的链表数据管理系统:

#include<iostream>
#include "myfun.h"
using namespace std;
enum Status{
	OK = true,
	ERROR = false
};
typedef struct LNode{
	int data;
	LNode* next;	
}L,*LinkList;
Status Print_LS(LinkList L);
Status Create_LS(LinkList L,const int N);
void Init_L(LinkList L);
Status Insert_LS(LinkList& L,const int i);
Status Delete_LS(LinkList& L,const int i);
Status Search_LS(LinkList L,const int data,int& e);
Status Change_LS(LinkList& L,const int data1,const int data2);

int main(void){
	cout << "程序规则如下:" << endl;
	cout << "1.链表值为1~100之间的随机数" << endl;
	cout << "2.输入show:则输出链表" << endl;
	cout << "3.输入insert i:则在i下标后插入一个随机数" << endl;
	cout << "4.输入delete i:则删除第i个元素(注意不是下标)" << endl;
	cout << "5.输入search n:则输出n在链表中的下标" << endl;
	cout << "6.输入change m n:则将链表中的元素m改为n" << endl;
	srand(time(0));
	LinkList L = new LNode;
	Init_L(L);
	Create_LS(L,9);					//在初始节点后面插入 9 个节点 
	Print_LS(L);
	string str;
	cout << "请输入操作指令:";
	while (cin >> str){
		if (str == "show"){
			Print_LS(L);
			cout << "********************" << endl;
		}
		else if (str == "insert"){
			int i;cin >> i;
			if (Insert_LS(L,i)){
				cout << "insert OK" << endl;
				cout << "********************" << endl;
			}
			else{
				cout << "insert fail!" << endl;
				cout << "********************" << endl;
			}
		}
		else if (str == "delete"){
			int i;cin >> i;
			if (Delete_LS(L,i)){
				cout << "delete OK" << endl;
			}
			else{
				cout << "delete fail!" << endl;
			}
		}
		else if (str == "search"){
			int data,e;
			cin >> data;
			if (Search_LS(L,data,e)){
				cout << "search OK!\nThe Index: " << e << endl;
			}
			else{
				cout << "search fail!" << endl;
			}
			cout << "********************" << endl;
		}
		else if (str == "change"){
			int data1,data2;
			cin >> data1 >> data2;
			if (Change_LS(L,data1,data2)){
				cout << "change OK" << endl;
			}
			else {
				cout << "change fail!" << endl;
			}
			cout << "********************" << endl;
		}
		cout << "请输入操作指令:"; 
	}
	return 1;
};



void Init_L(LinkList L){
	L->data = randint(1,100);
	L->next = NULL;
}
Status Print_LS(LinkList L){
	LinkList p = L;
	int i = 0;
	cout << "元素:";
	while (p){
		i++;
		printf("%-3d",p->data);
		p = p->next;
	}
	cout << endl;
	cout << "索引:";
	for (int j=0;j<i;j++){
		printf("%-3d",j);
	}
	cout << endl;
	cout << "序号:";
	for (int j=0;j<i;j++){
		printf("%-3d",j+1);
	}
	cout << endl;
	return OK;
}
Status Search_LS(LinkList L,const int data,int& e){		//寻找第一个出现data的下标 
	int i = 0;
	LinkList cur = L;
	while (cur){
		if (cur->data == data){
			break;
		}
		i++;
		cur = cur->next;
	}
	if (!cur){
		return ERROR;
	}
	e = i;
	return OK; 
}
Status Create_LS(LinkList L,const int N){
	LinkList p,cur;
    p = L;
	cur = L;
	cout << "随机生成链表成功!" << endl;
	for (int i=0;i<N;i++){
		p = new LNode;
		p->data = randint(1,100);
		cur->next = p;
		cur = p;
	}
	if (cur == NULL){
		return ERROR;
	}
	p->next = NULL;
	return OK;
}
Status Insert_LS(LinkList& L,const int i){
	int j = 0;
	LinkList cur = L;
	if (i < 1){
		LinkList newL = new LNode;
		Init_L(newL);
		newL->next = L;
		L = newL;
		return OK;
	}
	while (j < i-1 && cur->next){
		cur = cur->next;
		j++;
	}
	LinkList newL = new LNode;
	Init_L(newL);
	newL->next = cur->next;
	cur->next = newL;
	return OK;
}
Status Delete_LS(LinkList& L,const int i){
	int j = 0;
	LinkList cur = L;
	if (i < 1){
		return ERROR;
	}
	else if(i == 1){
		L = cur->next;
		delete cur;
		return OK;
	}
	while (j < i-2){
		if (!(cur->next->next)){			//一个神奇的判断越界魔法代码<( ̄︶ ̄)↗ 
			return ERROR;
		}
		cur = cur->next;
		j++;
	}
	LinkList delCur = cur->next;
	cur->next = delCur->next;
	delete delCur;
	return OK;
}
Status Change_LS(LinkList& L,const int data1,const int data2){
	LinkList cur = L;
	while (cur){
		if (cur->data == data1){
			cur->data = data2;				//改 
			return OK;
		}
	}
	return ERROR;
}


myfun.h头文件往下翻 👇👇👇

以上为项目完整代码,是不是很简单呢?(doge)🐕🐕🐕

★★★★★★下面进行解析: 


★☆☆☆☆☆一、链表的创建

初始化代码省略.

Status Create_LS(LinkList L,const int N){
	LinkList p,cur;                            //用双指针进行动态分配
	cur = L;            
	cout << "随机生成链表成功!" << endl;   
	for (int i=0;i<N;i++){
		p = new LNode;                          //用p创建一个新的指针
		p->data = randint(1,100);               //初始化新节点的值[1,100]
		cur->next = p;                          //让链表最后一个节点指向新的节点
		cur = p;                                //更新链表最后一个节点
	}
	if (cur == NULL){                           //这段代码没用可以不写
		return ERROR;
	}
	p->next = NULL;                              //最后一个节点指向空代表结束
	return OK;
}

 ☆★☆☆☆☆二、链表的打印

Status Print_LS(LinkList L){
	LinkList p = L;
	int i = 0;                            //累加器用于求链表中元素数量
	cout << "元素:";
	while (p){                            //只要指针不为空就打印
		i++;
		printf("%-3d",p->data);
		p = p->next;                      //指针指向下一个链表节点
	}
	cout << endl;
	cout << "索引:";                     //格式化输出打印索引
	for (int j=0;j<i;j++){
		printf("%-3d",j);
	}
	cout << endl;
	cout << "序号:";                     //格式化输出打印序号
	for (int j=0;j<i;j++){
		printf("%-3d",j+1);
	}
	cout << endl;
	return OK;                           //返回状态(成功)
}

☆☆★☆☆☆三、链表的查找 

Status Search_LS(LinkList L,const int data,int& e){		//寻找第一个出现data的下标
	int i = 0;                                //i先记录为元素索引
	LinkList cur = L;                         //指针指向头节点
	while (cur){
		if (cur->data == data){               //只要找到要查找的元素就退出循环
			break;
		}
		i++;                                  //没有找到下标增加
		cur = cur->next;                      //指针指向下一个节点元素
	}                                           
	if (!cur){
		return ERROR;                         //如果找了一圈指针最后指向空说明没有找到
	}                                         //所以返回错误
	e = i;
	return OK;                                //没有错误就是成功咯~
}

 不难看出,i 的下标和 cur 所指向的节点是同步增加的,i 就是 cur 所指向节点的下标


☆☆☆★☆☆四、链表的插入

Status Insert_LS(LinkList& L,const int i){    //在链表的第 i 个位置后插入新的节点
	int j = 0;                                //j开始时指向第一个节点的下标索引
	LinkList cur = L;                         //cur指向第一个节点
	if (i < 1){                               //如果要插入的节点在头节点的前面则单独处理
		LinkList newL = new LNode;            //在内存中分配一个新的节点用newL指向它
		Init_L(newL);                         //初始化新节点的数据
		newL->next = L;                       //头插法:新节点指向我们的头节点
		L = newL;                             //别忘记更改头节点,传入L指针的引用的作用
		return OK;                            //返回修改成功
	}
	while (j < i-1 && cur->next){             
  //不需要头插的情况,如果cur下一个节点为空(说明给的下标超过长
                                                        //度了,但是我们照样插入到最后面
		cur = cur->next;                      //指针指向下一个节点
		j++;                                  //j索引往后移动
	}                                         //循环结束cur指向需要插入的节点位置
	LinkList newL = new LNode;                //新建一个孤儿节点(因为此时它和链表无关)
	Init_L(newL);                             //初始化节点数据
	newL->next = cur->next;                   //新的节点指向我们要插入的节点的下一个节点
	cur->next = newL;                         //再让我们的节点指向新的节点,完成插入!
	return OK;                                //返回插入成功的状态->true
}

Tips:插入的时候要注意两种情况:

1.插在头节点前,则要更新我们的头节点,这里参数传入的是指针的引用就是为了这一步,否则函数会生成一个指针的副本,对指针进行的修改会失效(函数种传入指针只能够修改指针所指的地址的数据,而指针本身和传入普通变量一样都是副本)。

2.插入的位置超出我们的链表长度了,那么这时我们使用(cur->next)传入判断,如果为下一个是空节点就不继续往下走了,然后我们的指针会留在最后一个节点,直接插就完事了。

注意:这里实际上可以单独判断,然后返回ERROR来报错,但是我就不这么做了。


☆☆☆☆★☆五、链表的删除 

Status Delete_LS(LinkList& L,const int i){
	int j = 0;                              //老样子,j为第一个节点的下标
	LinkList cur = L;                       //老样子,链表指针指向第一个节点
	if (i < 1){
		return ERROR;                       //如果删除的位置非法,即<=0,返回错误
	}
	else if(i == 1){                        //如果删除的是头节点
		L = cur->next;                      //头节点往后移动一下就行
		delete cur;                         //同时也别忘记释放被删除的节点内存
		return OK;                          //返回删除成功
	}
	while (j < i-2){                        //i-1是要删除节点的下标,i-2为删除节点前节点
		if (!(cur->next->next)){			//一个神奇的判断越界魔法代码<( ̄︶ ̄)↗ 
			return ERROR;                   //在纸上画出整个链表演算一遍你就明白了!!
		}
		cur = cur->next;                    //指针后移
		j++;                                //索引同步后移
	}
	LinkList delCur = cur->next;            //循环结束后cur的位置是删除节点的前节点
	                                        //delCur就是cur的下一个节点
    cur->next = delCur->next;               //让被删的前节点指向它的下一个节点
	delete delCur;                          //释放被删节点分配的内存
	return OK;                              //返回成功
}

 链表的删除就是,让被删的节点的前节点指向其下一个节点,从而让它从链表中剔除。


☆☆☆☆☆★六、链表的修改

Status Change_LS(LinkList& L,const int data1,const int data2){
	LinkList cur = L;                       //初始化cur,指向头节点
	while (cur){                            //如果cur指针不为空
		if (cur->data == data1){            //如果节点数据等于需要改的元素
			cur->data = data2;				//修改链表元素
			return OK;                      //返回成功并结束函数
		}
	}                                       //结束循环,cur指向NULL说明没找到
	return ERROR;                           //返回查找失败
}

其他定义与函数:

enum Status{                         //枚举型定义状态
	OK = true,                       //注意bool类型属于C++,C中可以用1/0来替代
	ERROR = false
};

            
typedef struct LNode{                //链表节点的定义
	int data;
	LNode* next;	
}L,*LinkList;                        //给指针型和节点型各起一个别名用来使用


void Init_L(LinkList L){             //给一个节点进行初始化
	L->data = randint(1,100);
	L->next = NULL;
}


 myfun.h头文件的代码:

#include<stdlib.h>                   //stdlib.h用来使用rand()生成随机数
#include<ctime>                      //时间库,用来在主函数中生成时间种子
#include<iostream>
int randint(int a,int b){            //相当于Python中random库中的randint(a,b)
	return rand()%(b-a+1)+a;         //返回一个在[a,b]范围内的整数
}

main函数主体:

int main(void){
//程序开始时输出提示
	cout << "程序规则如下:" << endl;
	cout << "1.链表值为1~100之间的随机数" << endl;
	cout << "2.输入show:则输出链表" << endl;
	cout << "3.输入insert i:则在i下标后插入一个随机数" << endl;
	cout << "4.输入delete i:则删除第i个元素(注意不是下标)" << endl;
	cout << "5.输入search n:则输出n在链表中的下标" << endl;
	cout << "6.输入change m n:则将链表中的元素m改为n" << endl;

/***生成一个时间种子来达到伪随机的效果***/

	srand(time(0));

	LinkList L = new LNode;         //为链表第一个数据分配空间
	Init_L(L);                      //初始化链表
	Create_LS(L,9);					//在初始节点后面插入 9 个随机生成值的节点 
	Print_LS(L);                    //先打印一遍我们随机生成的链表看看
	string str;                     //字符类存放输入的指令
	cout << "请输入操作指令:";
	while (cin >> str){             //一直输入除非EOF
		if (str == "show"){                                //根据输入的指令选择操作
			Print_LS(L);
			cout << "********************" << endl;
		}
		else if (str == "insert"){
			int i;cin >> i;
			if (Insert_LS(L,i)){
				cout << "insert OK" << endl;
				cout << "********************" << endl;
			}
			else{
				cout << "insert fail!" << endl;
				cout << "********************" << endl;
			}
		}
		else if (str == "delete"){
			int i;cin >> i;
			if (Delete_LS(L,i)){
				cout << "delete OK" << endl;
			}
			else{
				cout << "delete fail!" << endl;
			}
		}
		else if (str == "search"){
			int data,e;
			cin >> data;
			if (Search_LS(L,data,e)){
				cout << "search OK!\nThe Index: " << e << endl;
			}
			else{
				cout << "search fail!" << endl;
			}
			cout << "********************" << endl;
		}
		else if (str == "change"){
			int data1,data2;
			cin >> data1 >> data2;
			if (Change_LS(L,data1,data2)){
				cout << "change OK" << endl;
			}
			else {
				cout << "change fail!" << endl;
			}
			cout << "********************" << endl;
		}
		cout << "请输入操作指令:"; 
	}
	return 1;
};

 以上就是C++中链表操作的基本内容了,实际上也可以面向对象来实现,

但是一般选择结构体来实现较为便捷高效。

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
c语言链表基本操作包括创建链表、插入元素、删除元素、读取链表和销毁链表。在给出具体操作之前,我先解释一下引用内容的代码。 引用\[1\]的代码是作者在学习数据结构时遇到的问题和解决方法。作者通过重新学习C语言和指针相关的知识,成功地理解了指针的概念,并能够使用C语言实现数据结构的算法。 引用\[2\]的代码是作者在解决链表内存访问冲突问题时采用的二级指针的方法。作者通过使用二级指针,解决了链表创建后内存访问冲突的问题。 引用\[3\]的代码是一个主函数,用于测试链表基本操作功能。其包括创建链表、读取链表、插入元素、删除元素和销毁链表等操作。 现在我来回答你的问题,c语言链表基本操作如下: 1. 创建链表:创建一个头结点为head的链表。可以通过申请内存空间来创建链表,并将头结点的指针赋值给head。 2. 插入元素:在链表指定的结点前插入元素e。可以通过遍历链表找到指定的结点,然后创建一个新的结点,并将新结点的指针指向指定结点的下一个结点,再将指定结点的指针指向新结点。 3. 删除元素:删除链表指定的结点。可以通过遍历链表找到指定的结点,然后将指定结点的前一个结点的指针指向指定结点的下一个结点,再释放指定结点的内存空间。 4. 读取链表:读取链表的数据域并打印。可以通过遍历链表,依次读取每个结点的数据域,并将其打印出来。 5. 销毁链表:释放为链表申请的内存空间。可以通过遍历链表,依次释放每个结点的内存空间。 以上就是c语言链表基本操作。希望对你有帮助! #### 引用[.reference_title] - *1* *2* *3* [C语言实现链表基本操作(超详细注释)](https://blog.csdn.net/weixin_63069485/article/details/123784826)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值