头插防断链;尾插留尾针
算法思想1:(四个指针的情况)
p指针(遍历链表)、pre指针(指向p的前驱)、minp(标记最小值结点)、minpre指针(用来标记最小值的前驱);
若p->datadata,将p和pre分别赋值给minp,minpre指针;
扫描完成后,minp指向的是最小值结点,minpre指向的最小值结点的前驱,将minp结点删除即可
void Del_Min(LinkList &L) {
LNode *p=L->next; //遍历当前链表
LNode *pre=L; //指向p的前驱
LNode *minpre=pr,*minp=p; //minp用来指向当前链表的最小值结点
//minpre指向最小值结点的前驱,方便后序结点的删除
//查找出最小值的结点
while(p!=NULL){
if(p->data<minp->data){ //当前遍历的结点,若比min指针所指的结点还要小的时候,
minp=p; //将minp和minpre值修改为p和pre
minpre=pre;
}
pre=p; //当前结点判断完后,p和pre指针继续向后移动
p=p->next;
}
//删除最小值的结点
minpre->next=minp->next; //minp的前驱指向minp的后继,修改结点指向
free(minp); //将最小值的结点删除,释放空间
}
算法思想2:只需要两个指针;
*p指针用来遍历单链表,*minp指针用来指向最小值的结点
void Del_Min(LinkList &L) {
LNode *p=L->next; //遍历当前链表
LNode *minp=p; //minp用来指向当前链表的最小值结点
LNode *q; //临时指针,用来删除结点,释放内存空间
while(p!=NULL) {
if(p->data<minp->data){ //移动minp到p结点
minp=p;
}
p=p->next;
}
//偷天换日思想:利用当前找到的最小值的结点minp,然后minp后继结点的值赋值给minp,将minp指向的结点的后继删除
//删除结点的操作
q=minp->next;
minp->data=q->data; //用minp后继结点的值来替换minp结点的值,并将minp的后继结点删除
minp->next=q->next;
free(q);
}
思想:
LinkList * Head_CreatLinkList(LinkList &L){
int x;
LNode *s;
L=(LinkList *)malloc(sizeof(LNode)); //创建一个头结点
scanf("%d",&x);
while(x!=-1){ //当输入的值为-1时,停止插入
s=(LNode *)malloc(sizeof(LNode)) ; //动态一个结点
s->data=x;
s->next=L->next; //进行插入操作,修改指针指向
L->next=s;
scanf("%d",&x);
}
}
算法思想:
//尾插法
LinkList List_TailInsert(LinkList &L){
int x;
L=(LinkList) malloc(sizeof (LNode));//建立头结点,初始化一空表
LNode *s,*r=L; //r为表尾指针
scanf("%d",&x); //输入结点的值
while (x!=1000){ //当输入1000代表结束
//在r结点之后插入x元素
s=(LNode *) malloc(sizeof (LNode));
s->data=x;
r->next=s;
r=s; //r指向新的表的尾结点
scanf("%d",&x); //输入结点的值
}
r->next=NULL; //为几点指针置为空
return L;
}
算法思想1:利用头插法的思想对单链的元素进行逆置
//头插法置逆单链表
LinKList reverse_LinkList(LinkList &L){
LNode *p,*s; //p指针用来遍历单链表,s指针用来p的后继防止断链
p=L->next;
L->next=NULL; //将表头结点置为空
while(p!=NULL){
r=p->next; //保留后继防止断链
p->next=L->next;
L->next=p;
p=r;
}
}
算法思想2:三个指针来实现
pre指针:p的前驱
p指针:遍历单链表
r指针:p的后继
只需要修改pre和p的指向,然后将三个指针同时向后移动一个单位,最后只需将p->next=pre,L->next=pre即可
//头插法置逆单链表
LinKList reverse_LinkList(LinkList &L){
LNode *p,*pre,*r; //p指针用来遍历单链表,r指针用来p的后继,pre指针用来指向p的前驱
//初始化指针
p=L->next;
r=p->next; //r指向p的后继
pre=NULL;
while(r!=NULL){ //r等于NULL的时候结束
p->next=pre;//修改pre和p的指向
//pre,p,r向偶移动一个单位
pre=p;
p=r;
r=r->next;
}
//当r是NULL的时候,并没有修改pre到p的指向
p->next=pre //修改pre到p的指向
L->next=p; //将表头结点指向p
}
算法思想:
需要两个指针:*pre(用来指向p的前驱)、*p(用来遍历链表)*q(用来删除结点)
当p指针指向的结点的值在给定的两个值之间的时候,用pre->next=p;p指针后移,然后释放要删除的结点。
void Del_sk(LinkList &L,int s,int k) //删除单链表在s和k之间的结点
{
LNode *q,*pre=L,*p=L->next;
while(p!=NULL){
if(p->data>=s&&p->data<=k)
{
q=(LNode *)malloc(sizeof(LNode)); //动态申请一个结点,用来释放要删除的结点
q=p;
pre->next=p->next; //修改指针指向跳过删除结点
pre=p; //后移pre指针
p=p->next; //后移p指针
free(q); //释放待删除的结点
}
}
}
算法思想1:暴力求公共结点(当两个链表遍历的结点相等时,即为公共结点)
时间复杂度:O(la.length*lb.length)
LNode * Search_Common(LinkList La,LinkList &\Lb){
//初始化
LNode *la=La->next;
LNode *lb=Lb->next;
if(la==NULL||lb==NULL) return NULL;
while(la!=NULL){
while(lb!=NULL){
if(la==lb) return la; //相同的时候,返回结点
lb=lb->next;
}
la=la->next; //la指针后移
lb=Lb->next; //重新指向Lb链表的第一个元素,进行下一轮循环
}
return NULL;
}
算法思想2:利用两链表的长度差k,将较长的链表指针往后移动k位,然后对两链表的指针进行同步移动,进行判断即可。
时间复杂度:O(la.length+lb.length)
LNode * Search_Common(LinkList La,LinkList Lb){
//初始化
LNode *la=La->next;
LNode *lb=Lb->next;
//求两链表的长度
int a=Length(La);
int b=Length(lb);
//将较长的链表向后移动k位
if(a>b){
k=a-b;
while(k>0){
la=la->next;
k--;
}
}
else{
k=b-a;
while(k>0){
lb=lb->next;
k--;
}
}
//最后,进行同步比较
while(la!=NULL){
if(la==lb)
return la;
la=la->next;
lb=lb->next;
}
return NULL;
}
算法思想01:不断的使用尾插法(保证相对顺序保持不变),依次生成链表A,B;设置一个计数器i(用来判断是奇数还是偶数结点)
LinkList Split_tow(LinkList &A){
LNode *la=A->next; //la用来遍历A链表
LNode *ra,*rb;
int i=1; //用来技术
LinkList B =(LinkList )malloc(sizeof(LNode)); //创建一个结点
A->next=NULL;
B->next=NULL;
ra=A;
rb=B;
while(la!=NULL){
if(i%2==0) //插入到B链中--尾插
{
rb->next=la;
rb=la;
}
else{ //插入到A链中 --尾插
ra->next=la;
ra=la;
}
la=la->next;
i++;
}
//将最后链表AB的最后一个结点指向NULL
ra->next=NULL;
rb->next=NULL;
return B;
}
算法思想02:不断的使用尾插法(保证相对顺序保持不变),依次生成链表A,B;顺序的分别给AB插入
LinkList Split_tow(LinkList &A){
LNode *p=A->next; //la用来遍历A链表
LNode *ra,*rb;
LinkList B =(LinkList )malloc(sizeof(LNode)); //创建一个结点
A->next=NULL;
B->next=NULL;
ra=A;
rb=B;
while(p!=NULL){
//奇数肯定是尾插 1357..
ra->next=p;
ra=p;
p=p->next;
if(p!=NULL){ //偶数定是 尾插到B中 2468..
rb->next=p;
rb=p;
p=p->next;
}
}
//将最后链表AB的最后一个结点指向NULL
ra->next=NULL;
rb->next=NULL;
return B;
}
算法思想:对与a数列而言,采用尾插法(保证相对顺序保持不变)(保证相对顺序保持不变),对与b数列而言采用头插法(保证逆序);依次生成链表A,B。
int Split_tow(LinkList &CLinkList &B,LinkList &A){
LNode ra; //尾指针
LNode *p=C->next; //p用来遍历A链表
LNode *r; //防止头插的时候断链
B =(LinkList )malloc(sizeof(LNode *)); //创建一个头结点的单链表
A =(LinkList )malloc(sizeof(LNode *)); //创建一个头结点的单链表
A->next=NULL; //用尾插
B->next=NULL; //用头插
ra=A;
if(p==NULL) return 0;
while(p!=NULL){
ra->next=p;
ra=p;
p=p->next;
if(p!=NULL){
r=p->next;
//头插B
p->next=B->next;
B->next=p;
p=r; //防断链
}
}
//使A链的最后一个结点指向NULL
ra->next=NULL;
return 1;
}
递增有序;相同元素一定相邻
算法思想1:pre指针表示p的前驱,p指针用来遍历
void Del_SV(LinkList &L){
//初始化结点
LNode *p=L->next->next;
LNode *temp,*pre=L->next;
while(p!=NULL){
if(p->data==pre->data){ //找到元素重复的结点
temp = (LNode)malloc(sizeof(LNode));
temp=p;
pre->next=p->next; //删除p结点
p=p->next; //此时不需要移动pre指针
free(temp);
}
else{ //不是相同的,pre和p指针向后移动
pre=p;
p=p->next;
}
}
}
算法思想2:偷天换日(一个指针)
算法思想:用两个指针分别指向两个单链表,然后将一个表置为空,将两指针较小的元素利用头插法插入到空表中
void Merge_LinkList(LinkList &La,LinkList &Lb){
LNode *la=La->next;
LNode *lb=Lb->next;
LNode *r; //防止断链
La->next=NULL; //将所有的元素都插入到La链表中,用来原来的存储空间
//第一中情况 :La和Lb都一样长
while (la!=NULL&&lb!=NULL){
if(la->data>lb->data){ //将Lb链表中的元素插入到La中(头插法)
r=lb->next; //记录lb,防断链
lb->next=La->next; //lb结点头插到La中
La->next=lb;
lb=r; //
}
else{ //la->data小的时候
r=la->next;
la->next=La->next;
La->next=la;
la=r;
}
}
//第二种情况,两条链表不一样长,只要将剩余的元素插入到La中
while(la!=NULL){ //la链表有剩余时
r=la->next;//防断链
la->next=La->next;
La->next=la;
la=r;
}
while(lb!=NULL){ //若lb链表有剩余时
r=lb->next;//防断链
lb->next=La->next;
La->next=lb;
la=r;
}
}