数据结构之单链表(c++(c语言)通用版)

我们创建一个长度为n的链表时,可以采取头插法创建或者尾插法创建,本篇博客我们采取头插法来创建,(作者只学了头插,尾插等以后来补qwq,补上喽)。

头插原理

我们先来画图来看看头插的创建形式把,会了原理再写代码。

首先是我们的一号和二号节点,我们发现他们是相连的。现在我们使用头插法创建链表要怎么做呢,其实很简单,头插就是把我们新创建的节点放到最前面,我们每次都把创建的节点放到最前面,也就是1好节点的后面。大家注意了,这个一号节点不要存储任何数据或者(这能存储链表的长度信息,)它是我们的头节点。我们创建它只是为了好遍历以后的节点信息。

看图:

我们把一号节点的next地址连接到三号节点,三号的next地址连接到2号节点上,这就是头插。

上代码解释:

头插详细代码

void InitList(LinkedList a,int n){
	int e;
	for(e=0;e<n;e++){
		Lnode *b=(Lnode*)malloc(sizeof(Lnode));
		b->a=e;
		b->next=a->next;
		a->next=b;
	}
}
//a号节点是指向节点,我们之后创建的节点都是不断放在a号节点的后面,a号节点只是用来方便遍历。
//我们创建一个b节点,并为他的数据域赋予数值,接着,我们令b号节点链接a号节点链接的节点,并使得a号节点可以连接到b号节点。
//如果是一开始,只有指向a号节点,我们就相当于创建一个尾节点,指向空,令a号节点联系到尾节点

结构体代码:

typedef struct Lnode{
	int a;
	struct Lnode* next;
}Lnode,*LinkedList;//创建结构体,把结构体的别名起为Lnode
//把结构体Lnode的指针起名为LinkedList
//学过Java的同学是不是DNA动了呢qwq

创建指向节点的代码:

void test(){
	LinkedList a=(LinkedList)malloc(sizeof(Lnode));//动态开辟空间

	a->next=NULL;//令指向节点的next指向域为NULL
	int b;
	cin>>b;//输入链表的长度
	InitList(a,b);
	for(int c=0;c<b;c++){//打印验证成果
		a=a->next;
		cout<<a->a<<endl;
	}
	free(a);//释放a的空间
}

头插总代码详细代码:

#include<bits/stdc++.h>
using namespace std;
typedef struct Lnode{
	int a;
	struct Lnode* next;
}Lnode,*LinkedList;
void InitList(LinkedList a,int n){
	int e;
	for(e=0;e<n;e++){
		Lnode *b=(Lnode*)malloc(sizeof(Lnode));
		b->a=e;
		b->next=a->next;
		a->next=b;
	}
}
void test(){
	LinkedList a=(LinkedList)malloc(sizeof(Lnode));
	a->next=NULL;
	int b;
	cin>>b;
	InitList(a,b);
	for(int c=0;c<b;c++){
		a=a->next;
		cout<<a->a<<endl;
	}
	free(a);
}
int main(){
test();

	return 0;
}

运行结果:

大家可以看到这个6是我输入的,5到0为答案。为什么呢,我们采用头插,会把新创建的节点不断往前安防,而我们赋值又是从0开始,这就使得我们的最后一次赋值5用头插放到最前面了。

按照约定补上尾插:

尾插法原理:

尾插简单多了,顾名思义我们每次都插在最后面即可,别忘记最后一个节点要给他的next域赋值为NULL

尾插代码:

void creatweicha(LinkedList a,int length){
	Lnode* b=a;//创建指向节点来作为我们的指向
	int c=0;
	for(c=1;c<=2length;c++){///从1开始创建节点
		Lnode* p=(Lnode*)malloc(sizeof(Lnode));
		p->shuju=c;//节点存储的值为1到n
		b->next=p;//让指向节点链接到我们创建的节点上
		b=p;//同时移动指向节点让其指向我们创建的节点,以方便以后继续尾插
	}
	b->next=NULL;//别忘记最后一个节点的next域要赋值为NULL
}

在单链表中位置n插入一个元素代码

bool LinkedList_L(LinkedList a,int blocation,int c){
	int d=0;
	Lnode* p=(Lnode*)malloc(sizeof(Lnode));//动态开辟节点p来寻找查询节点的前驱节点
	p=a;
	while(true){
		d++;//d代表着我们这是第几号节点,节点编号从1号开始
		p=p->next;//不断使得p节点往后移动
		if(blocation<=0||p==NULL){//如果位置非法或者插入位置的前驱节点为NULL则代表着不存在前驱
			return false; //节点,返回false代表无法插入
		}
			if(d==blocation-1){
			break;//如果找到前驱节点那么结束循环
		}
	}
	Lnode* n=(Lnode*)malloc(sizeof(Lnode));
	n->shuju=c;//创建节点,并赋予其初始值
	n->next=p->next;//插入节点链接后面的节点
	p->next=n;//链接前驱节点
	return true;
	
}

附带插入函数的头插建立单链表附带验证的总代码:

#include<bits/stdc++.h>
using namespace std;
typedef struct Lnode{
	int shuju;
	struct Lnode* next;
}Lnode,*LinkedList;
void InitList(LinkedList a,int b){
	int c;
	for(c=1;c<=b;c++){
		Lnode* p=(Lnode*)malloc(sizeof(Lnode));
		p->shuju=c;
		p->next=a->next;
		a->next=p;
	}
}
bool LinkedList_L(LinkedList a,int blocation,int c){
	int d=0;
	Lnode* p=(Lnode*)malloc(sizeof(Lnode));
	p=a;
	while(true){
		d++;
		p=p->next;
		if(blocation<=0||p==NULL){
			return false; 
		}
			if(d==blocation-1){
			break;
		}
	}
	Lnode* n=(Lnode*)malloc(sizeof(Lnode));
	n->shuju=c;
	n->next=p->next;
	p->next=n;
	return true;
	
}
void testtoucha(){
	LinkedList a=(LinkedList)malloc(sizeof(Lnode));
	a->next=NULL;
	int b;
	cin>>b;
	InitList(a,b);
	Lnode* a1=a;
	for(int c=0;c<b;c++){
		a1=a1->next;
		cout<<a1->shuju<<endl;
	}
	cout<<"--------------------------------------"<<endl;
	LinkedList_L(a,3,100);
	Lnode* b1=a;
	while(true){
		b1=b1->next;
		if(b1==NULL){
			break;
		}
		else{
			cout<<b1->shuju<<endl;
		}
	}
	free(a);
}
int main(){
	testtoucha();
	return 0;
}

我们可以看到,我们头插创建十个节点,在第三个节点处插入数值为100的节点。

删除指定位置的节点

bool shanchu(LinkedList a,int b){
	Lnode* c=a;//创建节点,并把指向节点给与其
	int d=0;
	while(true){
		c=c->next;//不断往后移动节点
		d++;//记录这是第几个节点,下表从1开始
		if(b<=0||c==NULL){//如果删除位置不合法,或者要删除的位置的前驱为空,直接返回删除失败
			return false;
		}
		if(d==b-1){
			break;//找到合法的前驱节点,结束循环
		}
	}
	Lnode* m=c->next;//定义节点m来确定删除的节点
	if(m==NULL){
		return true;//如果m已经为NULL那么就不用管了。
	}
	else{//不为空,则删除节点m
		c->next=m->next;
		free(m);
		return true;
	}
}

带有删除节点函数的尾插创建的单链表验证:

#include<bits/stdc++.h>
using namespace std;
typedef struct Lnode{
	int shuju;
	struct Lnode* next;
}Lnode,*LinkedList;
bool shanchu(LinkedList a,int b){
	Lnode* c=a;
	int d=0;
	while(true){
		c=c->next;
		d++;
		if(b<=0||c==NULL){
			return false;
		}
		if(d==b-1){
			break;
		}
	}
	Lnode* m=c->next;
	if(m==NULL){
		return true;
	}
	else{
		c->next=m->next;
		free(m);
		return true;
	}
}
void creatweicha(LinkedList a,int length){
	Lnode* b=a;
	int c=0;
	for(c=1;c<=2length;c++){
		Lnode* p=(Lnode*)malloc(sizeof(Lnode));
		p->shuju=c;
		b->next=p;
		b=p;
	}
	b->next=NULL;
}
void test(){
	LinkedList a=(LinkedList)malloc(sizeof(Lnode));
	a->next=NULL;
	int c;
	cin>>c;
	creatweicha(a,c);
	Lnode* p=a;
	while(true){
		p=p->next;
		if(p!=NULL){
			cout<<p->shuju<<endl;
		}
		else{
			break;
		}
	}
	cout<<"AAAAAAA"<<endl;
	shanchu(a,3);
	Lnode* p1=a;
	while(true){
		p1=p1->next;
		if(p1!=NULL){
			cout<<p1->shuju<<endl;
		}
	  else{
	  	break;
	  }
	}
	free(a);
	
}
int main(){
	test();
	return 0;
}

可以看到我们创建了9个节点,成功删除了第三号节点。

一点小更正:

如果大家要单独写初始化函数的化,那么初始化函数就必须要加引用:

带初始化函数的尾插法:

#include<bits/stdc++.h>
using namespace std;
typedef struct Lnode{
	int shuju;
	struct Lnode* next;
}Lnode,*LinkedList;
bool shanchu(LinkedList a,int b){
	Lnode* c=a;
	int d=0;
	while(true){
		c=c->next;
		d++;
		if(b<=0||c==NULL){
			return false;
		}
		if(d==b-1){
			break;
		}
	}
	Lnode* m=c->next;
	if(m==NULL){
		return true;
	}
	else{
		c->next=m->next;
		free(m);
		return true;
	}
}
void creatweicha(LinkedList a,int length){
	Lnode* b=a;
	int c=0;
	for(c=1;c<=length;c++){
		Lnode* p=(Lnode*)malloc(sizeof(Lnode));
		p->shuju=c;
		b->next=p;
		b=p;
	}
	b->next=NULL;
}
void chushihua(LinkedList &a){//加引用,不然初始化失败
	a=(LinkedList)malloc(sizeof(Lnode));
	a->next=NULL;
	
}
void test(){

	
		LinkedList a;
		 chushihua(a);//=(LinkedList)malloc(sizeof(Lnode));
		//a->next=NULL;
	int c;
	cin>>c;
	creatweicha(a,c);
	Lnode* p=a;
	while(true){
		p=p->next;
		if(p!=NULL){
			cout<<p->shuju<<endl;
		}
		else{
			break;
		}
	}
	cout<<"AAAAAAA"<<endl;
	shanchu(a,3);
	Lnode* p1=a;
	while(true){
		p1=p1->next;
		if(p1!=NULL){
			cout<<p1->shuju<<endl;
		}
	  else{
	  	break;
	  }
	}
	free(a);
	
}
int main(){
	test();
	return 0;
} 

头插亦同理

#include<bits/stdc++.h>
using namespace std;
typedef struct Lnode{
	int a;
	struct Lnode* next;
}Lnode,*LinkedList;
void InitList(LinkedList a,int n){
	int e;
	for(e=0;e<n;e++){
		Lnode *b=(Lnode*)malloc(sizeof(Lnode));
		b->a=e;
		b->next=a->next;
		a->next=b;
	}
}
void chushihua(LinkedList &a){
	a=(LinkedList)malloc(sizeof(Lnode));
	a->next=NULL;
}
void test(){
	LinkedList a;
	chushihua(a);//=(LinkedList)malloc(sizeof(Lnode));
	//a->next=NULL;
	int b;
	cin>>b;
	InitList(a,b);
	for(int c=0;c<b;c++){
		a=a->next;
		cout<<a->a<<endl;
	}
	free(a);
}
int main(){
test();

	return 0;
}

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
c语言中,使用头插法可以方便地建立单链表头插法是指将新的节点插入到链表的头部的方法。 首先,我们需要定义一个结构体来表示节点: ```c typedef struct Node { int data; // 节点数据 struct Node* next; // 指向下一个节点的指针 } Node; ``` 然后,我们可以使用头插法建立单链表,具体步骤如下: 1. 创建一个头节点,并将其初始化为NULL,表示链表为空。 2. 读取第一个节点的数据。 3. 如果读取到的数据不为0(或其它结束标志),则继续执行下面的步骤;否则跳到第7步。 4. 创建一个新节点,并将读取到的数据存入新节点的data中。 5. 将新节点的next指针指向头节点指向的节点(即原来的第一个节点)。 6. 更新头节点的指针,使其指向新节点,表示新节点成为链表的第一个节点。 7. 链表建立完成。 下面是一个示例代码,用于展示如何使用头插法建立单链表: ```c #include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node* next; } Node; Node* createLinkedList() { Node* head = NULL; Node* newNode = NULL; int data; printf("请输入节点数据(以0作为结束标志):\n"); do { printf("节点数据:"); scanf("%d", &data); if (data == 0) { break; } newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->next = head; head = newNode; } while (1); return head; } void printLinkedList(Node* head) { Node* currentNode = head; printf("链表数据:"); while (currentNode != NULL) { printf("%d ", currentNode->data); currentNode = currentNode->next; } printf("\n"); } int main() { Node* head = createLinkedList(); printLinkedList(head); return 0; } ``` 通过运行以上代码,可以根据输入的节点数据建立单链表,并将建立的链表数据打印出来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值