顺序表

1.将两个有序表合并为一个新的有序顺序表,并由函数返回顺序表
算法思想:按照顺序不断取下两个顺序表表头较小的结点存入新的顺序表,然后看哪个表有剩余,将剩下的部分加到新的顺序表后面。

  1. bool Merge(SqList A,SqList B,SqList &C){
  2. if(A.length+B.length>C.length)//表长超过
  3. return false;
  4. int i=0,j=0,k=0;
  5. while(i<A.length&&j<B.length){//循环两两比较
  6. if(A.data[i]<=B.data[i])
  7. C.data[k++]=A.data[i++];
  8. else
  9. C.data[k++]=B.data[j++];
  10. }
  11. while(i<A.length)
  12. C.data[k++]=A.data[i++];
  13. while(j<B.length)
  14. C.data[k++]=B.data[j++];
  15. C.length=k;
  16. return true;
  17. }

2.搜索整个顺序表,查找并删除最小值元素并记录其位置,搜索结束后用最后一个元素填补空出的原最小值位置

  1. bool Delete_Min(SqList &L,ElemType &value){
  2. if(L.length==0)
  3. return false;
  4. value=L.data[0];
  5. int pos=0;//假设0号元素值最小
  6. for(int i=1;i<L.length;i++){
  7. if(L.data[i]<value){
  8. value=L.data[i];
  9. pos=i;
  10. }
  11. }
  12. L.data[pos]=L.data[L.length-1];
  13. L.length--;
  14. return true;
  15. }

3.设将 n(n>1)个整数存放在一维数组 R 中。试着设计一个在时间复杂度和空间复杂度都尽可能高效的算法,将 R 中保存的序列循环左移 p ( 0<p<n ) 个位置, 即将 R 中 的 数 据 由 ( x0,x1, … ,xn-1 ) 变换为( xp, xp+1,…,xn-1,x0,x1,…,xp-1)。要求:
(1) 给出算法的基本设计思想;
(2) 根据算法设计思想,采用 C 或 C++语言描述,关键之处给出注释
(3) 说明你所设计算法的时间复杂度和空间复杂度

  1. void Reverse(int R[],int left,int right){
  2. //将数组原地逆置
  3. int i=left,j=right;
  4. while(i<j){
  5. int temp=R[i];
  6. R[i]=R[j];
  7. R[j]=temp;
  8. i++;//i右移一个位置
  9. j--;//j左移一个位置
  10. }
  11. }
  12. void LeftShift(int R[],int n,int p){
  13. //将长度为n的数组R的数据循环左移p个位置
  14. if(p>0&&p<n){
  15. Reverse(R[],0,n-1);//将数组全部逆置
  16. Reverse(R[],0,n-p-1);//将前n-p个数据逆置
  17. Reverse(R[],n-p,n-1);
  18. }
  19. }

4.顺序结构La和Lb,元素按非递减顺序排列.试给出一个高效算法,将Lb元素合并到La中,并使合并后的La依旧保持非递减顺序排列,要求:最大限度避免移动元素

  1. void Merge_AB(SqList &La,SqList Lb){
  2. int k=La.length+Lb.length-1;//合并后的La的最大下标
  3. int i=La.length-1,j=Lb.length-1;//La,Lb从后往前进行遍历
  4. while(i>=0&&j>=0){
  5. if(La.data[i]>=Lb.data[j]){
  6. La.data[k]=La.data[i];
  7. k--;
  8. i--;
  9. }
  10. else{
  11. La.data[k]=Lb.data[j];
  12. k--;
  13. j--;
  14. }
  15. }
  16. while(j>=0){
  17. La.data[k]=Lb.data[j];
  18. k--;
  19. j--;
  20. }
  21. La.length=La.length+Lb.length;
  22. return La;
  23. }

5.一个长度为N的整型数组A[1….N],给定整数X,请设计一个时间复杂度不超过O(nlog2n)的算法,查找出这个数组中所有两两之和等于X的整数对(每个元素只输出一次)

  1. //先利用快排将数组元素进行排序
  2. int Partition(int A[],int low,int high){
  3. int pivot=A[low];
  4. while(low<high){
  5. while(low<high&&A[high]>=pivot)
  6. --high;
  7. A[low]=A[high];
  8. while(low<high&&A[ow]<pivot)
  9. ++low;
  10. A[high]=A[low];
  11. }
  12. A[low]=pivot;
  13. return low;
  14. }
  15. void QuickSort(int A[],int low,int high){
  16. while(low<high){
  17. int pivotpos=Partition(A,low,high);
  18. QuickSort(A,0,pivotpos-1);
  19. QuickSort(A,pivotpos+1,high);
  20. }
  21. }
  22. void Find_sum_e(int A[].int N,int e){
  23. int i=0,j=N-1;
  24. QuickSort(A,0.N-1);
  25. while(i<j){
  26. int sum=A[i]+A[j];
  27. if(sum>e)
  28. j--;
  29. else if(sum<e)
  30. i++;
  31. else{
  32. printf("%d %d\n",A[i],A[j]);
  33. i++;
  34. j--;
  35. }
  36. }
  37. }

链表

1.将两个递增的有序链表合并为一个递增的有序链表。要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中不允许有重复的数据

  1. void MergeList(LinkList &La,LinkList &Lb,LinkList &Lc){
  2. LNode *pa,*pb,*pc;
  3. pa=La->next;
  4. pb=Lb->next;
  5. pc=La;
  6. Lc=pc;
  7. while(pa&&pb){
  8. if(pa->data<pb->data){
  9. pc->next=pa;
  10. pc=pa;
  11. pa=pa->next;
  12. }
  13. else if(pa->data>pb->data){
  14. pc->next=pb;
  15. pc=pb;
  16. pb=pb->next;
  17. }
  18. else{
  19. q=pb->next;
  20. free(pb);
  21. pb=q;
  22. }
  23. }
  24. if(pa)
  25. pc->next=pa;
  26. else
  27. pc->next=pb;
  28. free(Lb);
  29. }

2. 试编写在带头结点的单链表 L中删除一个最小值结点的高效算法(假设最小值结点是唯一的)。

  1. LinkList Del_Min(LinkList &L){
  2. LNode *pre=L,*p=pre->next;
  3. LNode *minpre=pre,*minp=p;
  4. while(p!=NULL){
  5. if(p->data<min->data){
  6. minp=p;
  7. minpre=pre;
  8. }
  9. pre=p;
  10. p=p->next;
  11. }
  12. minpre->next=minp->next;
  13. free(minp);
  14. return L;
  15. }

3. 在带头结点的单链表 L 中,删除所有值为 x 的结点,并释放其空间,假设值为 x 的结点不唯一,试编写算法实现上述操作。

  1. LinkList Del_x(LinkList &L,ElemType x){
  2. LNode *p=L->next,*pre=L;
  3. while(p!=NULL){
  4. if(p->data==x){
  5. q=p;
  6. p=p->next;
  7. pre->next=p;
  8. free(q);
  9. }
  10. else{
  11. pre=p;
  12. p=p->next;
  13. }
  14. }
  15. return L;
  16. }
  17. //采用尾插法建立单链表
  18. void Del_x(LinkList &L,ElemType x){
  19. LNode *p=L->next,*r=L,*q;
  20. while(p!=NULL){
  21. if(p->data!=x){
  22. r->next=p;
  23. r=p;
  24. p=p->next;
  25. }
  26. else{
  27. q=p;
  28. p=p->next;
  29. free(q);
  30. }
  31. }
  32. r->next=NULL;
  33. }

4. 试编写算法将带头结点的单链表就地逆置,所谓“就地”是辅助空间复杂度为 O(1)。

  1. //头插法
  2. LinkList Reverse(LinkList &L){
  3. LNode *p,*r;//p为工作指针,r为p的后继,防止断链
  4. p=L->next;
  5. L->next=NULL;
  6. while(p!=NULL){
  7. r=p->next;
  8. p->next=L->next;
  9. L->next=p;
  10. p=r;
  11. }
  12. return L;
  13. }

5. 将一个带头结点的单链表 A 分解为两个带头结点的单链表 A 和 B,使得 A 表中含有原标中序号为奇数的元素,而 B 表中含有原表中序号为偶数的元素,
且保持其相对顺序不变。

  1. LinkList DisCreat(LinkList &A){
  2. i=0;
  3. B=(LinkList*)malloc(sizeof(LNode));
  4. B->next=NULL;
  5. LNode *ra=A,*rb=B;//ra,rb分别指向A,B表的尾结点
  6. p=A->next;
  7. A->next=NULL;
  8. while(p!=NULL){
  9. i++;
  10. if(i%2==0){
  11. rb->next=p;
  12. rb=p;
  13. }
  14. else{
  15. ra->next=p;
  16. ra=p;
  17. }
  18. p=p->next;
  19. }
  20. ra->next=NULL;
  21. rb->next=NULL;
  22. return B;
  23. }

6. 设 C = {a1,b1,a2,b2,…,an,bn}为线性表,采用头结点的 hc 单链表存放, 设计一个就地算法,将其拆分为两个单链表,使得 A = {a1,
a2,…,an},B = {bn,…, b2,b1}。

  1. LinkList DisCreat(LinkList &A){
  2. LinkList B=(LinkList)malloc(sizeof(LNode));
  3. B->next=NULL;
  4. LNode *p=A->next.*q;
  5. LNode *ra=A;
  6. while(p!=NULL){
  7. ra->next=p;
  8. ra=p;
  9. p=p->next;
  10. q=p->next;
  11. p->next=B->next;//头插后,*p将断链
  12. B->next=p;
  13. p=q;
  14. }
  15. ra->next=NULL;
  16. return B;
  17. }

7. 设计算法将一个带头结点的单链表A 分解为两个具有相同结构的链表 B 和 C,其中 B 表的结点为 A 表中小于零的结点,而 C 表中的结点为 A 表中值大于零的结点(链表 A 中的元素为非零整数,要求 B、C 表利用 A 表的结点)。

  1. void Decompose(LinkList &A){
  2. B=(LinkList)malloc(sizeof(LNode));
  3. C=(LinkList)malloc(sizeof(LNode));
  4. B->next=NULL;
  5. C->next=NULL;
  6. p=A->next;
  7. while(p!=NULL){
  8. r=p->next;
  9. if(p->data<0){
  10. p->next=B->next;
  11. B->next=p;
  12. }
  13. else{
  14. p->next=C->next;
  15. C->next=p;
  16. }
  17. p=r;
  18. }
  19. }

8. 设计一个算法,通过一趟遍历确定长度为 n 的单链表中值最大的结点,返回该结点的数据域。

  1. ElemType Max(LinkList L){
  2. if(L->next==NULL)
  3. return NULL;
  4. pmax=L->next;
  5. p=pmax->next;
  6. while(p!=NULL){
  7. if(p->data>pmax->data){
  8. pmax=p;
  9. }
  10. p=p->next;
  11. }
  12. return pmax->data;
  13. }

9. 设计一个算法,删除递增有序表中值大于 mink 且小于 maxk(mink 和 maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同)的所有元素

  1. void Del_mink_maxk(LinkList &L,int mink,int maxk){
  2. p=L->next;
  3. while(p&&p->data<=mink){
  4. pre=p;
  5. p=p->next;
  6. }
  7. while(p&&p->data<maxk)
  8. p=p->next;
  9. q=pre->next;
  10. pre->next=p;
  11. while(q!=p){
  12. s=q->next;
  13. free(q);
  14. q=s;
  15. }
  16. }

10. 在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再具有重复的元素。

  1. void Del_Same(LinkList &L){
  2. LNode *p=L->next,*q;
  3. if(p==NULL)
  4. return;
  5. while(p->next!=NULL){
  6. q=p->next;
  7. if(p->data==q->data){
  8. p->next=q->next;
  9. free(q);
  10. }
  11. else
  12. p=p->next;
  13. }
  14. }

双指针策略思想(重点):
【2009 年统考】11. 已知一个带有表头结点的单链表,结点结构为:

yuque_diagram.jpg
假设该链表只给出了头指针 list。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中 倒数第 k 个位置上的结点( k 为正整数)。若查找成功,算法输出该结点的 data 域的值,并返回 1;否则,只返回 0。要求:
(1) 描述算法的基本设计思想;
(2) 描述算法的详细实现步骤;
(3) 根据设计思想和实现步骤,采用程序设计语言描述算法(使用 C、C++语言实现),关键之处请给出简要注释。

(1) 【算法思想】
定义指针 p 和 q,初始化指针时均指向单链表的首元结点。首先将 p 沿链表移动 到第 k 个结点,而 q 指针保持不变,这样当 p 移动到第 k+1 个结点时,p 和 q 所指结点的间隔距离为 k。然后 p 和 q 同时向下移动,当 p 为 NULL 时,q 所指向的结点就是该链表倒数第 k 个结点。
(2) 【算法步骤】
①设定计数器 i = 0,用指针 p 和 q 指向首元结点
②从首元结点开始依顺着链表 link 依次向下遍历链表,若 p 为 NULL,则转向步骤⑤。
③若 i 小于 k,则 i+1;否则,q 指向下一个结点。
④p 指向下一个结点,转步骤②。
⑤若 i == k,则查找成功,输出该结点的 data 域的值,返回 1;否则,查找失败, 返回 0.

  1. typedef struct LNode{
  2. int data;
  3. struct LNode *link;
  4. }LNode,*LinkList;
  5. int Search_k(LinkList list,int k){
  6. int i=0;//计数
  7. p=q=list->link;
  8. while(p!=NULL){
  9. if(i<k)
  10. i++;
  11. else
  12. q=q->link;//q移动到下一个结点
  13. p=p->link;
  14. }
  15. if(i==k){
  16. printf("%d",q->data);
  17. return 1;
  18. }
  19. else
  20. return 0;
  21. }

12.给定一个链表,判断链表中是否有环。如果有环,返回 1,否则返回 0。
捕获.JPG
1)给出算法的基本思想
2)根据设计思想,采用 C 或 C++语言描述算法,关键之处给出注释

【算法思想】
快慢指针遍历链表,快指针步距为 2,慢指针步距为 1,如果链表带环,两指针一定会在环中相遇。
1、判断极端条件,如果链表为空,或者链表只有一个结点,一定不会带环,直
接返回 NULL。
2、创建快慢指针,都初始化指向头结点。因为快指针每次都要步进 2 个单位,
所以在判断其自身有效性的同时还要判断其 next 指针的有效性,在循环条件中
将两语句逻辑与并列起来。
初始化慢指针 slow = head,每次向后走一步;
初始化快指针 fast =head->next,每次走两步,每走一步判断一次。 如果存在环,
fast 和 slow 必定会相遇。

  1. typedef struct LNode{
  2. int data;
  3. struct LNode *next;
  4. }LNode,*LinkList;
  5. int hasCycle(LinkList L){
  6. if(L.length==0||L->next=NULL)
  7. return 0;
  8. LNode *p=L->next;
  9. LNode *q=L;
  10. while(p!=q){
  11. if(p==NULL||p->next==NULL)
  12. return 0;
  13. p=p->next->next;
  14. q=q->next;
  15. }
  16. return 1;
  17. }

13.请写出在单链表中实现直接插入排序的算法

  1. void Sort(LinkList L){
  2. LinkList p,pre,q,p1;
  3. p=L->next->next;
  4. L->next->next=NULL;
  5. while(p){
  6. pre=L;
  7. q=pre->next;
  8. while(q!=NULL&&q->data<p->data){
  9. pre=q;
  10. q=q->next;
  11. }
  12. p1=p->next;
  13. p->next=pre->next;
  14. pre->next=p;
  15. p=p1;
  16. }
  17. }

14.给定一个链表,两两交换其中相邻的结点,并返回交换后的链表。(不能只是单纯的交换值,需要进行实际的结点交换)如:A->B->C->D,应该返回B->A->D->C

  1. LinkList Swap(LinkList L){
  2. if(L==NULL||L->next==NULL)
  3. return L;
  4. LNode *pre=L;
  5. LNode *prenext=L->next;
  6. LNode *cur=prenext->next;
  7. pre->next=cur;
  8. prenext->next=pre;
  9. L=prenext;//新的头结点
  10. while(cur!=NULL&&cur->next!=NULL){
  11. prenext=cur->next;//交换时第二个结点元素
  12. cur=prenext->next;
  13. pre->next->next=cur;
  14. prenext->next=pre->next;
  15. pre=prenext->next;
  16. }
  17. return L;
  18. }
  19. LinkList Swap(LinkList head){
  20. LNode *dummy=(LNode*)malloc(sizeof(LNode));
  21. dummy->next=head;
  22. LNode *first,*second,*current;
  23. current=dummy;
  24. while(current->next!=NULL&&current->next->next!=NULL){
  25. //初始化双指针
  26. first=current->next;
  27. second=current->next->next;
  28. //交换顺序
  29. first->next=second->next;
  30. second->next=first;
  31. current->next=second;
  32. //更新指针
  33. current=current->next->next;
  34. }
  35. return dummy->next;
  36. }