单链表的基本操作及逆置、去重、归并、奇偶分解

一、运行效果

完整程序在末尾。

1、链表储存结构

typedef struct LNode{ //定义单链表结点类型
	elemtype data; //数据域
	struct LNode *next; //指针域
}Lnode, *Linklist;
typedef int status;

链表由指针域来连接各结点,确保链表线性连续。

2、初始化—头插法

status Initlist(Linklist &l){
	Linklist p,q;
	l=(Linklist)malloc(sizeof(Lnode));
	p=(Linklist)malloc(sizeof(Lnode));
	p=l;
	printf("请输入链表长度:");
	int len;
	scanf("%d",&len);
    printf("请输入链表元素:");
	for(int j=1;j<=len;j++){
		q=(Linklist)malloc(sizeof(Lnode));
		scanf("%d",&q->data);
		p->next=q;
		p=q;
	}
	p->next=NULL;
	return ok;
}

首先,定义两指针结点p、q,p指向L(头结点),生成q,且p->next=q,利用scnaf输入q->data,然后将p指向q,如此在for循环中,不断生成新结点q,p又随之指向下一结点,最后将p->next=NULL即可。

 3、插入

status Insertlist(Linklist &l,int i,elemtype e){
	Linklist p,s;
	int j=0;
	p=(Linklist)malloc(sizeof(Lnode));

	s=(Linklist)malloc(sizeof(Lnode));
	p=l;
	while(p&&j<i-1){
		p=p->next;++j;
	}
	if(!p||j>i-1){return error;}
	s->next=p->next;
	p->next=s;
	s->data=e;
	printf("插入成功\n");
	js=Printlist(l);
	return ok;
}

首先,定义结点指针p、s,通过for循环,将p指向所插入的前一个结点,且s为插入节点,令s->next=p->next;再将p->next=s;如此便成功将s节点插入了。

4、删除

status Deletelist(Linklist &l,int i){
	Linklist p,q;
	printf("目前删除第%d位节点",i);
	int j=0;
	p=(Linklist)malloc(sizeof(Lnode));
	if(!p){return error;}
	q=(Linklist)malloc(sizeof(Lnode));
	p=l;
	while(p&&j<i-1){
		p=p->next;++j;
	}
	q=p->next;
	p->next=q->next;
	free(q);
	printf("删除成功,如下:");
	js=Printlist(l);
	return ok;
}

首先,生成结点p、q,通过for循环将p指向所删除结点的前一个结点,将q作为中转结点,且q为p的下一结点,q=p->next;再p->next=q->next,再释放q,Free(q);即可。

5、按值查找

status Getlist(Linklist &l,int &i){
	Linklist p,q;
	elemtype e;
	int j=0;
	i=0;
	p=(Linklist)malloc(sizeof(Lnode));
	if(!p){return error;}
	p=l;
	printf("请输入查找的元素:");
	fflush(stdin);
	scanf("%d",&e);
	do{
		++i;++j;
		p=p->next;
	}
	while(p&&p->data!=e);
	if(p->data==e){
		printf("查找成功");
	}
	else{printf("查找失败");}
	printf("该元素位置为:%d",i);
	return ok;
}

生成结点p,将p指向头结点L,通过在do-while函数中比对所输入的值与链表结点data,取相等时候的第一个结点的位置。

6、打印

status Printlist(Linklist L){
	Linklist p;
	p=(Linklist)malloc(sizeof(Lnode));
	p=L->next;
	if(!p){return error;}
	while(p){
		printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
	return ok;
}

生成结点p,将p指向头结点L,在while循环中不断输出p->data,直至打印到p->next=NULL为止。

7、单链表逆置

status Reverselist(Linklist &l){
	Linklist p,q,s;
	int j=0;
	p=(Linklist)malloc(sizeof(Lnode));
	if(!p){return error;}
	q=(Linklist)malloc(sizeof(Lnode));
	s=(Linklist)malloc(sizeof(Lnode));
	p=l->next;
	q=p->next;
	p->next=NULL;
	s=q->next;
	q->next=p;p=q;q=s;
	while(s){
	s=q->next;
	q->next=p;p=q;q=s;
	}
	l->next=p;
	printf("逆置后的链表如下:");
	js=Printlist(l);
	return ok;
}

首先,生成结点指针p、q、s;

第一阶段,p指向L->next,q指向p->next,将p->next=NULL赋空值,令s=q->next,再将q->next赋给p,即将q指向p,再移位,p=q;q=s;

第二阶段,循环;利用s=q->next;可以放心将q指向p,再移位即可,

最后,将头结点指向p。

8、清除

void Clearlist(Linklist &L) {
	Linklist p;
	while (L->next) {
		p = L->next;
		L->next = p->next;
		free(p);
	}
	printf("清空成功");
}

生成结点指针p,在循环中,将p指向L->next,并移动头指针,指向p->next,接着释放p,如结点1、 2、3,p指向1,L最后指向2,然后删除1即可。

9、销毁

void Destroylist(Linklist &L) {
	Linklist p;
	p=L;
	while (p)
	{
		L = L->next;
//		free(p);
		delete(p);
		p = L;
	}
	printf("销毁成功");
}

生成结点指针p,在循环中,移动头指针,指向下一结点,令p=L,不断删除上一结点,并将原头结点L不断指向下一结点,最后L将指向NULL。

10、归并

void Mergelist(Linklist &la,Linklist &lb,Linklist &lc){
	Linklist pa,pb,pc;
	pa=(Linklist)malloc(sizeof(Lnode));
	pb=(Linklist)malloc(sizeof(Lnode));
	pc=(Linklist)malloc(sizeof(Lnode));
	pa=la->next;pb=lb->next;
	lc=pc=la;
	while(pa&&pb){
		if(pa->data<=pb->data){
			pc->next=pa;pc=pa;pa=pa->next;
		}
		else{pc->next=pb;pc=pb;pb=pb->next;}
	}
	pc->next=pa?pa:pb;
	free(lb);
	printf("归并LC链表如下:");
	js=Printlist(lc);
}

生成两结点pa、pb,由于La,Lb为单调递增有序链表,且将pa指向La->next,

Pb指向Lb->next,通过比较pa->data和pb->data,将较小的插入Lc中,直至La或Lb其中一个全部插入完成,则剩下的链表全部插入Lc即可

11、去重

void Distinctlist(Linklist &l)
{
	Lnode *p,*mark,*q;
	for(mark=l->next;mark!=NULL;mark=mark->next)
	{
		q=mark;
		p=mark->next; 
		while(p)
		{		
			if(mark->data==p->data)
			{
				q->next=p->next; 
				free(p);	
				p=q->next;				
			}else
			{
				q=p;
				p=p->next;
			}
		}
	}
	printf("去重后如下:");
	js=Printlist(l);
}

原理为,将链表第i=1个结点(比对结点)的data与其余结点的data比对是否相等,然后i++;随之将下一结点比对其后面的结点的data,直至结点为NULL。

生成结点p、mark、q;在for循环中,mark为比对结点,并令q=mark,p为mark所指向的结点,通过比对p结点的data(p->data),如果相等,采用删除结点函数的方法使链表连续,并将p指向q->next,否则,p指向下一结点p=p->next。

12、分解

void Devide(Linklist &La,Linklist &Lb,Linklist &Lc)
{
	int count=0;
	Lb=(Lnode *)malloc(sizeof(Lnode));
    Lc=(Lnode *)malloc(sizeof(Lnode));
	Lnode *p,*q,*r;
	p=La;q=Lb;r=Lc;
	while(p!=NULL&&p->next!=NULL){
		count++;
		p=p->next;
		if(count%2!=0){q->next=p;q=q->next;}
		else{r->next=p;r=r->next;}
	}
	 r->next=NULL;
    q->next=NULL;
	printf("分解两链表如下:\n");
	printf("奇数链表 Lb: ");
	js=Printlist(Lb);
	printf("偶数链表 Lc: ");
	js=Printlist(Lc);
}

生成结点p、q、r,并设立计数器count,且将p指向La,q指向Lb,r指向Lc,在while循环中,第一次循环,count++,当前为结点1,如果count%2!=0,即当前结点为奇数结点,将该结点赋给q->next,即将q(Lb)指向该节点,并将q指向自己的下一结点,如果count%2==0,即当前结点为偶数结点,将该结点赋给r->next,即将r(Lc)指向该节点,并将r指向自己的下一结点。最后将r和q指向NULL,即La分配完毕后。

此外,还有一种方法:

void Devide(Linklist &La,Linklist&Lb,Linklist&Lc)
{
    Linklist p,q,r;  //p用来指向Lb
    r=La->next;
    Lb=(Linklist)malloc(sizeof(LinkNode));
    Lc=(Linklist)malloc(sizeof(LinkNode));
    p=Lb;
    q=Lc;         //q用来指向Lc
    while(r!=NULL&&r->next!=NULL)
    {
       p->next=r;
       p=p->next;
       q->next=r->next;
       q=q->next;
       r=r->next->next;
    }
    p->next=NULL;
    q->next=NULL;
}

生成两结点指针,p、q;p用来指向Lb、q用来指向Lc;在while循环中,第一次循环时,p的next指向r,并将p赋为p->next,即将p下移一位,q也同理,并将r指向r的next的next,即在下一次循环中不影响前一次的分配,直至r指向NULL。最后将p、q指向NULL;

此思路源自这位:

数据结构与算法C语言实现——单链表分开_abcwsp的博客-CSDN博客

完整代码如下:

#include<stdio.h>
#include<stdlib.h>

#define ok 1
#define error 0

typedef int elemtype;
typedef int status;

typedef struct LNode{ //定义单链表结点类型
	elemtype data; //数据域,可以是别的各种数据类型,本文统一用int类型
	struct LNode *next; //指针域
}Lnode, *Linklist;
typedef int status;
int js;
status Printlist(Linklist L);
// 初始化,头插法
status Initlist(Linklist &l){
	Linklist p,q;
	l=(Linklist)malloc(sizeof(Lnode));
	p=(Linklist)malloc(sizeof(Lnode));
	p=l;
	printf("请输入链表长度:");
	int len;
	scanf("%d",&len);
    printf("请输入链表元素:");
	for(int j=1;j<=len;j++){
		q=(Linklist)malloc(sizeof(Lnode));
		scanf("%d",&q->data);
		p->next=q;
		p=q;
	}
	p->next=NULL;
	return ok;
}

// 插入
status Insertlist(Linklist &l,int i,elemtype e){
	Linklist p,s;
	int j=0;
	p=(Linklist)malloc(sizeof(Lnode));

	s=(Linklist)malloc(sizeof(Lnode));
	p=l;
	while(p&&j<i-1){
		p=p->next;++j;
	}
	if(!p||j>i-1){return error;}
	s->next=p->next;
	p->next=s;
	s->data=e;
	printf("插入成功\n");
	js=Printlist(l);
	return ok;
}

// 删除
status Deletelist(Linklist &l,int i){
	Linklist p,q;
	printf("目前删除第%d位节点",i);
	int j=0;
	p=(Linklist)malloc(sizeof(Lnode));
	if(!p){return error;}
	q=(Linklist)malloc(sizeof(Lnode));
	p=l;
	while(p&&j<i-1){
		p=p->next;++j;
	}
	q=p->next;
	p->next=q->next;
	free(q);
	printf("删除成功,如下:");
	js=Printlist(l);
	return ok;
}

// 查找链表某元素并返回位置
status Getlist(Linklist &l,int &i){
	Linklist p,q;
	elemtype e;
	int j=0;
	i=0;
	p=(Linklist)malloc(sizeof(Lnode));
	if(!p){return error;}
	p=l;
	printf("请输入查找的元素:");
	fflush(stdin);
	scanf("%d",&e);
	do{
		++i;++j;
		p=p->next;
	}
	while(p&&p->data!=e);
	if(p->data==e){
		printf("查找成功");
	}
	else{printf("查找失败");}
	printf("该元素位置为:%d",i);
	return ok;
}

// 打印
status Printlist(Linklist L){
	Linklist p;
	p=(Linklist)malloc(sizeof(Lnode));
	p=L->next;
	if(!p){return error;}
	while(p){
		printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
	return ok;
}
// // 单链表逆置
status Reverselist(Linklist &l){
	Linklist p,q,s;
	int j=0;
	p=(Linklist)malloc(sizeof(Lnode));
	if(!p){return error;}
	q=(Linklist)malloc(sizeof(Lnode));
	s=(Linklist)malloc(sizeof(Lnode));
	p=l->next;
	q=p->next;
	p->next=NULL;
	s=q->next;
	q->next=p;p=q;q=s;
	while(s){
	s=q->next;
	q->next=p;p=q;q=s;
	}
	l->next=p;
	printf("逆置后的链表如下:");
	js=Printlist(l);
	return ok;
}

//清除
void Clearlist(Linklist &L) {
	Linklist p;
	while (L->next) {
		p = L->next;
		L->next = p->next;
		free(p);
	}
	printf("清空成功");
}

//销毁
void Destroylist(Linklist &L) {
	Linklist p;
	p=L;
	while (p)
	{
		L = L->next;
//		free(p);
		delete(p);
		p = L;
	}
	printf("销毁成功");
}

// 归并
void Mergelist(Linklist &la,Linklist &lb,Linklist &lc){
	Linklist pa,pb,pc;
	pa=(Linklist)malloc(sizeof(Lnode));
	pb=(Linklist)malloc(sizeof(Lnode));
	pc=(Linklist)malloc(sizeof(Lnode));
	pa=la->next;pb=lb->next;
	lc=pc=la;
	while(pa&&pb){
		if(pa->data<=pb->data){
			pc->next=pa;pc=pa;pa=pa->next;
		}
		else{pc->next=pb;pc=pb;pb=pb->next;}
	}
	pc->next=pa?pa:pb;
	free(lb);
	printf("归并LC链表如下:");
	js=Printlist(lc);
}

// 去重

void Distinctlist(Linklist &l)
{
	Lnode *p,*mark,*q;
	for(mark=l->next;mark!=NULL;mark=mark->next)
	{
		q=mark;
		p=mark->next; 
		while(p)
		{		
			if(mark->data==p->data)
			{
				q->next=p->next; 
				free(p);	
				p=q->next;				
			}else
			{
				q=p;
				p=p->next;
			}
		}
	}
	printf("去重后如下:");
	js=Printlist(l);
}

 分解
void Devide(Linklist &La,Linklist &Lb,Linklist &Lc)
{
	int count=0;
	Lb=(Lnode *)malloc(sizeof(Lnode));
    Lc=(Lnode *)malloc(sizeof(Lnode));
	Lnode *p,*q,*r;
	p=La;q=Lb;r=Lc;
	while(p!=NULL&&p->next!=NULL){
		count++;
		p=p->next;
		if(count%2!=0){q->next=p;q=q->next;}
		else{r->next=p;r=r->next;}
	}
	r->next=NULL;
    q->next=NULL;
	printf("分解两链表如下:\n");
	printf("Lb: ");
	js=Printlist(Lb);
	printf("Lc: ");
	js=Printlist(Lc);
}

// 分解2
//void Devide(Linklist &La,Linklist&Lb,Linklist&Lc)
//{
//    Linklist p,q,r;  //p用来指向Lb
//    r=La->next;
//    Lb=(Linklist)malloc(sizeof(LinkNode));
//    Lc=(Linklist)malloc(sizeof(LinkNode));
//    p=Lb;
//    q=Lc;         //q用来指向Lc
//    while(r!=NULL&&r->next!=NULL)
//    {
//       p->next=r;
//       p=p->next;
//       q->next=r->next;
//       q=q->next;
//       r=r->next->next;
//    }
//    p->next=NULL;
//    q->next=NULL;
//}

int main()
{
	Linklist L,la,lb,lc,ld,le;
    js=Initlist(L);
	js=Insertlist(L,2,6);
	js=Printlist(L);
	js=Deletelist(L,3);
	js=Getlist(L,js);
	printf("\n");
	js=Reverselist(L);
	Distinctlist(L);
	Clearlist(L);
	printf("\n");
	Destroylist(L);
	printf("\n");
	printf("初始化链表La、Lb\n");
	js=Initlist(la);
	js=Initlist(lb);
	Mergelist(la,lb,lc);
	printf("分解链表Lc");
	Devide(lc,ld,le);
	return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值