//2009、含头指针的单链表,查找其链表中倒数第K个位置上的结点 typedef int ElemType; //链表数据的结构定义 typedef struct LNode{ //链表结点的结构定义 ElemType data; //结点数据 struct Lnode *link; //结点链接指针 }*LinkList; int Search_k(LinkList list ,int k){ Linklist p = list->link , q = list->link; //指针p、q指向第一个结点 int count = 0; while(p!= NULL){ //遍历链表直到最后一个结点 if(count < k){ count ++; p = p->link; } else{ p = p->link; q = q->link; } } if (count < k){ //结点数不足K return 0; } else{ cout<data; return 1; } } --------------------------------------------------------------------------------------------------------------------------------------- //2010、含n个整数的一维数组R,将R中保存的序列循环左移p个位置,即将R( a0,a1,....,a(n-1) )变换为R( ap,a(p+1),....a(n-1),a0,a1,....,a(p-1) ) //思路同:将字符串分开的两个子串相互倒转 void Reverse(int R[],int from,int to){ int i,temp; for(int i = 0; i<(to-from+1)/2;i++){ temp = R[from+i]; R[from+i] = R[to-i]; R[to-i] = temp; } } void Converse(int R[],int n,int p){ Reverse(R,0,p-1); Reverse(R,p,n-1); Reverse(R,0,n-1); } --------------------------------------------------------------------------------------------------------------------------------------- //2011、对于长度为L的升序序列S,处在第L/2个位置的数成为S的中位数,求两个等长升序序列A、B的中位数 /*思路: 1、先分别求出A、B的中位数a、b 2、若a=b则a或b为所求 3、若ab,则舍弃A中较大一半和B中较小一半(舍弃长度相等) 5、重复1234步,直到最后都只剩一个元素,较小者为所求 */ int M_Search(int A[],int B[],int n){ int s1=0,d1=n-1,m1,s2=1,d2=n-1,m2; //分别表示序列A和B的首位数、末位数、中位数 while(s1 != d1 || s2 != d2 ){ m1 = (s1+d1)/2; m2 = (s2+d2)/2; if(A[m1]==B[m2]){ return A[m1]; //满足条件a=b } if(A[m1]=n,则使p指向链表中的第m-n+1个结点;反之则使q指向其第m-n+1个结点 3、反复将p和q同步向后移动,并判断它们是否指向同一结点。 */ typedef char ElemType; typedef struct LNode { ElemType data; struct Lnode *link }LinkList; LinkNode *Find_1st_common(LinkList str1,LinkList str2){ int len1=length(str1),len2=length(str2); LinkNode *p,*q; for(p=str1;len1>len2;len1--){ p=p->next; } for(q=str2;len1next; } while(p->next!=NULL&&p->next!=q->next){ p=p->next; q=q->next; } return p->next; } --------------------------------------------------------------------------------------------------------------------------------------- //2013、整数序列A(a0,a1,...,a(n-1) ),其中0n/2,则称x为A的主元素,设计算法求A的主元素 /*思路:从前往后扫描数组元素,标记出一个可能成为主元素的元素Num,然后重新计数,确认Num是否是主元素 1、选取候选的主元素:依次扫描所给数组中的每个证书,将第一个遇到的证整数Num保存到c中,记录Num的出现次数为1; 若遇到的下一个整数仍等于Num,则计数+1,否则计数减1; 当计数减到0时,将遇到的下一个整数保存到c中,计数重新记为1,开始新一轮计数,即从当前位置开始重复上述,扫完全部元素 2、判断c中元素是否是真正的主元素:再次扫描该数组,统计c中元素出现的次数,若大于n/2,则为主元素 */ int Majority(int A[],int n){ int i,c,count=1; c = A[0]; for(i=1;i0){ count--; } else{ c = A[i]; count = 1; } } if(count>0){ for(i=count=0;i=n/2){ return c; } else{ return -1; } } } --------------------------------------------------------------------------------------------------------------------------------------- /*2014 二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。 给定一棵二叉树,采用二叉链表存储,其中叶结点weight域保存该结点的非负权值,left指向其左孩子,right指向其右孩子 设root为指向T的根结点,设计求T的WPL的算法 */ //二叉树结点的数据类型定义 typedef struct BiTNode{ int weight; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; /*思路: 方法1(先序遍历递归算法):用static变量记录WPL 1、若该结点是叶子结点,那么变量wpl加上该结点的深度与权值之积 2、若该结点非叶子结点,那么若左子树不空,对左子树调用递归算法,若右子树不空,对右子树调用递归算法,深度参数均为本结点深度参数+1 3、最后返回计算出的wpl即可 */ int WPL(BiTree root){ int wpl_PreOrder(root,0); } int wpl_PreOrder(BiTree root,int deep){ static int wpl = 0; //定义一个static变量存储wpl if(root->lchild == NULL && root->rchild == NULL){ wpl += deep * root -> weight ; //若为叶子结点,累计wpl } if(root->lchild != NULL){ wpl_PreOrder(root->lchid,deep+1); } if(root->rchild !=NULL){ wpl_PreOrder(root->rchild,deep+1); } return wpl; } /* 方法2(基于层次遍历的队列): 1、用队列进行层次遍历,记录当前的层数,当遍历到叶子结点时,累计wpl; 2、当遍历到非叶子结点时把该结点的子树加入队列; 3、当某结点为该层的最后一个结点时,层数自增1; 4、队列空时遍历结束,返回wpl */ #define MaxSize 100 //设置队列的最大容量 int wpl_LevelOrder(BiTree root){ BiTree q[MaxSize]; //声明队列,end1为头指针,end2为尾指针 int end1,end2; //队列最多容纳MaxSize-1个元素 end1 = end2 =0 ; //头指针指向队头元素,尾指针指向队尾的后一个元素 int wpl = 0,deep =0; //初始化wpl和深度 BiTree lastNode; //lastNode用来记录当前层的最后一个结点 BiTree newlastNode; //newlastNode用来记录下一层的最后一个结点 lastNode = root; //lastNode初始化为根结点 newlastNode = NULL; //newlastNode初始化为空 q[end2++] = root; //根结点入队 while(end1 != end2){ //层次遍历,若队列不空则循环 BiTree t = q[end1++]; //拿出队列中的头一个元素 if(t->lchild == NULL && t->rchild == NULL){ wpl += deep*t->weight; //若为叶子结点,统计wpl } if(root->lchild != NULL){ //若非叶子结点把左结点入队 q[end2++] = t->lchild; newlastNode = t->lchild; } if(root->rchild != NULL){ q[end2++] = t->rchild; newlastNode = t->rchild; } if(t == lastNode){ lastNode = newlastNode; deep += 1; } } return wpl } --------------------------------------------------------------------------------------------------------------------------------------- /*2015 用单链表保存m个整数,结点的结构为[data][link],且[data]<=n 设计一个时间复杂度尽可能高效的算法,对于链表中data的绝对值相等的结点,仅保留第一次出现的结点而删除其余绝对值相等的结点 如链表:21 -> -15 -> -15 -> -7 -> 15,删除结点后为:21 -> -15 -> -7 */ /* 思路:因|data|<=n,故辅助数组q的大小为n+1,各元素的初值均为0. 依次扫描链表中各结点,同时检查q[|data|]的值,若为0,则保留结点并令q[|data|]=1,否则将该结点删除 */ //单链表结点的数据类型定义 typedef struct node{ int data; struct node *link; }NODE; typedef NODE *PNODE //算法实现 void func(PNODE h,int n){ PNODE p = h , r; int *q,m; q = (int *)malloc(sizeof(int)*(n+1)); //申请n+1个位置的辅助空间 for(int i=0;ilink != NULL){ m = p->link->data >0 ? p->link->data:-p->link->data; if(*(q+m) == 0){ //判断该结点的data是否已出现过 *(q+m) =1; p = p->link; } else{ r = p->link; p->link = r->link; free(r); } } free(q); } --------------------------------------------------------------------------------------------------------------------------------------- /*2016 已知由n(n>=2)个正整数构成的集合A,将其划分为两个不相交的子集A1和A2,元素个数分别为n1和n2 令A1和A2中元素之和为S1和S2,设计划分算法,满足|n1-n2|最小且|S1-S2|最大 */ /*思路: 将最小的n/2(向下取整,下同)个元素放在A1中,其余的元素放在A2中,分组结果即可满足题意 利用快速排序的思想,基于枢轴将n个整数划分为两个子集,根据划分后枢轴所处的位置i分别处理 1、若i=n/2,则分组完成,算法结束 2、若in/2,则枢轴及之后的所有元素均属于A2,继续对i之前的元素进行划分 */ int setPartition(int a[],int n[]){ int pivotkey,low=0,low0=0,high=n-1,flag=1,k=n/2,i; int s1=0,s2=0; while(flag){ pivotkey=a[low]; while(low=pivotkey){ --high; } if(low != high){ a[low]=a[high]; } while(lowleft == NULL && root->right == NULL){ printf("%s",root->data ); } else{ if(deep>1){ printf("("); //若有子表达式则加一层括号 } BtreeToExp(root->left,deep+1); printf("%s",root->data ); BtreeToExp(root->right,deep+1); if(deep>1){ printf(")"); //若由子表达式则加一层括号(此处是为了封闭次结点层的运算) } } } --------------------------------------------------------------------------------------------------------------------------------------- /*2018 给定一个含n个整数的数组,设计一个时间上尽可能高效的算法,找出数组中未出现的最小正整数 例如,数组{-5,3,2,3}中未出现的最小正整数是1;数组{1,2,3}中未出现的最小正整数是4 */ /*思路: 由于A中只有n个数,因此若最小的n个正整数全在A内的话,未出现的最小正整数则为n+1,反之,将A中n个数扫一遍后,1~n中有数没被扫到,则最小的那个为所求 分配一个用于标记的数组B[n],用来记录A中是否出现了1~n中的正整数,B[0]对应正整数1,B[n-1]对应正整数n,初始化B中所有值为0 从A[0]开始遍历A,若00 && A[i]<=n){ B[A[i]-1] == 1; } } for(i=0;inext != NULL){ //寻找中间结点 p = p->next; q = q->next; if(q->next != NULL){ q = q->next; } } q = p->next; p->next = NULL; while(q != NULL){ //将链表后半段逆置 r = q->next; q->next = p->next; p->next = q; q=r; } s = h->next; //s指向前半段的第一个数据结点,即插入点 q = p->next; //q指向后半段的第一个数据结点 p->next = NULL; while(q != NULL){ //将链表后半段的结点插入到指定位置 r = q->next; //r指向后半段的下一个结点 q->next = s->next; //将q所指结点插入到s所指结点之后 s->next = q; s = q->next; //s指向前半段的下一个插入点 q = r; } } --------------------------------------------------------------------------------------------------------------------------------------- /*2020 定义三元组(a,b,c)(均为整数)的具里D=|a-b|+|b-c|+|c-a| 给定三个非空整数集合S1、S2、S3,按升序分别存储在3个数组中 设计算法计算并输出所有可能的三元组(a,b,c)中的最小距离(a,b,c分别为S1,S2,S3中的整数) 例如S1={-1,0,9},S2={-25,-10,10,11},S3={2,9,17,30,41},则最小距离为2,相应的三元组为(9,10,9) */ --------------------------------------------------------------------------------------------------------------------------------------- /*2021 已知无向连通图G由顶点集V和边集E组成|E|>0 当G中度为奇数的顶点个数为不大于2的偶数时,G存在包含所有边且长度为|E|的路径(成为EL路径) 设图G采用邻接矩阵存储,类型定义如下: Typedef struct{ //图的定义 int numVertices,numEdges; //图中实际的顶点权和边数 char VertticesList[MAXV]; //顶点表。MAXV为已定义常量 int Edge[MAXV][MAXV]; //邻接矩阵 }:MGraph; 设计算法:int IsExistEL(MGraph G),判断G是否存在EL路径,若存在,则返回1,否则返回0 */ /*思路 对于采用邻接矩阵存储的无向图,邻接矩阵每一行(列)中非零元素的个数为本行(列)对应的顶点的度。 因此可以依次计算连通图G中各顶点的度,并记录度为奇数的顶点个数,若个数为0或2,则返回1,否则返回0 */ int IsExistEL(MGraph G){ int degree,i,j,count=0; for(i=0;i