学链表也学了有一段时间了,在这里先总结一下
1.链表的中头结点相当重要,判断是否有值或为空相当重要,建议头结点一般设置为不赋值
2.每次操作一般都是从移动元素的上一个结点来操作,这也是头结点为建议不赋值的原因
3.链表的每次指向变化最好还是画图更加清晰易懂
删除两条链表重复的数 我的思路就是用较长链表遍历较短链表,再创一条链表把不重复的数存储起来。。。 #include <stdio.h> #include<stdlib.h> typedef struct node { int data; struct node *next; }NODE; NODE *createa() { NODE *head,*p,*q; int i,j,k; k=0; head=NULL; for(i=0;i<10;i++) { p=(NODE *)malloc(sizeof(NODE)); p->data=k+2; p->next=NULL; if(head==NULL) { head=p; } else { q->next=p; } q=p; k+=2; } return head; } NODE *createb() { NODE *head,*p,*q,*t; int i,j,k; k=0; head=NULL; for(i=0;i<5;i++) { p=(NODE *)malloc(sizeof(NODE)); p->data=k+2; p->next=NULL; if(head==NULL) { head=p; } else { q->next=p; } q=p; k+=4; } return head; } void shuchu(NODE *head) { while(head!=NULL) { printf("%d ",head->data); head=head->next; } } NODE *shanchu(NODE* la,NODE *lb)//这篇代码的核心 { NODE *q,*p,*t,*head; int i,flag; q=la; p=lb; head=(NODE *)malloc(sizeof(NODE));//为下面存储不同数做准备 head->next=NULL; for(i=0;i<10;i++) { flag=0; while(p!=NULL) { if(q->data==p->data)//较长链遍历较短链 { flag=1; break; } p=p->next; } if(flag==0) { t=(NODE *)malloc(sizeof(NODE));//头插法创建新链存储不重复数 t->data=q->data; t->next=head->next; head->next=t; } q=q->next;// 判断下一个结点 p=lb;//新的遍历还是从较短链开始 } return t;//注意不要返回head; } int main(void) { NODE *la,*lb,*q; la=createa(); lb=createb(); shuchu(la); printf("\n"); shuchu(lb); printf("\n"); q=shanchu(la,lb); while(q!=NULL) { printf("%d ",q->data); q=q->next; } }
冒泡排序//交换结点 #include<stdio.h> #include<stdlib.h> typedef struct node { int data; struct node *next; }NODE; NODE *create(int n) { int a; NODE *head,*p,*q,*t; t=(NODE *)malloc(sizeof(NODE)); head=NULL; while(n--) { scanf("%d",&a); p=(NODE *)malloc(sizeof(NODE)); p->data=a; p->next=NULL; if(head==NULL) { head=p; } else { q->next=p; } q=p; } t->next=head;//设立一个空的表头,为下面结点交换做准备 return t; } int paixu(NODE *head)//设链表为2,1,5,3,4 { NODE *pre,*p,*tail; tail=NULL; pre=head; while((head->next)!=tail) { p=head->next; pre=head; while(p->next!=tail) { if((p->data)<(p->next->data)) { pre->next=p->next; //pre->next=1... p->next = p->next->next;// p->next=5;确定了后面三个结点的连接 pre->next->next = p; //pre->next->next=2; p = pre->next; //p=1; } //则pre->1,2,5,3,4,p->1,2,5,3,4, p=p->next; pre=pre->next; } tail=p; } return 0 ; } int main(void) { int n; NODE *p,*q,*t; scanf("%d",&n); p=create(n); paixu(p); while(p->next!=NULL) { printf("%d ",p->next->data); p=p->next; } return 0; } 头指针不变,后面的结点进行交换,需要注意的是除了两个比较的数之外后面结点的正确连接。。。
链表的逆置
#include<stdio.h> #include<stdlib.h> #include<time.h> struct node { int data; struct node *next; }; struct node *create(int count) { struct node *phead,*pend,*pnew; int i; phead=pend=(struct node *)malloc(sizeof(struct node));///// srand((unsigned)time(NULL)); for(i=0;i<count;i++) { pnew=(struct node *)malloc(sizeof(struct node)); pnew->data=rand()%100; pend->next=pnew; pend=pnew; } pnew->next=NULL; return phead; } void output(struct node * phead) { phead=phead->next;//为什么要指向下一个呢?因为phead->pend;此时Pend为空, while(phead)//相当于b=a;a=3;无论a后来怎么变,b总等于最初的a。。。。 { printf("%d ",phead->data); phead=phead->next; } printf("\n"); } void contrary(struct node *phead) { struct node *ptemp1=phead->next,*ptemp2=phead->next; phead->next=NULL; while(ptemp2)//以下代码分成两部分来看 { ptemp1=ptemp2;//p2永远指向p1的下一个 ptemp2=ptemp1->next; ptemp1->next=phead->next;//妥妥的头插法啊 phead->next=ptemp1; } } int main(void) { struct node *phead; int count=10; phead=create(count); output(phead); contrary(phead); output(phead); }
将两个有序链表合并再进行逆置
#include<stdio.h> #include<stdlib.h> #include<time.h> struct node { int data; struct node *next; }; struct node *create(int icount,int num) { struct node *phead=NULL,*pend,*pnew; int i,j; phead=pend=(struct node*)malloc(sizeof(struct node)); for(i=0,j=0;i<icount;i++) { pnew=(struct node *)malloc(sizeof(struct node)); pnew->data=j; j+=num; pend->next=pnew; pend=pnew; } pnew->next=NULL; return phead; } void output(struct node *phead) { phead=phead->next; while(phead) { printf("%-5d",phead->data); phead=phead->next; } printf("\n"); } void merge(struct node *phead_a,struct node *phead_b) { struct node *la,*lb,*lc,*la_t,*lb_t;//a指向la当前结点,b指向lb当前结点 la=phead_a->next;//la_t,lb_t可看作链表的备份 lb=phead_b->next; phead_a->next=NULL; while(la&&lb) { if((la->data)<(lb->data)) {//备份移动 la_t=la->next;//la_t备份比较数的下一个结点 //头插法 la->next=phead_a->next; phead_a->next=la; //跟前面链表的逆置一样、、 la=la_t;//a移动到下一个结点 } else { lb_t=lb->next; lb->next=phead_a->next; phead_a->next=lb; lb=lb_t; } } while(la)//接下来思路都跟上面一样,只是将较长链再头插进去而已 { la_t=la->next; la->next=phead_a->next; phead_a->next=la; la=la_t; } while(lb) { lb_t=lb->next; lb->next=phead_a->next; phead_a->next=lb; lb=lb_t; } } int main(void) { struct node *phead_a,*phead_b; srand((unsigned)time(NULL)); int icount_a=rand()%20+1,icount_b=rand()%20+1; int a=rand()%4+1,b=rand()%4+1; phead_a=create(icount_a,a); phead_b=create(icount_b,b); output(phead_a); output(phead_b); merge(phead_a,phead_b); output(phead_a); return 0; }
链表的交叉合并
#include<stdio.h> #include<stdlib.h> #include<time.h> struct node { int data; struct node *next; }; struct node*create(int icount) { struct node *phead,*pend,*pnew; int i; pend=phead=(struct node*)malloc(sizeof(struct node)); for(i=0;i<icount;i++) { pnew=(struct node*)malloc(sizeof(struct node)); pnew->data=rand()%100; pend->next=pnew;//尾插法 pend=pnew; } pnew->next=NULL; return phead; } void output(struct node *phead) { phead=phead->next; while(phead) { printf("%d ",phead->data); phead=phead->next; } printf("\n"); } void merge(struct node *phead_x,struct node *phead_y) { struct node *lx,*lx_h,*ly,*lz; lx=phead_x->next; ly=phead_y->next; lz=phead_x; while(lx)//lx短链表,ly长链表,lz指向已排好序链表的尾部 { //会不会感到很奇怪为什么直接输出phead_x就可以,答案应该就是下一句lz=phead_x lz->next=lx;//连接lz和短链表的当前节点 //则lz->next=phead_x->next,接下来的操作都可以看作phead_x已经作为头节点 lx_h=lx->next;//备份lx的指针域 lx->next=ly;//连接lx当前节点和ly当前节点 lz=ly;//移动lz,使lz成为当前已排好节点尾部 lx=lx_h;//移动lx,使lx成为短链表未排好序的第一个 ly=ly->next;//移动ly,使ly成为长链表未排好序的第一个 } lz->next=ly;//连接剩下的长链表 } int main(void) { struct node *phead_a,*phead_b; srand((unsigned)time(NULL)); int icount_a=rand()%20+1,icount_b=rand()%20+1; phead_a=create(icount_a); phead_b=create(icount_b); output(phead_a); output(phead_b); if(icount_a<=icount_b) { merge(phead_a,phead_b); output(phead_a); free(phead_b); } else { merge(phead_b,phead_a); output(phead_b); free(phead_a); } }
循环单链表的创建//尾节点指向头节点时退出
#include<stdio.h> #include<stdlib.h> typedef struct n{ int data; struct n *next; }node; node *create(int count) { int i; node *phead,*q,*p; phead=(node *)malloc(sizeof(node)); q=phead; for(i=0;i<count;i++){ p=(node *)malloc(sizeof(node)); scanf("%d",&p->data); phead->next=p; phead=p; } phead=q;// head恢复开始时的位置 p->next=phead;//尾节点指向头节点 return phead; } void output(node *head){ node *pt; pt=head->next;//head本身没有赋值 while(pt!=head)//当尾节点走到头节点时退出循环 { printf("%d ",pt->data); pt=pt->next; } } int main(void){ int count; node *head; scanf("%d",&count); head=create(count); output(head); }
双向单链表的创建//插入//删除
#include<stdio.h>//不难理解,建议画图所谓的删除与添加只是多考虑了一个指针域而已 #include<stdlib.h> typedef struct n { int data; struct n *pre,*next; }node; node *create(int count) { int i; node *phead,*p,*q; phead=(node *)malloc(sizeof(node)); q=phead;//phead数据域未给赋值 for(i=0;i<count;i++) { p=(node *)malloc(sizeof(node)); printf("输入数据:\n"); scanf("%d",&p->data); p->pre=phead;//其实就是尾插法加上这个 phead->next=p; phead=p; } p->next=q;//完成头尾节点的互相指向 phead=q; phead->pre=p; return phead; } void output(node *head) { node *p,*s; p=head->next; while(p!=head)//从左至右 { printf("%d ",p->data); p=p->next; } s=head->pre; printf("\n"); while(s!=head)//从右至左 { printf("%d ",s->data); s=s->pre; } printf("\n"); } void charu(node *head,int n)//链表的插入 { int i; node *p,*q,*s; p=head; for(i=1;i<n;i++)//i=1 { p=p->next; } s=(node *)malloc(sizeof(node)); printf("输入待插入数:\n"); scanf("%d",&s->data); s->next=p->next; p->next=s; s->pre=p; (s->next)->pre=s; output(head); } void shanchu(node *head,int n) { int i; node *p; p=head; for(i=0;i<n;i++)//注意这里和删除的不同 i=0 { p=p->next; } (p->next)->pre=p->pre; (p->pre)->next=p->next; output(head); free(p); } int main(void) { int n; node *head; printf("请输入链表数\n"); scanf("%d",&n); head=create(n); output(head); printf("输入待插入节点位置:\n"); scanf("%d",&n); charu(head,n); printf("输入待删除节点位置:\n"); scanf("%d",&n); shanchu(head,n); }
链表学到这里再将前面的知识再过了一遍,多了一些该注意的点
struct node* shanchu(struct node *head)//链表的删除//没什么难度,就是得注意下循环中的break; {//可以尝试下取掉break删除最后一个数就懂了 int a; scanf("%d",&a); struct node *begin,*end,*p; begin=(struct node *)malloc(sizeof(struct node)); begin=head; while(head->next!=NULL) { if(a==head->next->data) { p=(struct node *)malloc(sizeof(struct node)); p=head->next->next; head->next=p; break;////// } head=head->next; }
void paixu(struct node *head)//冒泡排序节点交换核心 {//基本没什么问题 struct node *begin,*end,*pre,*p; end=NULL; while(head->next!=end)//设计的很巧妙 { begin=head->next; pre=head; while(begin->next!=end) { if(begin->data<begin->next->data) { pre->next=begin->next; begin->next=begin->next->next; pre->next->next=begin; begin=pre->next;//这个东西不能忘,相当于后退一步再前进一步 } begin=begin->next; pre=pre->next; } end=begin; } }
void nizhi(struct node *head)//链表的逆置,,这之间的逻辑关系还是有点没理清 { struct node *begin,*end; begin=head->next;end=head->next; head->next=NULL; while(end) { begin=end; end=begin->next; begin->next=head->next; head->next=begin; }}
void shanchu(qnode *p1,qnode *p2)//链表的交叉合并 { qnode *la,*lb,*la_t,*lc; la=p1->next;lb=p2->next; lc=p1; while(la){ lc->next=la; la_t=la->next; la->next=lb;//我写的是lc=lc->next;lc->next=lb,明显错了 lc=lb;//上面已经有lc->next=la,则la->next=lb可看成lc-la-lb la=la_t; lb=lb->next; } lc->next=lb; }
链表学到这里就先告一段落,接下来会继续深入的