链表学习:单向链表,双向链表,双向循环链表的构建及插入和删除节点操作(C/C++)

漫漫学习数据结构之路(1.链表)
博客代码根据《数据结构》教材思路

我觉得链表的理解和掌握借助画图会很好很高效!多动手多观察链表各元素之间的连接关系。

1.单向链表

单向链表结构体的构建核心为一个数据域和一个指针域(指向下一个节点)。
我比较习惯有头指针head。
首先是链表的构建

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef struct node
{
	int data;
	struct node *next;
}chart;
chart *head,*p;
void create(int n)//n为链表的长度; 
{
	int i,j;
	head=p=(chart *)malloc(sizeof(chart));
	head->data=0;
	head->next=NULL;
	for(i=1;i<=n;i++)
	{
		p->next=(chart *)malloc(sizeof(chart));
		scanf("%d",&p->next->data);
		p->next->next=NULL;
		p=p->next;
	}
}

接着是插入操作:

void add(int i,int k)//要插入的元素的位置和元素的值; 
{
	int j; 
	j=1;
	chart *t,*s;
	t=head;
	while(t&&j<i)//寻找目标的位置; 
	{
		t=t->next;
		j++;
	}
	s=(chart *)malloc(sizeof(chart));
	s->data=k;
	s->next=t->next;
	t->next=s;
}

然后是删除节点的操作:

void dele(int a)//删除元素的位置;
{
	chart *s,*t;
	s=head;
	j=1;
	while(s&&j<=a-1)
	{
		s=s->next;
		j++;
	}
	t=s->next;//将目标元素用另一指针标记; 
	s->next=s->next->next;
	free(t);//释放该内存; 
}

单向链表的合并(按升/降序)

void connect()
 {
 	int i,j;
 	head3=p3=(chart *)malloc(sizeof(chart));
 	p3->next=NULL;
 	p1=head1->next;
 	p2=head2->next;
	while(p1&&p2)
	{
		if(p1->data<=p2->data)
		{
			p3->next=(chart *)malloc(sizeof(chart));//注意指针使用前一定要开新位置!!!
			p3->next=p1;
			p1=p1->next;
			p3=p3->next;
		 } 
		 else
		 {
		 	p3->next=(chart *)malloc(sizeof(chart));
		 	p3->next=p2;
		 	p2=p2->next;
		 	p3=p3->next;
		 }
	 } 
	 if(p1)//将剩下的插入;
	 {
	 	while(p1)
	 	{
	 		p3->next=(chart *)malloc(sizeof(chart));
	 		p3->next=p1;
	 		p1=p1->next;
	 		p3=p3->next;
	 		p3->next=NULL;
		 }
	 }
	 else
	 {
	 	while(p2)
	 	{
	 		p3->next=(chart *)malloc(sizeof(chart));
	 		p3->next=p2;
	 		p2=p2->next;
	 		p3=p3->next;
	 		p3->next=NULL;
		 }
	 }
 }

2.双向链表

与单向链表不同的是,双向链表中多一个指向前一节点的指针perior,故进行操作时会复杂一些。
首先还是构建

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;//双向链表; 
typedef struct node
{
	int data;
	struct node *perior;
	struct node *next;
}chart;//相比于单向链表多了一个指针perior; 
chart *head,*p,*s;
void create(int n) 
{
	int i,j;
	head=p=(chart *)malloc(sizeof(chart));//所有指针都要先malloc一个空间! 
	p->next=NULL;
	p->perior=NULL;
	for(i=1;i<=n;i++)
	{
		s=(chart *)malloc(sizeof(chart));
		scanf("%d",&s->data);
		s->next=NULL;
		p->next=s;
		s->perior=p;
		p=p->next; //p为中间指针量,负责s的perior指针的连接; 
	 } 
}

然后是插入删除节点的操作(这里一起写了,小组合),都比单向链表多一个指针要连接或断开:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;//双向链表; 
typedef struct node
{
	int data;
	struct node *perior;
	struct node *next;
}chart;//相比于单向链表多了一个指针perior; 
chart *head,*p,*s;
void create(int n)//按照数据结构书本单链表构建的思路; 
{
	int i,j;
	head=p=(chart *)malloc(sizeof(chart));//所有指针都要先malloc一个空间! 
	p->next=NULL;
	p->perior=NULL;
	for(i=1;i<=n;i++)
	{
		s=(chart *)malloc(sizeof(chart));
		scanf("%d",&s->data);
		s->next=NULL;
		p->next=s;
		s->perior=p;
		p=p->next; //p为中间指针量,负责s的perior指针的连接; 
	 } 
}
void del(int k)
{
	int i,j;
	chart *t;
	j=0;
	t=(chart *)malloc(sizeof(chart));
	t=head;
	while(t&&j<=k-1)
	{
		j++;
		t=t->next;
	}//最后一个元素的next为NULL,没有perior; 
	if(t->next!=NULL)
	{ 
	    t->next->perior=t->perior;
	    t->perior->next=t->next;
	}
	else
	t->perior->next=NULL;
}
void insert(int a,int k)//在第k个位置插入新数据a;
{
	chart *t;
	chart *p;
	int i,j;
	j=0;
	t=(chart *)malloc(sizeof(chart));
	t=head;
	while(t&&j<k-1)//容易遗漏最后一个位置的特殊处理情况; 
	{
		t=t->next;
		j++; 
	}
	 p=(chart *)malloc(sizeof(chart));
	 p->data=a;
	if(t->next!=NULL)
	{
	 t->next->perior=p;
	 p->next=t->next;
	 p->perior=t;
	 t->next=p;
    }
    else
	{
        t->next=p;
		p->perior=t;
		p->next=NULL;	
	} 
 } 
int main()
{
	int i,j;
	int n,k1;
	int t;
	int a,k;
	int c;//计数用; 
	int f;//判断操作指令;
	int q; 
	printf("请输入测试次数:\n");
	scanf("%d",&t);
	while(t--)
	{
		c=0;
		printf("\n请输入链表长度:\n");
		scanf("%d",&n);
		printf("\n请输入各个元素的值:\n");
		create(n);
		printf("请输入您要进行的操作次数:\n");
		scanf("%d",&q);
		while(q--)
		{
		   printf("请输入您要进行的操作指令(若进行插入操作输入数字1,若要进行删除操作输入数字2):\n");
		   scanf("%d",&f);
		   if(f==1)
		   {
		   	printf("请输入要插入的元素的值及其位置:\n");
 	     	scanf("%d%d",&a,&k);
 	     	if(k>n+1||k<=0)
 	    	{
 		    	printf("输入的插入位置不存在!\n\n");
 		    	
		    }
		       else
		       {
 		       insert(a,k);
 		       printf("插入后:\n");
 		       for(p=head->next;p!=NULL;p=p->next)
 		       {
 		        	printf("%d ",p->data);
		        }
		            printf("\n\n");
		            n++;
	            }
		   }
		   else
		   if(f==2)
		   {
		   	printf("请输入要删除的元素的位置:\n");
	     	scanf("%d",&k1);
	    	if(k1>n||k1<=0)
	    	printf("要删除的位置不存在!\n\n");
	     	else
	    	{
		     del(k1);
		    printf("元素删除后:\n");
	    	for(p=head->next;p!=NULL;p=p->next)
		    {
			   printf("%d ",p->data);
			   c++;
		    }
	     	if(c==0)
	     	printf("空");
	    	printf("\n\n");
	    	n--;
	        }
		   }
		   else
		   printf("输入的指令有误!\n\n");
	    }
	}
	return 0;
}

双向循环链表

循环链表的思路只是在原来链表的基础上尾节点不是指向NULL,而是改成指向头节点(单向链表和双向链表的循环模式差不多,因此直接写双向链表(比单向链表多一个改变:head多的perior指针要指向尾节点)
构建,插入,删除:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef struct node
{
	int data;
	struct node *perior;
	struct node *next; 
}chart;
chart *head,*p,*s;
void create(int n)
{
	int i,j;
	head=p=(chart *)malloc(sizeof(chart));
	head->next=NULL;
	head->perior=NULL;
	for(i=1;i<=n;i++)
	{
		s=(chart *)malloc(sizeof(chart));
		scanf("%d",&s->data);
		s->next=NULL;
		s->perior=p;
		p->next=s;
		p=p->next;
	}
	s->next=head;//唯一与双向链表在构建时的不同之处:尾指针指向头,头指针指向尾; 
	head->perior=s;
}
void del(int k)//删除位置; 
{
	chart *t;
	int i,j;
	t=(chart *)malloc(sizeof(chart));
	t=head;
	j=0;
	while(t&&j<=k-1)
	{
		t=t->next;
		j++; 
	}
		t->next->perior=t->perior;
		t->perior->next=t->next;
		free(t);
}
void insert(int a,int m)//值为a,插入位置为m;
{
	chart *t,*p;
	int i,j;
	t=(chart *)malloc(sizeof(chart));
	t=head;
	j=0;
	while(t&&j<m-1)
	{
		t=t->next;
		j++;
	}//找到插入位置的前一节点;
	p=(chart *)malloc(sizeof(chart));
	p->data=a;
	p->next=t->next;
	t->next=p;
	p->next->perior=p;
	p->perior=t;
 } 
int main()
{
	int i,j;
	int n;
	int k;
	int t;
	int a,m;
	printf("请输入实例数:\n");
	scanf("%d",&t);
	while(t--)
	{
	printf("请输入链表长度:\n"); 
	scanf("%d",&n);
	printf("请输入链表各元素的值:\n");
	create(n);
	printf("请输入要删除的元素的位置:\n");
	scanf("%d",&k);
	del(k);
	printf("删除后:\n"); 
	for(p=head->next;p!=head;p=p->next)
	{
		printf("%d ",p->data);
	}
	printf("\n");
	printf("请输入要插入的元素的值及其位置:\n");
	scanf("%d%d",&a,&m);
	insert(a,m);
	for(p=head->next;p!=head;p=p->next)
	{
		printf("%d ",p->data);
	}
	printf("\n");
    }
	return 0;
 } 

坚持,努力!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值