线性表

线性表的基本操作

InitList(&L)      //初始化表,构造一个空的线性表Length(L)            //求表长,返回线性表L长度LocateElem(L,e)       //按值查找操作,在表L中查找具有给定关键字个数GetElem(L,i)     //按位查找操作,在表L中查找第i个位置元素的值ListInsert(&L,i,e)   //插入操作,在表L中第i个位置插入指定元素ListDelete(&L,i,&e)    //删除操作,删除表L中第i个位置的元素,用e返回删除元素的值PrintList(L)       //输出表L中的元素Empty(L)          //判断表L是否为空操作DestoryList(&L)     //销毁线性表L,释放其空间

线性表的顺序表示

顺序表可以随机存取或者顺序存取

//线性表的顺序存储结构
#define MaxSize 50
typedef struct{ElemType data[MaxSize];      //一维数组静态分配int length;
}SqList;#define InitSize 100
typedef struct{ElemType *data;          //动态分配数组的指针int MaxSize,length;      //数组最大容量和当前个数
}SeqList;

1、插入操作

bool ListInsert(SqList &L,int i,ElemType e){if(i<1||i>L.length)        //保护性检查,范围是否有效return false;if(L.length>MaxSize)return false;for(int j=L.length;j>=i;j--)L.data[j]=L.data[j-1];      //后移元素 下标j-1元素位置给j元素位置L.data[j]=e;L.length++;        //插入一个元素后长度+1return true;
}

2、删除操作

bool ListDelete(SqList &L,int i,ElemType &e){if(i<1||i>L.length)       //保护性检查,范围是否有效return false;e=L.data[i-1];for(int j=i;j<L.length;j++)L.data[j-1]=L.data[j];       //前移元素  下标j位置给j-1位置L.length--;      //删除一个元素后return true;
}

3、按值查找(顺序查找)

int LocateElem(SqList L,ElemType e){int i;for(i=0;i<L.length;i++)if(L.data[i]==e)return i+1;        //下标为i的元素,位序为i+1return 0;
}

线性表的链式表示

链表只能顺序存取,不可随机存取

//单链表的结构定义
typedef struct LNode{ElemType data;         //数据域struct LNode *next;        //指针域
}LNode,*LinkList;

头结点是带头结点链表中的第一个结点,结点内不存放信息;头结点的指针域指向线性表的第一个元素结点

头指针始终指向链表的第一个结点

带头结点 空表判断:L==NULL

不带头结点 空表判断:L->next==NULL

单链表基本操作

1、头插法建立单链表

分析:从一个空表开始,若带有头结点,则将新建结点放到数据域中,将新结点插入到当前链表的表头,头结点之后。
头插法建立的单链表,读入数据的顺序与生成的链表中元素的顺序相反。

LinkList List_HeadInsert(LinkList &L){L=(LinkList)malloc(sizeof(LNode));    //创建头结点,初始链表为空L->next=NULL;scanf("%d",&x);while(x!=9999){s=(LNode* )malloc(sizeof(LNode));   //建立一个新带插入结点,为其数据域赋值s->data=x;s->next=L->next;        //调整指针域next 每次都是将新结点插入到当前链表的表头之后L->next=s;scanf("%d",&x);}return L;
}

2、尾插法建立单链表

分析:新建结点插入到当前链表的表尾,需要增加尾指针r,始终指向当前链表的表尾结点

LinkList List_TailInsert(ListList &L){L=(LinkList)malloc(sizeof(LNode));LNode *r=L;        //设置尾指针r 初始指向表头结点scanf("%d",&x);while(x!=9999){s=(LNode* )malloc(sizeof(LNode));    //建立一个新带插入结点,为其数据域赋值s->data=x;r->next=s;     //调整指针域next 将s插入r之后,修改s为尾结点r=s;scanf("%d",&x);}r->next=NULL;  //所有结点插入结束后,修改尾指针r->next为空return L;
}

【注】头插法和尾插法区别:头插法形成数据顺序为逆序,尾插法形成数据顺序为顺序;头插法依据头结点,尾插法依据尾结点

3、按序号查找结点值

分析:单链表中第一个结点出发,顺着指针next域逐个向下,直到找到第i个结点为止,否则找到表尾返回最后一个结点指针域NULL

LNode *GetElem(LinkList L,int i){int j=1;   //从前开始遍历,计数,与第i个结点比较LNode *p=L->next; //p指向链表的第一个结点//特殊情况判断if(i==0) return L;if(i<1)return NULL;while(p!=NULL&&j<i){ //没有遍历到表尾或还未找到i 就继续向后遍历p=p->next;j++;}return p;
}

4、按值查找结点

分析:单链表第一个结点出发,依次比较表中各结点数据域的值,若某结点数据域的值==给定值e,直接返回结点指针;找到表尾也没有,返回NULL

LNode *LocateElem(LinkLIst &L,ElemType e){LNode *p=L->next;while(p!=NULL&&p->data!=e)p=p->next;return p;
}

5、插入结点(第 i-1 个结点后插入;第 i 个结点前插入)

分析:插入结点将值为x的新结点插入到第 i 个位置上,先检查插入位置的合法性,找到待插入结点位置的前驱结点【第 i-1 个结点】,再插入其后面

p=GetElem(L,i-1);   //查找i-1位置的结点,也就是i位置的前驱结点
s->next=p->next; //s所指新结点指向p的后一个结点
p->next=s;

【注】上述例子将s插入p之后,若要使s在p之前,可以增加数据域交换

temp=p->data;
p->data=s->data;
s->data=temp;

6、删除结点

分析:删除结点将单链表第 i 个结点的值删除。先检查删除位置的合法性,查找表中第 i-1 个结点【被删除结点前驱结点】

若p为前驱,q为待删除结点,将p的指针域指向q的下一个结点,q就被删除

p=GetElem(L,i-1);   //p为待删除结点的前驱结点
q=p->next;
p->next=q->next;
free(q);

7、求表长

int count=0;
p=L;   //带头结点
while(p->next!=NULL){count++;p=p->next;
}

双链表

//双链表中的结点类型
typedef struct DNode{ElemType data;struct DNode *prior,*next;   //prior指向前驱指针,next指向后继指针
}DNode,*DLinkList;

双链表插入

分析:双链表中p所指结点之后插入s

s->next=p->next;  //修改后继指针和后继的前驱
p->next->prior=s;
s->prior=p;
p->next=s;          //修改p的后继,最后结果是p是s的前驱 s是p的后继

双链表删除

分析:删除双链表中p的后继结点q

p->next=q->next;  //修改后继 前驱 都是对q->next而言
q->next->prior=p;

循环链表

循环单链表

最后一个结点的指针不是NULL 改为指向头结点的指针

表尾结点r的next域指向L,表中没有指针域为NULL的结点,判空条件L->next==L

不设头指针而仅设尾指针,r->next也就是头指针,对于表头表尾的操作都只要O(1)的时间复杂度

循环双链表

头结点的prior要指向表尾结点

循环双链表L,结点p为尾结点 p->next==L;

循环双链表L空表,头结点的L->prior=L?;L->next=L?

静态链表

借助数组来描述线性表的链式存储结构,结点也有数据域data和指针域next,指针是结点的相对地址(数组下标)【游标】

#define MaxSize 50   //静态链表的最大长度
typedef struct{ElemType data;   //存储数据元素int next;       //下一个元素的数组下标
}SLinkList[MaxSize];

静态链表 next==-1作为其结束的标志

静态链表的插入、删除与动态链表的相同,只需要修改指针,而不需要移动元素

课后习题

1、不带头结点单链表L 递归删除所有值为x的结点

分析:删除以L为首的结点指针单链表中所有值==x的结点

​ 建立递归模型

​ 终止条件:f(L,x) 不做任何事情 L为空表

​ 递归主体:f(L,x)==删除L的结点 L->data=x + f(L->next,x) 后面还有没有值为x的结点

​ 其他情况:f(L,x)==f(L->next,x)

void Del_X(LinkList &L,ElemType x){LNode *p;if(L==NULL)return ;if(L->data==x){p=L;L=L->next;free(p);Del_X(L,x);      //判断后面有没有值为x的结点}elseDel_X(L->next,x);    //继续向后判断
}

2、带头结点的单链表L 删除所有值为x的结点【释放空间,假设值为x的结点不唯一】

分析:pre为p的前驱结点,用于删除防止断链,p为遍历指针从头到尾扫描单链表,pre指向p结点的前驱,若p指向结点值为x就删除,并让p指向下一个结点,否则让pre、p同步后移一个结点。无序单链表中删除值为x结点,x可以设定范围或者条件,仅需修改if语句

void Del_X(LinkList &L,ElemType x){LNode *p=L->next,*pre=L,*q;while(p!=NULL){if(p->data==x){q=p;     //用q保存p结点,作为删除结点p=p->next;pre->next=p;free(q);}else{pre=p;p=p->next;}}
}

3、带头结点的单链表L 实现从尾到头反向输出每个结点的值

分析:依次将L->next不为空的结点入栈中,直到最后一个结点,退栈时就是逆序输出——>递归解决

void  Print_Rev(LinkList L){if(L->next!=NULL)Print_Rev(L->next);if(L!=NULL)printf("%d",L->data);
}

4、带头结点的单链表L 删除一个最小值结点的算法【假设最小值结点是唯一的】

分析:设置前驱结点minpre【最小值结点的前驱】pre【p的前驱结点】用p->data与minp->data进行比较,如果有更小的结点存在就将值保存在minpre与minp中,否则就扫描下一个结点,直到整个表遍历结束再删除minp所指的结点

void Del_Min(LinkList &L){LNode *pre=L,*p=L->next;LNode *minpre=pre,*minp=p;while(p!=NULL){if(minp->data>p->data){minpre=pre;minp=p;}pre=p;p=p->next;}minpre->next=minp->next;free(minp);
}

5、带头结点的单链表L 就地逆置【就地:辅助空间复杂度为O(1)】

分析1:头插法逆置单链表,取下头结点,p为遍历指针,r为p的后继【保持不断链】,每次将p插到L的后面,实现逆置

void Reverse_List(LinkList &L){LNode *p,*r;p=L->next;L->next=NULL;while(p!=NULL){r=p->next;p->next=L->next;L>next=p;p=r;}
}

分析2:指针反转实现,需要前驱指针哦pre 遍历指针p 后继指针r。取下头结点,对于第一个结点令其指针域为NULL(新表的最后一个结点/表尾结点);对于最后一个结点,要将头结点重新指向它,也就是第一个结点

void Reverse_List(LinkList &L){LNode *pre,*p=L->next,*r=p->next;p->next=NULL;    //第一个结点置为空while(r!=NULL){pre=p;       //依次修改各个指针的值p=r;r=r->next;p->next=pre;  //指针反转}L->next=p;      //最后一个结点由头结点指向
}

6、带头结点的单链表L 设计一个算法使其元素递增有序

分析:直接插入法排序,先构造只有一个元素的单链表,将p所指的结点与之链表中的比较,p的后继用r保存,如果比表中某元素小,头插入其前面,直到表为空

void Sort_List(LinkList &L){LNode *p=L->next,*pre,*r=p->next;p->next=NULL;   //构造只有一个结点的单链表,并且p指向下一个元素p=r;while(p!=NULL){r=p->next; //保存后继pre=L;       //每次都是要遍历整个单链表比较,pre的值每次都要重新从L开始while(pre->next!=NULL&&pre->next->data<p->data)      //寻找带插入结点的前驱结点pre=pre->next;p->next=pre->next;   //头插法插入结点pre->next=p;p=r;      //遍历下一个结点}
}

7、元素结点值无序的带头结点的单链表L 删除表中所有介于给定的两个值之间的元素的元素

分析:类似习题2 if中设定x的范围即可

void Del_X(LinkList &L,int mink,int maxk){LNode *p=L->next,*pre=L,*q;while(p!=NULL){if(p->data>mink&&p->data<maxk){q=p;p=p->next;pre->next=p;free(q);}else{pre=p;p=p->next;}}
}

8、找出给定两个链表的公共结点

分析:若两个链表有公共结点,则公共结点之后所有结点都重合,可以用两个指针同时遍历到最后一个结点,若重合就有公共结点,否则无公共结点。对于两个长度一样的链表可以用上述方法。
对于不一样长度的链表需求出长度差,若一个链表比另一个链表长k个结点,可以先在长的链表上遍历k个结点之后再同时遍历,两个链表就可同时到达尾结点,直到找到公共结点为止。

LinkList Search_SameNode(ListList L1,LinkList L2){int len1=Length(L1),len2=Length(L2);LinkList longlist,shortlist; //指向表长较长和较短链表if(len1>len2){      //求长度差+修改遍历指针longlist=L1->next;shortlist=L2->next;k=len1-len2;}else{longlist=L2->next;shortlist=L1->next;k=len2-len1;}while(k--){            //表长较长的链表移动长度差为k个元素,与短表同步longlist=longlist->next;}while(longlist!=NULL){        //两个表同步向后遍历,一旦找到相同结点就返回,否则就继续遍历if(longlist==shortlist)return longlist;else{longlist=longlist->next;shortlist=shortlist->next;}}  return NULL;   //没有找到就返回空
}

9、带头结点的单链表L 递增输出单链表各结点数据元素,释放结点占用空间【遍历+输出+释放】

分析:对单链表进行遍历,第一次找出最小值结点输出,释放结点,第二次找出次小值结点输出……直到链表为空

void Print_Sort(LinkList &L){LNode *p,*pre;while(L->next!=NULL){pre=L;          //p指向第一个结点,pre指向p的前驱,每次从头开始遍历p=pre->next; while(p->next!=NULL&&pre->next->data>p->next->data){ //保存最小值结点的前驱指针和遍历指针pre=p;p=p->next;}printf(pre->next->data); //由于pre=p 所以pre就是最小值结点u=pre->next;     //p结点为待删除结点pre->next=p->next;free(u);}free(L);
}

10、带头结点的单链表A分解为带头结点的单链表A和B,使得A表中含有原表中序号为奇数元素,B表中含有原表中序号为偶数元素,相对顺序不变

分析:设置一个访问序号的变量(初值为0)每访问一个结点序号自动+1,根据序号的奇偶性将结点插入A表或者B表中,直到表尾。由于元素相对顺序不变,所以采用尾插法建立单链表

LinkList Creat_List(LinkList &A){int i=0;B=(LinkList)malloc(sizeof(LNode));B->next=NULL;LNode *pa=A,*pb=B;       //A表与B表的遍历指针p=A->next;      //拆取A表的表头结点 p是原始表中的遍历指针A->next=NULL;while(p!=NULL){i++;if(i%2==0){     //偶数编号的结点 尾插法插入B表中rb->next=p;rb=p;}else{ra->next=p;ra=p;}ra->next=NULL;rb->next=NULL;reutrn B;     }
}

11、设C={a1,b1,a2,b2……an,bn}为线性表,采用带头结点的单链表L存放,分解两个线性表,使得A={a1,a2,……an} B={bn,……b2,b1}

分析:和上题思路类似,不采用编号方法,直接将结点插入A表后再将下一结点插入B表,采用头插法建立B链表【逆序】

LinkList Creat_List(LinkList &A){B=(LinkList)malloc(sizeof(LNode)); //创建B的表头B->next=NULL;LNode *pa=A,*q;p=A->next;while(p!=NULL){ra->next=p;      //直接把当前结点插入到A的表尾【尾插法】ra=p;p=p->next;       //指向下一个结点,插入B链表if(p!=NULL)      //q记忆p的后继,防止断链q=p->next;p->next=B->next;  //头插插入B的表头后B->next=p;p=q;      //修改p的指针为下一个结点}
}

12、递增有序的单链表中,有数值相同的元素存在,设计算法去掉数值相同元素,使得表中不再有重复的元素。例如(7,10,10,21,30,42,42,42,51,70)变为(7,10,21,30,42,51,70)

分析:p为工作指针,所有相同数值的结点均为相邻结点,用q保存p的下一个结点,如果与p结点数值相同就删除,并指向下一个结点

void Del_Same(LinkList &L){LNode *p=L->next,*q;while(p->next!=NULL){q=p->next;if(q->data==p->data){  //只有结点值不同才后移,否则还是从当前结点开始向后比较p->next=q->next;free(p);}elsep=p->next;}
}

13、两个按照元素值递增次序排列的单链表,将这两个单链表归并为一个按元素值递减次序排序的单链表,要求利用原来两个单链表的结点存放归并后的单链表

分析:两个链表原先按照元素值递增排列,合并过程中,从第一个结点起进行比较,将小的结点放入链表中,后移工作指针。最后按照递减次序—头插法,如果还有剩余的元素没有插入,直接将元素插入新表【头插】

void Merge_List(LinkList &La,LinkList &Lb){LNode *pa=La->next,*pb=Lb->next,*r;La->next=NULL;     //将La作为新链表的头指针,La中的元素pa指向while(pa!=NULL&&pb!=NULL){if(pa->data<=pb->data){r=pa->next;pa->next=La->next;   //将pa元素的值头插入La中La->next=pa;pa=r;   //指向下一个结点}else{r=pb->next;pb->next=La->next; //将pb元素的值头插入La中La->next=pb;pb=r;   //指向下一个结点}//如果pa指向的结点不为空,pb指向剩余结点,即使pa为空,pb不为空下面循环依旧执行【将剩余结点插入】if(pa!=NULL)   pb=pa;while(pb!=NULL){r=pb->next;pb->next=La->next;    //将pb元素的值头插入La中La->next=pb;pb=r;   //指向下一个结点}free(Lb); //Lb全部插入La所指链表中,释放表头结点}
}

14、带头结点的单链表A和B,元素递增有序,设计一个算法从A和B中的公共元素产生单链表C,不破坏A、B结点

分析:表A、B均有序,可以从第一个元素比较A、B,若元素值不相等,将值较小的指针后移,若元素值相等,创建一个值等于两个结点元素值的新结点,尾插法插入到新表C中,并将A、B所指的指针后移

void Get_SameList(LinkList &A,LinkList &B){LNode *pa=A->next,*pb=B->next,*r,*s;LinkList C=(LinkList)malloc(sizeof(LNode));      //新建链表C 设置尾指针rr=C;while(pa!=NULL&&pb!=NULL){if(pa->data<pb->data)pa=pa->next;else if(pa->data>pb->data)pb=pb->next;else{s=(LNode*)malloc(sizeof(LNode));s->data=p->data;   //新建1个s结点作为插入结点r->next=s;       //尾插法r=s;pa=pa->next;pb=pb->next;}r->next=NULL;    //最后将C的尾指针置为空}
}

15、链表A和链表B分别表示两个集合,元素递增排序。求A和B的交集,存放于A链表中。

分析:同习题13采用归并的思想,设置两个工作指针pa和pb,对两个链表同时遍历,只有元素相同才链接到A表中并且保留一个,对于B表元素全部释放,由于元素相对顺序不改变,所以采用尾插法

void Union_List(LinkList &La,LinkList &Lb){LNode *pa=La->next,*pb=Lb->next,*pc=La;      //La作为结果链表while(pa!=NULL&&pb!=NULL){if(pa->data==pb->data){pc->next=pa;   //尾插法将pa插入La所指表中,并将pa指向下一个结点pc=pa;pa=pa->next;q=pb;        //将pb所在结点释放,并且pb指向下一个结点pb=pb->next;free(q);}else if(pa->data<pb->data){     //对于结点值小的元素,直接释放结点,后面必定不存在公共结点q=pa;pa=pa->next;free(q);}else{q=pb;pb=pb->next;free(q);} }//对于各表中剩余的结点,直接释放,必定不存在公共结点while(pa!=NULL){q=pa;pa=pa->next;free(q);}while(pb!=NULL){q=pb;pb=pb->next;free(q);}pc->next==NULL;      //尾插法需要将最后一个结点置空free(Lb);
}

16、两个整数序列A和B已经存入两个单链表中,设计一个算法,判断B是否是A的连续子序列

分析:两个整数序列存入链表中,从两个链表的第一个结点开始,若对应数据元素相等,同时后移指针;若对应数据元素不相等,A从上次比较结点的后继开始,B从第一个开始比较,直到B的表尾表示匹配成功。若A到表尾B未到表尾,表示匹配失败。需要记忆每次A开始的结点,以便下次继续从这个位置重新开始

int Pattern(LinkList &A,LinkList &B){LNode *pa=A,*pb=B,*pre=pa;   //pre记录每次A开始的比较的位置,一旦不相等就返回while(pa!=NULL&&pb!=NULL){if(pa->data==pb->data){pa=pa->next;pb=pb->next;}else{pre=pre->next;   //从先前开始比较结点的下一个结点开始,重新给pa赋值,pb重新从B的表头开始pa=pre;pb=B;}}if(pb==NULL)     //如果B表遍历结束,就说明是连续子序列,否则就不是return 1;elsereturn 0;
}

17、带头结点的双循环链表是否对称

分析:设置两个遍历指针,p从左向右扫描,q从右向左扫描,直到指向同一结点(链表中奇数个结点:p==q;链表中偶数个结点:p->next=q或q->prior=p)若所指结点相同就继续遍历,否则结束循环

int Symmetry(DLinkList &L){DNode *p=L->next,*q=L->prior; //设置两头的遍历指针while(p!=q&&q->next!=p){    //如果没有遍历到中间位置,还在两端就继续比较if(p->data==q->data){ //相等情况下,继续向中间遍历,一个指向后继,一个指向前驱p=p->next;    q=q->prior;}elsereturn 0;}return 1; //全部遍历结束可以判断是否对称
}

18、链表头指针分别为h1和h2,将链表h2链接到h1之后,要求链接后的链表依旧保持循环链表的形式

分析:先找到两个链表的尾指针,将第一个链表的尾指针与第二个链表的头结点链接起来,就形成了一个循环链表——h1+h2

LinkList Link(LinkList &h1,LinkList &h2){LNode *p=h1,*q=h2;while(p->next!=h1)      //找p和q的尾结点p=p->next;while(q->next!=h2)q=q->next;//链接首尾结点p->next=h2;q->next=h1;return h1;        //最终形成以h1为首的链表
}

19、带头结点的循环单链表,结点值均为整数,反复找出单链表中结点值最小的结点并输出【递增输出】然后从结点中删除直到单链表为空,再删除表头结点

分析:类似习题4,只是判断链表结束的条件不同,循环单链表结束标志是(L->next!=L)每次都要从头开始遍历,因为是反复找出结点最小的结点

void Del_Min(LinkList &L){LNode *p,*pre,*minp,*minpre;while(L->next!=L){     //反复找出!表不空就循环,直到表为空pre=L;            //pre为p的前驱结点,minpre为minp的前驱结点p=L->next;minpre=pre;minp=p;while(p!=L){ //循环一次的条件if(p->data<minp->data){       //如果有更小的结点存在就将其结点值进行修改minpre=pre;minp=p;}pre=p;      //遍历后面的结点p=p->next;}printf("%d",minp->data);   //输出本次循环所得最小值结点 最后形成的数据是从小到大输出的有序序列minpre->next=minp->next;free(minp);}
}

20、带头结点的单链表,表头指针list。查找链表倒数第k个位置上的结点(k为整数)若查找成功输出结点的data域数值,返回1否则返回0

分析:使用两个指针变量p和q,初始都指向第一个结点【头结点的下一个结点】p移动到第k个结点时,q与之同步向后移动;p移动到最后一个结点时,q所指向的就是倒数第k个结点【p和q之间始终相差k个结点,第一次为正数第k个,第二次为倒数第k个】

int Search_List_k(LinkList list,int k){LNode *p=list->next;*q=list->next;int count=0;   //计数,判断是否p移动到第k个结点?while(p!=NULL){if(count<k)count++;elseq=q->next; //若count==k就将q开始向后移动  p每次都要移动,但是q需要条件p=p->next;}if(count<k)     //k的值无效,超过了线性表的长度return 0;else{      //如果最后count的值==k 说明存在有效k值,q所指就是倒数第k个结点printf("%d",q->data);return 1;}
}

21、带头结点的单链表保存单词,当两个单词相同后缀时,可以共享相同的后缀存储空间,设str1 str2分别指向两个单词所在的单链表的头结点,找出str1 str2 所指两个链表的共同后缀的起始位置【第一个公共结点的位置】

分析:类似习题8,对于不一样长度的链表需求出长度差,若一个链表比另一个链表长k个结点,可以先在长的链表上遍历k个结点之后再同时遍历,两个链表就可同时到达尾结点,直到找到公共结点为止。

LinkList Search_FirstSameNode(LinkList &L1,ListList &L2){int len1=Length(L1),len2=Length(L2);LinkList longList,shortList;if(len1>len2){     //根据长度差判断哪个表更长longList=L1->next;shortList=L2->next;k=len1-len2;}else{longList=L2->next;shortList=L1->next;k=len2-len1;}while(k--)     //对于较长的表使之移动k个结点,与短的表同步移动longList=longList->next;while(longList!=NULL){if(longList->data==shortList->data)return longList;else{longList=longList->next;shorList=shortList->next;}}return NULL;
}

22、单链表保存m个整数,对于链表中data的绝对值相等的结点,仅保留第一次出现的结点而删除其余绝对值相等的结点

分析:借助一个辅助数组用来存放已出现的数值,并且存放在数组下标为结点元素值的(绝对值)位置上,用0表示未被访问,1表示已经访问;对于已经出现过的结点就将其删除,对于未出现过的结点将对应的辅助数组下标位置改为1

void Del(LinkList &L,int n){LNode *p=L,r;int *q,m;q=(int *)malloc((int)*(n+1);//动态分配n+1个空间的位置,并且将每个位置赋值为0for(int i=0;i<n+1;i++){       //初始化数值,每个位置未访问==0*(q+i)=0;  }while(p->next!=NULL){if(p->next->data>0)      //对于当前遍历的元素修改为正数,判断是否已被访问m=p->next->data;elsem=-p->next->data;if(*(q+m)==0){        //如果未被访问,就存入相应的数组中,p指向下一个结点*(q+m)=1;p=p->next;}else{r=p->next;      //p为待删除结点的前驱,p->next才是待删除结点p->next=r->next;free(r);}}free(q);      //循环结束后,删除辅助数组
}

23、带头结点的单链表存放L=(a1,a2,a3……an-3,an-2,an-1,an),重新排列L中各个结点,得到线性表L=(a1,an,a2,an-1,a3,an-2……)

分析:设置两个指针,p每次移动一个位置,q每次移动二个位置,当q移动到表尾,p正好在表中间位置。将p->next到q位置的所有结点都逆置【头插】;单链表的前后两段【链表开始第一个结点到后半段第一个结点】中各取一个结点,按照要求重新排列

void Sort_List(LinkList &L){LNode*p=L,*q=L,*s,*r;while(q->next!=NULL){     //移动指针到合适位置,左半表和右半表的尾结点p=p->next;q=q->next;if(q->next!=NULL)q=q->next;}q=p->next;    //用q指向后半段表的首结点p->next=NULL; //p作为其表头结点while(q!=NULL){      //r保存q的后继结点防止断链,头插法插入p的后面【逆序】r=q->next;q->next=p->next;p->next=q;q=r;}s=L->next;     //s指向前半表的首结点q=p->next;      //q指向后半表的首结点while(q!=NULL){r=q->next;      //将后半部分表头插到前半部分表中q->next=s->next;s->next=q;s=q->next;        //同时修改s和q的值 s指向的是下一个带插入结点的前驱【q的下一个结点】q=r;}
}

王道_线性表代码合集相关推荐

  1. 王道考研机试指南代码合集

    王道考研机试指南代码合集 github链接 王道考研机试指南的代码合集,附有一些笔记和感悟 文件夹中包括机试指南的pdf,笔记部分,和代码对应题目的列表 如发现任何问题欢迎在下面留言 更新: 最短路题 ...

  2. python机器人算法_机器人实用Python代码合集,5大类算法助你搞定自主导航

    迷之栗 发自 凹非寺 量子位 出品 | 公众号 QbitAI "有代码么?" 每每写到某实验室的机器人,解锁了厉害的操作,评论区很容易生出这样的问题. 然而,答案常常略带伤感,不好 ...

  3. python画心形代码大全_Python代码合集看点 机器人算法、自动导航算法算法大全...

    导读:本文包含机器人算法.自动导航算法的Python代码合集.其主要特点有以下三点:选择了在实践中广泛应用的算法:依赖最少.容易阅读,容易理解每个算法的基本思想.希望阅读本文后能对你有所帮助.文章来源 ...

  4. apicloud ajax html,基于apicloudAJAX请求代码合集

    get请求代码: api.ajax({ url:'http://m.weather.com.cn/data/101010100.html' //天气预报网站的WebService接口 },functi ...

  5. Algorithms_基础数据结构(04)_线性表之链表_单向循环链表约瑟夫环问题

    文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 结构 分析 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 tip:单向链表 约瑟夫问题 N个人围成一圈, ...

  6. iOS开发中经常用的实用代码合集

    iOS开发中经常用的实用代码合集 本文整理了,在iOS开发中我们所遇到一些开发问题的技巧类的代码,让你在开发过程中避免了很多弯路,希望能给你的开发带来帮助和启发. 1.判断邮箱格式是否正确的代码: / ...

  7. 王道数据结构线性表:有读者认为直接去掉p结点会造成断链?

    王道数据结构线性表:有读者认为直接去掉p结点会造成断链? 我用图解的方式来说明一下,文字有点多,看起来比较眼疼,但是内容不多,希望能对你有帮助. 书上的代码 解释 (ps:对上面解释的一点补充↓)

  8. python爱心代码合集

    python爱心代码合集 一行代码画爱心 输出 I 爱 U 填充型 动态画红心 桃心 线性 立体红心 画一朵玫瑰花 画树 附录 一行代码画爱心 print('\n'.join([''.join([(' ...

  9. 一、PyTorch Cookbook(常用代码合集)

    PyTorch Cookbook(常用代码合集) 原文链接:https://mp.weixin.qq.com/s/7at6y2NcYaxGGN8syxlccA 谢谢作者的付出.

最新文章

  1. 2021年大数据HBase(四):HBase的相关操作-客户端命令式!【建议收藏】
  2. 2020年涨薪26-30%,能实现吗?18%数据科学家是这么期待的
  3. pascal--生成Pascal矩阵
  4. 以服务器时间为基准显示到某一时间的倒计时
  5. 指向类对象的指针非空但是部分对象成员不存在原因分析
  6. spss数据预处理步骤_5个步骤,用SPSS进行数据分析
  7. 语义分割的三点奇技淫巧
  8. wowza配置rtsp/rtp播放
  9. Csv 之 简单解决使用 Excel 打开 csv 出现中文乱码现象
  10. 上市只是开端,库客音乐用版权打出组合拳
  11. list中抽出某一个字段的值_Java 将List中所有item中的某一个字段值提出来生成一个新的List...
  12. python 爬取《延禧攻略》所有的演员参演的电视剧
  13. 无法执行磁盘检查,因为windows无法访问该磁盘的一种解决思路
  14. java flash 播放器_视频播放插件Video.js
  15. linux临时关闭防火墙,和永久关闭防火墙
  16. android x86耗电,X86挑战ARM 29项测试揭秘鲜为人知的功耗
  17. Win10多版本CUDA和CUDNN安装
  18. 解决iOS手机连接fiddler后出现 “此站点的安全证书不受信任” 的问题!!!
  19. Web---监听用户名注册技术-myAJax-隐藏帧
  20. 电容(1)——电容种类以及电容选择

热门文章

  1. ubuntu 8.10安装配置经验(转载)
  2. 高通量测序数据分析:RNA-seq
  3. 一种基于知识图谱的新闻推荐模型
  4. 基于Pytorch Mobile在安卓手机端部署深度估计模型
  5. 浅谈XSS跨站脚本攻击
  6. 时间片轮转算法(c++)
  7. 芝麻信用免押金成趋势 报告称租赁经济有望突破10万亿元
  8. 关于Cxp采集卡连接大面阵相机取图耗时问题研究
  9. 欧拉回路(混合图的欧拉回路)
  10. 【个人C++学习日记】