//考前一个月把真题中和王道书上所有的代码再自己手敲一遍,然后检查错误,所有的代码要非常熟练,其实瓜大考的代码题真的非常基础,多做点模板题就行
//注意把本章学习完成后,自己再动手把顺序表的课后题再敲一遍
//9.5 链表王道书课后代码题
#include<stdlib.h>
#include<iostream>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
typedef int ElemType;
#define MaxSize 100
typedef struct
{
ElemType data[MaxSize];
int top;//栈顶
}SqStack;
bool Push(SqStack &S,ElemType x)//入栈
{
if(S.top==MaxSize-1)return false;//栈满
S.data[++S.top]=x;//相当于S.top++ S.data[top]=x;
return true;
}
bool Pop(SqStack &S)
{
if(S.top==-1)return false;
cout<<S.data[top--]<<endl;//输出栈顶元素 首先cout 然后再进行top--
}
int Length(LinkList L)
{
int length;
LNode *p=L->next;
while(p!=NULL)
{
length ++;
}
return length;
}
//1.递归删除不带头结点的链表中值为x的结点
void Delete(LinkList &L,int x)
{
LNode *p;
if(L->data==x)
{
p = L;
L = L->next;
free(p);
Delete(L,x);
}//若data!=x,则向下继续调用
else { Delete(L->next,x); }
}
//2.删除所有值为x的结点
void DeleteElem(LinkList &L,int x)
{
LNode *p=L->next;
while(p!=NULL)
{
if(p->next->data==x)//注意是找到值为x的前面一个结点有利于删除
{
LNode *q=(LNode*)malloc(sizeof(LNode));
q = p->next;
p->next = q->next;
free(q);
}
p = p->next;
}
}
//3.链表反向输出
//法一:借用辅组数组
void PrintReverse(LinkList L,int a[])
{
int i = 0;
LNode *p=L->next;
while(p!=NULL)
{
a[i++]=p->data;
p = p->next;
}
for(int j=i;j>0;j--)cout<<a[j]<<endl; //在辅助数组中反向输出
}
//法二:利用栈
void PrintReverse(LinkList L)
{
SqStack &S;//使用栈
LNode *p=L->next;
while(p!=NULL)
{
Push(S,p->data); //入栈
}
while(S.top!=-1)
{
Pop(S);//依次出栈输出序列;
}
}
//4.删除链表中一个最小的元素
//法一:
void DeleteMinNode(LinkList &L)
{
int min;
LNode *p=L->next;
min = p->data;
//可以定义一个下一个结点是最小值结点的结点
while(p!=NULL)
{
if(p->data<min)min=p->data;//更新min
p = p->next;
}
for(p=L->next;p!=NULL;p=p->next)
{
if(p->next->data==min)
{
LNode *q = p->next;
p->next = q->next;
free(q);
}
}
}
//法二
void DeleteMinNode(LinkList &L)
{
int min;
LNode *p=L->next;
LNode *minpre;
min = p->data;
//可以定义一个下一个结点是最小值结点的结点
while(p!=NULL)
{
if(p->next->data<min)
{
min=p->next->data;
minpre = p;
}//更新min
p = p->next;
}
LNode *q=minpre->next;
minpre->next = q->next;
free(q);//minpre->next所指向的就是最小值的结点,即对q进行free
}
//5.链表逆置 :
//法一:头插法实现链表逆置
void Reverse(LinkList &L)
{
LNode *p=L->next;
L->next = NULL;//重新链表置空
L->next = p;//首先将L->next = p;指向p
while(p!=NULL)
{
LNode *r = p->next; //r为p的后继,防止断链 头插法一般要使用一个存储结点
p->next = L->next;
L->next = p;
p = r;
}
}
//6.设计算法使其元素递增有序:
//法一:借用辅助数组首先对链表中的元素进行排序,然后将排序好的序列导入链表,使其有序
void IncreaseSquence(LinkList &L,int a[])
{
}
//法二:直接对链表进行排序,交换结点的信息值:冒泡法 或者使用直接插入排序
void IncreaseSq(LinkList &L )
{
int temp;
LNode *p = L->next;
LNode *q=L->next;
while(q!=NULL)
{
for(p=q;p!=NULL;p=p->next)
{
if(p->data>p->next->data)
{
temp = p->data;
p->data = p->next->data;
p->next->data = temp;//交换
}
}
q = q->next;//冒泡排序,每一次把最小的送过来 时间复杂度为O(n^2)
}
}
//7.删除介于给定两个值之间的元素
void DeleteStoT(LinkList &L,ElemType s,ElemType t)
{
if(s>=t)return ;
LNode *p=L->next;
while(p!=NULL)
{
if(p->next->data > s&&p->next->data<t)
{
LNode *q = p->next;
p->next = q->next;
free(q);
}
p = p->next;
}
}
//答案一般都是使用的利用一个pre指针来进行删除,其实使用p->next判断的方法也是可行的,只不过没有保存指针
.
//10.划分奇偶元素
void Divided(LinkList &A,LinkList &B)
{
LNode *p=A->next;
LNode *r=B->next;//尾插法建立链表
int j = 1;
for(;p!=NULL;p=p->next,j++)
{
if(j%2==0)
{
LNode *q = p;
r->next = p;
r = p;
free(q);//若free(p),则找不到下一次循环进入的入口,不可将其作为辅助变量释放空间
}
}
}
//答案的方法是先保存A的信息然后把A置空,重新来创建链表
//11.拆分链表 :注意B是从小到大,对A使用尾插法,对B使用尾插法
void DisPatch(LinkList &A,LinkList &B,LinkList &C)
{
LNode *rA=A->next;//A的尾指针
LNode *rB;
LNode *p=C->next;
int j = 1;
for(;p!=NULL;p=p->next,j++)
{
if(j%2==0){rA->next = p;rA = p;}
else{rB=p->next;p->next = B->next;B->next = p;p=rB; }//注意在此使用尾插法
}
rA->next = NULL;//后面的元素置空
}
//12.删除重复的元素
void DeleteRepeatElem(LinkList &L)
{
LNode *p=L->next;
if(p==NULL)return ;
while(p!=NULL)
{
if(p->data == p->next->data)
{
LNode *q = p->next;
p->next = q->next;
free(q);
}
p = p->next;
}
}
//13.链表的归并
//法一:大胖の垃圾方法
/*
step1:首先将链表逆置
step2:开辟数组来存放归并排序的次序
step3:将数组中的元素放置于两个链表中覆盖原来的元素
*/
void Reverse(LinkList &L)
{
//将链表逆置
}
void MergeSort(LinkList &A,LinkList &B,int a[])
{
Reverse(A);
Reverse(B);
LNode *p=A->next;
LNode *q=B->next;
A->next = NULL;//将A置空
int k=0;
while(p!=NULL&&q!=NULL)
{
if(p->data > q->data){a[k++]=p->data;p=p->next;}
else {a[k++]=q->data;q=q->next;}
}
while(p!=NULL){a[k++]=p->data;p=p->next;}
while(q!=NULL){a[k++]=q->data;q=q->next;}
int i ,j=0;
//用A来保存归并后的结果
for(int i=0;i<k;i++)
{
p->data = a[i];
p = p->next;//依次向下搜索
}
//法二:利用头插法+归并
}
void MergeSort(LinkList &A,LinkList &B)
{
LNode *r;//用于头插
LNode *pa = A->next;
LNode *pb = B->next;
A->next = NULL;//A置为空保存归并后的结果
while(pa!=NULL&&pb!=NULL)
{
if(pa->data<=pb->data)
{
r = pa->next;
pa->next = A->next;
A->next = pa;
pa = r;
}
else
{
r = pb->next;
pb->next = A->next;
A->next = pb;
pb = r;
}
}
if(pa!=NULL)pb = pa;//以下两个判断逻辑可以实现对任何一个链表非空进行插入
while(pb)
{
r = pb->next;
pb->next = A->next;
A->next = pb;
pb = r;
}
free(B);
}
// 14.找公共元素
//法一:
void PublicElem(LinkList A,LinkList B,LinkList &C)
{
if(A->next==NULL||B->next==NULL)
{
return ;
}
LNode *p=A->next;
LNode *q=B->next;
LNode *r = C;//r指向C链表的尾部,利用尾插法来建立链表
while(p!=NULL)
{
for(q=B->next;q!=NULL;q=q->next)
{
if(p->data==q->data)//两层遍历找到A B的公共元素
{
LNode *s=(LNode*)malloc(sizeof(LNode)); //用此时的p或者q指针都可以
s->data = p->data;
r->next = s;
r = s;//尾插法重新将尾指针指向s
continue;//跳出
}
}
p = p->next;
}
}
//法二:元素较小者后移,利用三个分支判断,在第三个分支内创建链表
void PublicElem(LinkList A,LinkList B,LinkList &C)
{
if(A->next==NULL||B->next==NULL)
{
return ;
}
LNode *p=A->next;
LNode *q=B->next;
LNode *r = C;//r指向C链表的尾部,利用尾插法来建立链表
while(p!=NULL&&q!=NULL)
{
if(p->data < q->data)p = p->next;
else if(p->data>q->data)q = q->next;
else
{
LNode *s=(LNode*)malloc(sizeof(LNode)); //用此时的p或者q指针都可以
s->data = p->data;
r->next = s;
r = s;//尾插法重新将尾指针指向s
p = p->next;
q = q->next;
}
}
r->next = NULL;//注意利用尾插法创建链表完成后,最后尾指针的next域要指向NULL
}
//由于本题是递增序列,可以不用O(n2)复杂度的算法,可以利用一些优化的算法,看一下答案最优算法,链表归并问题
//15 取交集 存放到A 可以使用辅助数组
//算法思想:
//step1:两层循环分别遍历,由于最后需要将公共元素存放至A,则在A中只保存公共元素即可
//step2:将不是公共元素的结点free掉,最终保存都是公共元素结点
void PublicElem(LinkList &A,LinkList B)
{
if(A->next==NULL||B->next==NULL)
{
return ;
}
LNode *p=A->next;
LNode *q=B->next;
// LNode *r = C;//r指向C链表的尾部,利用尾插法来建立链表
while(p!=NULL)
{
for(q=B->next;q!=NULL;q=q->next)
{
if(p->data==q->data)//两层遍历找到A B的公共元素
{
continue;//找到相同跳出
}
}
LNode *de = p;
p = p->next;
free(de);//把不是公共的元素进行free
}
}
//答案做法:
void PublicElem(LinkList &A,LinkList B)
{
LNode *pa = A->next;
LNode *pb = B->next;
LNode *r = A;//利用尾插法建立链表
while(pa!=NULL&&pb!=NULL)
{
if(pa->data == pb->data)
{
r->next = pa;
r = pa;
pa = pa->next;//头插法将公共元素插入A中
LNode *q;
q = pb;
pb = pb->next;
free(q);//将B中的公共元素进行free 释放掉公共元素
}
else if(pa->data<pb->data)//若不相等,将较小的元素后移
{
LNode *de = pa;
pa = pa->next;
free(de);
}
else
{
LNode *de=pb;
pb = pb->next;
free(de);
}
}
while(pa)
{
LNode *de = pa;
pa = pa->next;
free(de);
}
while(pb)
{
LNode *de=pb;
pb = pb->next;
free(de);
}
r->next =NULL;
free(B);
}
//16题 B是否为A的子序列,先找到公共结点,然后依次遍历 类似于KMP
bool SubSequence(LinkList A,LinkList B)
{
LNode *pa = A->next;
LNode *pb = B->next;
while(pa&&pb)
{
if(pa->data==pb->data)
{
pa = pa->next;
pb = pb->next;
}
else
{
pa = pa->next;
pb = B->next;//匹配失败,B从头开始
}
}
if(pb=NULL)return true;
else return false;//匹配失败
}
//双链表结构体定义
typedef int ElemType ;
typedef struct DNode
{
ElemType data;
struct DNode *next;
struct DNode *prior;
}DNode,*DLinkList;
//17 判断双链表是否为对称的:重点是找到头和尾然后依次一个向前一个向后比较
void DUICHEN(DLinkList L)
{
DNode *p = L->next;//头结点指向的第一个结点
DNode *q = L->prior;//表尾指针
while(p!=NULL&&q!=NULL)//循环跳出条件??需要改正
{
if(p->data==q->data)
{
p = p->next;//后移
q = q->prior;//前移
}
else cout<<"不对称"<<endl; break;
}
cout<<"对称"<<endl;
}
//18 链接两个循环链表
void Link(LinkList &A,LinkList B)
{
//A B 为循环链表
LNode *h1=A->next;
LNode *h2=B->next;
while(h1!=NULL)
{
h1=h1->next;//找到A表的末结点
}
h1->next = B;//h1指向B链表的头指针
while(h2!=NULL)
{
h2=h2->next;
}
h2->next = A;//合并完成
}
//19 可以使用递归算法
void DeleteMinNode(LinkList &L)
{
int min;
while(L->next!=L)
{
LNode *p=L->next;
LNode *minpre=L;
min = p->data;
//可以定义一个下一个结点是最小值结点的结点
while(p!=NULL)
{
if(p->next->data<min)
{
min=p->next->data;
minpre = p;
}//更新min
p = p->next;
}
cout<<"最小值为:"<<min<<endl;
LNode *q=minpre->next;
minpre->next = q->next;
free(q);
}
free(L);
}
//24 判断一个链表是否有环 ?
//注意进入环以后不可能有指向NULL的结点,所有若slow或者fast==NULL则一定可以判定无环
LNode *FindLoopStart(LNode *head)
{
LNode *fast = head;
LNode *slow = head;
while(slow!=NULL&&fast->next!=NULL)
{
slow = slow->next;
fast = fast->next->next;
if(slow==fast)break;
}
if(slow==NULL||fast->next==NULL)
{
return NULL;
}
LNode *p1=head;
LNode *p2=slow;
while(p1!=p2)
{
p1=p1->next;
p2=p2->next;
}
return p1;
}
//25 2019年408真题
//本题可分为三个板块:1.找到中间结点 2.中间结点以后的内容进行逆置 3.头插法依次插入
void SpeicalSort(LinkList &L)
{
LNode *p=L->next;
LNode *q=L->next;//跳两步指针
LNode *r;
while(p&&q)
{
p = p->next;
q = q->next;
if(q->next!=NULL)q = q->next;//执行完以后p便是指向了中间结点
}
//中间结点以后的结点进行逆置
LNode *mid = p;//用mid暂存中间结点的位置
LNode *head = p;
while(p!=NULL)
{
r = p->next;
r->next = head->next;
head->next = r;
p = r;
}
head = L->next;
q = mid->next;//
while(q!=NULL)
{
r = q->next;
q->next = head->next;
head->next = q;
head = q->next;
q = r;
}
}
王道书链表课后代码题
最新推荐文章于 2024-04-02 19:28:46 发布