您的位置:首页 > 理论基础 > 数据结构算法

实战数据结构(3)_两个单链表间的合并操作

2013-08-22 23:05 447 查看
/************************************************************************/
/* 要求:
链表a非递减,链表b非递减
现在要求:
1.实现两个链表的合并,并且元素也是非递减
2.不能占用多余节点,即只能用已有的节点,不能开辟额外的节点
exp:
list a:2 4 4 5 7 8
list b:3 4 6 9
则合并后:
list a: 2 3 4 4 4 5 6 7 8 9
*/
/************************************************************************/
/************************************************************************/
/* 问题:
1.还是不能一次写对代码,还是要考编译器来查找错误,指针使用很容易内存泄露
2.还是在最后一个节点时候,scur=NULL了。就不能引用了scur->data内存泄露

*/
/************************************************************************/

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

typedef struct node
{
int data;
struct node *next;
}listnode;

void CreateList(listnode *head,int nodenum,int *data);
void printflist(listnode *head);
void DeleElement(listnode *lista,listnode *listb,int *leave,int dataa);
void mergelist(listnode *head1,listnode *head2,int length_a,int length_b);

void main()
{
int dataa[]={2,4,4,5,7,8};
int datab[]={3,4,6,9,11,25,69,78};
listnode *head1=(listnode *)malloc(sizeof(listnode));
listnode *head2=(listnode *)malloc(sizeof(listnode));
if(head1==NULL|| NULL==head2)
{
printf("头结点malloc分配失败\n");
exit(-1);
}
int length_a=sizeof(dataa)/sizeof(dataa[0]);
int length_b=sizeof(datab)/sizeof(datab[0]);
CreateList(head1,length_a,dataa);
printf("链表A的元素有%d个:\n",length_a);
printflist(head1);
CreateList(head2,length_b,datab);
printf("链表B的元素有%d个:\n",length_b);
printflist(head2);
mergelist(head1,head2,length_a,length_b);
}

void CreateList(listnode *head,int nodenum,int *data)
{

listnode *h=head,*pre=h,*newnode;
for(int i=0;i<nodenum;i++)
{
if(NULL==(newnode=(listnode *)malloc(sizeof(listnode))))//开辟一个新节点
{
printf("malloc申请失败");
return ;
}
newnode->data=data[i];
pre->next=newnode;
pre=newnode;
}
pre->next=NULL;
return ;

}

void printflist(listnode *head)
{
listnode *p=head->next;
while(p!=NULL)
{
printf("%4d",p->data);
p=p->next;
}
printf("\n");
return ;
}

void DeleElement(listnode *lista,listnode *listb,int *leave,int dataa)
{
//链表a删除b在a中出现的元素
listnode *cur_a=lista->next,*pre_a=lista,*cur_b=listb->next;
int count=0;
while(cur_a!=NULL) //控制整个流程
{
while(cur_b!=NULL && cur_a->data!=cur_b->data )		//将链表b中的元素在a中遍历
cur_b=cur_b->next;
if(NULL!=cur_b)		//找到了 将a中此节点 删除
{
pre_a->next=cur_a->next;
free(cur_a);
cur_a=pre_a->next; //这里漏掉了    当前元素也要后继一下
count++;
}
else	//当前a指向的元素在b中都没有,cur_a向后移动一位
{
pre_a=cur_a;
cur_a=cur_a->next;
}
cur_b=listb->next; //不管查找了没有 b都需要从新开始匹配
}
*leave=dataa-count; //返回剩下a中元素个数
return ;
}

void mergelist(listnode *head1,listnode *head2,int length_a,int length_b)
{
printf("合并两个链表后元素个数为%d且不递减顺序为:\n",length_a+length_b);
listnode *long_head=(length_a>=length_b)? head1:head2;
listnode *short_head=(length_a<length_b)? head1:head2;//先比较两个链表的长度,短的用来控制主流程 时间复杂度低
listnode *lpre=long_head,*scur=short_head->next; //lpre指向long的头结点,scur指向short第一个节点
listnode *lcur=lpre->next; //lcur指向long的第一个节点
listnode *temp;
while(lcur!=NULL && scur!=NULL) //short控制主流程 当short NULL时结束 并且long不为最后一个节点
{
while(scur->data > lcur->data) //当short>long时,long 后继一位
{	//当遇到最后一个节点时候,lcur==NULL了,不能再lcur->data了。这里 lcur!=NULL要放到逻辑前
lpre=lcur;
lcur=lcur->next;
}
if(scur->data <= lcur->data) //当short遇到不大于的数了 此时lcur就是要插入的点
{
temp=scur->next;	//记录short下一个节点
lpre->next=scur;
scur->next=lcur;    //将scur插入到long中
lpre=lpre->next;	//这里lpre后继一位 保持在lcur前一个节点 lcur不变
scur=temp;		//scur 后继一位
}
}
if(NULL==lcur)	//short 要插入的节点为最后一个节点 直接插入到最后
{
lpre->next=scur; //直接插入
scur=scur->next;	//到了最后一个节点了,short也应该是最后一个节点了 要scur=NULL
}
free(short_head);		//注意要释放短的头节点
printflist(long_head);
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: