从这一篇博客开始对链表的一些典型操作进行总结(主要是把思路和关键点弄清楚):
(1)逆置-头插法
整个程序代码:
#include<iostream>
using namespace std;
typedef struct node{
int data;
struct node *next;
}node;
node *create() //创建链表
{
node *head,*p,*q;
int i=0;
int x;
head=(node *)malloc(sizeof(node));
printf("please input thenode:");
while(1)
{
printf("→");
scanf("%d",&x); //输入链表data的存放的数据。
if(x==0) {
break;
}
p=(node *)malloc(sizeof(node));
p->data=x;
if(++i==1)
{
head->next=p;
}
else
{
q->next=p;
}
q=p;
}
q->next=NULL;
return head;
}
void print(node*head) //输出链表
{
node *p;
int index=0;
if(head->next==NULL)
{
printf("Link isempty!\n");
exit(0);
}
p=head->next;
printf("the link is: head");
while(p!=NULL)
{
printf("→ %d",p->data);
p=p->next;
}
printf("\n");
}
node * reverse(node*head){ //反置链表
printf("reverse begin\n");
node *pCur,*pHead;//pCur指向当前要处理的节点,pHead 为了头插而设置的指针
pCur=head->next->next;
head->next->next=NULL;//把第一个节点(头节点的下一个节点)next指向指为NULL。不然print 输出时1->2->。因为刚才把2放到1前面,但1->next=2形成循环了。
int i=0;
while(pCur!=NULL)
{
pHead=pCur;
pCur=pCur->next; //注意刚才pCur和pHead 指向同一节点。为了头插,我需要变换pHead 指针但做次之前一定要把pCur 往下移动。
pHead->next=head->next;
head->next=pHead;
}
return head;
}
int length(node*head) //得到链表的长度
{
int len=0;
node *p;
p=head->next;
while(p)
{
len++;
p=p->next;
}
return len;
}
node *search(node*head,int pos) //查找某个节点
{
node *p;
int len=length(head);
p=head->next;
if(pos<0)
{
printf("incorrectposition!\n");
return NULL;
}
else if(pos>len)
{
printf("incorrectposition!\n");
return NULL;
}
else if(pos==0)
{
return head;
}
if(p==NULL)
{
printf("the link isempty!\n");
return NULL;
}
while (--pos)
{
p=p->next;
}
return p;
}
node *del(node*head,int pos) //删除某个节点
{
node *p,*q;
int len=length(head);
p=head->next;
if(pos<0)
{
printf("incorrectposition!\n");
return NULL;
}
else if(pos>len)
{
printf("incorrectposition!\n");
return NULL;
}
if(p==NULL)
{
printf("linkempty!\n");
return NULL;
}
p=search(head,pos-1);
if(p!=NULL&&p->next!=NULL)
{
q=p->next;
p->next=q->next;
free(q);
}
return head;
}
node *insert(node*head,int pos,int x) //插入某个节点
{
node *p,*q=NULL;
q=(node *)malloc(sizeof(node));
q->data=x;
if(pos==0)
{
head->next=q;
return head;
}
p=search(head,pos);
if(p!=NULL)
{
q->next=p->next;
p->next=q;
}
return head;
}
int main(){
node * head=create();
print(head);
head=reverse(head); //逆置
print(head);
return 0;
}
注意关键点在node * reverse(node *head) 函数也注释部分。
1.写时一定要思路清楚。我要干什么。所以定义了当前节点指针pCur,为了头插与head 指针和head->next 交互的指针pHead。这样定义了分工明确的指针,避免写程序过程中思路混乱。
2.注意开始节点的next 要赋为空,不仅防止print 语句进入循环,也是链表的要求,思维要严密。
3.注意我们创建链表一般创建头指针,可以统一起来。加了头结点,第一个节点地址也被某一个节点next存放,空表和非空表。
输出结果为:
please input the node:→1
→2
→3
→4
→5
→6
→0
the link is: head→ 1 → 2 → 3 → 4 → 5 →
reverse begin
the link is: head→ 6 → 5 → 4 → 3 → 2 →
Press any key to continue
合并:
node * mergeLink(node *head1,node * head2){ //两个非递减链表合并成一个非递减链表
//记住要有活动指针概念 原链表两个活动指针和合并后的活动指针。
node *head; //刚开始打算直接用head1或者head2 作为合并后的头节点,感觉一直思路不清晰。
//干脆创建一个,在开始就给头节点赋值。一步一步来做,思路也清晰。
/* 初始化头节点必不可少,不然第一次p*/
if(head1->next->data<=head2->next->data){
head=head1; //把head1链表头结点作为合并后的头结点
}else{
head=head2; //把head2链表头结点作为合并后的头结点
}//不然第一次pCur 指向为NULL,pCur->next 没有空间。
//head=head1;
node * p1Cur,* p2Cur ,*pCur;//定义3个活动指针
//初始化3个活动指针
p1Cur=head1->next; //p1Cur指向链表1的第一个节点
p2Cur=head2->next; //p2Cur指向链表2的第一个节点
pCur=head; //初始化为合并后的头结点
printf("merge begin\n");
while(p1Cur!=NULL&&p2Cur!=NULL){
if(p1Cur->data<=p2Cur->data){ //从第一个节点开始放起
pCur->next=p1Cur;
p1Cur=p1Cur->next;
pCur=pCur->next;
}else{
pCur->next=p2Cur;
p2Cur=p2Cur->next;
pCur=pCur->next;
}
}
if(p1Cur!=NULL){
printf("p1Cur not null\n");
pCur->next=p1Cur;
}
if(p2Cur!=NULL){
printf("p2Cur not null\n");
pCur->next=p2Cur;
}
return head;
}
main 函数:
printf("create link1!\n");
node * head1=create();
print(head1);
printf("create link2!\n");
node * head2=create();
print(head2);
printf("merge link!\n");
node * mergeHead=mergeLink(head1,head2);
print(mergeHead);
运行结果:
create link1!
please input the node:→1
→2
→4
→6
→0
the link is: head→ 1 → 2 → 4 → 6
create link2!
please input the node:→2
→3
→5
→8
→9
→0
the link is: head→ 2 → 3 → 5 → 8 → 9
merge link!
merge begin
p2Cur not null
the link is: head→ 1 → 2 → 2 → 3 → 4 → 5 → 6 → 8 → 9
Press any key to continue
逆顺合并node * reverseMergeLink(node *head1,node * head2){ //两个非递减链表合并成一个非递增链表
//记住要有活动指针概念 原链表两个活动指针和合并后的活动指针。
node *head; //刚开始打算直接用head1或者head2 作为合并后的头节点,感觉一直思路不清晰。
//干脆创建一个,在开始就给头节点赋值。一步一步来做,思路也清晰。
/* 初始化头节点必不可少,不然第一次p*/
head=head1; //把head1链表头结点作为合并后的头结点,为了不开辟新的头结点
node * p1Cur,* p2Cur ,*pHead;//定义3个活动指针, pHead 方便头插的指针
//初始化3个活动指针
p1Cur=head1->next; //p1Cur指向链表1的第一个节点
p2Cur=head2->next; //p2Cur指向链表2的第一个节点
node * tail;
if(p1Cur->data<=p2Cur->data){
tail=p1Cur;
}else{
tail=p2Cur;;
}
pHead=head; //初始化为合并后的头结点
printf("merge begin\n");
while(p1Cur!=NULL&&p2Cur!=NULL){
if(p1Cur->data<=p2Cur->data){ //从第一个节点开始放起
pHead=p1Cur;
p1Cur=p1Cur->next;
pHead->next=head->next;
head->next=pHead;
}else{
pHead=p2Cur;
p2Cur=p2Cur->next;
pHead->next=head->next;
head->next=pHead;
}
}
if(p1Cur!=NULL){
printf("p1Cur not null\n");
while(p1Cur!=NULL)
{
pHead=p1Cur;
p1Cur=p1Cur->next; //注意刚才pCur和pHead 指向同一节点。为了头插,我需要变换pHead 指针但做次之前一定要把pCur 往下移动。
pHead->next=head->next;
head->next=pHead;
}
}
if(p2Cur!=NULL){
while(p2Cur!=NULL)
{
pHead=p2Cur;
p2Cur=p2Cur->next; //注意刚才pCur和pHead 指向同一节点。为了头插,我需要变换pHead 指针但做次之前一定要把pCur 往下移动。
pHead->next=head->next;
head->next=pHead;
}
}
tail->next=NULL; //这个非常重要,链表末尾就是要指向空。
return head;
}
main
printf("create link3!\n");
node * head3=create();
print(head3);
printf("create link4!\n");
node * head4=create();
print(head4);
printf("merge link!\n");
node * revMergeHead=reverseMergeLink(head3,head4);
print(revMergeHead);
运行结果:
create link3!
please input the node:→1
→2
→4
→5
→0
the link is: head→ 1 → 2 → 4 → 5
create link4!
please input the node:→2
→3
→6
→7
→8
→0
the link is: head→ 2 → 3 → 6 → 7 → 8
merge link!
merge begin
the link is: head→ 8 → 7 → 6 → 5 → 4 → 3 → 2 → 2 → 1
Press any key to continue