据说是腾讯招聘的题目。。
老实说,我对小甲鱼给出的答案很不以为然,小甲鱼的方法只是循环次数减少了,不见得总的执行次数会少多少。。不知道是不是我对算法的执行效率有误解。。。。。不过我也没有找到更好的办法,贴代码吧。
我的设想:
n = GetLength_L(); //获得长度 循环N次
找到第[n/2]元素 // 循环 [N/2]
小甲鱼的解法:
快慢指针方法
LNode * search ;
LNode *mid;
开始时 search = mid 都指向头指针,然后search每次按两个元素往单链表的后续元素推进,mid每次俺一个元素往单链表的元素推进。当search到达末尾的时候,mid刚好指向中间元素。。。
就好比两个人一起赛跑(跑道长度位置),甲乙两人同时在起点出发,甲的速度是乙的速度的两倍,甲到终点的时候,乙恰好在中间位置。。。。
--code为小甲鱼解法的实现。。
1 /******************************************************* 2 * @: Project: 找未知长度单链表的中间元素 3 * @: File: link_list.h 4 * @: Function: 提供单链表操作的数据结构定义及方法声明 5 * @: History: 2013-10-01 22:37:05 6 * @: Author: Alimy 7 *******************************************************/ 8 9 /******************************************************* 10 * @:头文件包含 11 *******************************************************/ 12 13 14 #ifndef __LINK_LIST_H__ 15 #define __LINK_LIST_H__ 16 17 18 /******************************************* 19 * @: 数据结构定义&一些宏 20 ********************************************/ 21 #define ElemType signed short int // 此例子中的数据为有符号短整形,在VC6 中占据16bits 22 #define StatusType int //操作状态为int类型 23 #define OK (StatusType)1 24 #define ERROR (StatusType)0 25 26 27 typedef struct LNode{ 28 ElemType m_data; // 数据域 29 struct LNode *p_next; // 指针域 30 } LNode, *pLinkList; 31 32 //typedef struct LHead{ //头结点,其实和 LNode的内存结构相似, 33 // int ElemNumber; //数据域,可以存储当前线性表的长度,也可以什么也不存储 34 // struct LNode *p_FirstNode; //指针域指向线性表的第一个元素 35 //}LHead, *pLHead; 36 37 /******************************************* 38 * @: 外部调用函数声明 39 ********************************************/ 40 extern StatusType CreateList_L(pLinkList *pL,int num);//构造num个结点的单链表 41 extern StatusType GetMidNode(pLinkList *pL,ElemType *pe); //找到未知长度链表的 中间元素 42 extern void ClearList_L(pLinkList *pL); //整表删除 43 extern void DisplayList_L(pLinkList *pL);//输出显示pL指向的链表中的所有元素 44 45 #endif
1 /******************************************************* 2 * @: Project: 找未知长度单链表的中间元素 3 * @: File: GetMidNode.c 4 * @: Function:提供单链表操作相关函数 5 * @: Version: 2013-10-09 22:09:36 6 * @: Author: Alimy 7 *******************************************************/ 8 9 /******************************************************* 10 * @: 头文件包含 11 *******************************************************/ 12 13 #include "link_list.h" 14 #include <stdio.h> 15 #include <conio.h> // int getch(void); 16 #include <stdlib.h> // int rand(void); malloc(); free(); 17 #include <time.h> // time_t time(time_t *); 18 19 20 /******************************************************* 21 * @: (外部&内部)变量声明及定义 22 *******************************************************/ 23 24 /******************************************************* 25 * @: (外部&内部)函数声明及定义 26 *******************************************************/ 27 StatusType CreateList_L(pLinkList *pL,int num);//构造num个结点的单链表 28 StatusType GetMidNode(pLinkList *pL,ElemType *pe); //找到未知长度链表的 中间元素 29 void DisplayList_L(pLinkList *pL);//输出显示pL指向的链表中的所有元素 30 void ClearList_L(pLinkList *pL); //整表删除 31 32 33 34 /******************************************************* 35 * @: 内部函数具体实现 36 *******************************************************/ 37 38 39 /* 40 *@:在堆中构造一个单链表,并逆序插入num个结点(头插法) 41 *@:返回值 42 *@: 构造成功返回OK 43 *@: 构造失败返回ERROR 44 **/ 45 StatusType CreateList_L(pLinkList *pL,int num){//构造num个结点的单链表 46 47 LNode* p_Work = NULL; //工作指针 48 int idx = 0; 49 50 if(*pL!=NULL){ 51 printf("当前单链表已被初始化,不需要执行Create操作 \n"); 52 return ERROR; 53 } 54 55 *pL = (pLinkList)malloc(sizeof(LNode)); 56 if(*pL == NULL){ 57 printf("在堆中申请头结点失败 \n"); 58 return ERROR; 59 } 60 (*pL)->m_data = 0; // 数据域可以存储当前单链表的长度 61 (*pL)->p_next = NULL; 62 63 srand(time(0)); 64 for(idx=0;idx<num;idx++){ 65 p_Work = (pLinkList)malloc(sizeof(LNode)); //在堆中申请新的结点 66 if(p_Work==NULL){ 67 printf("在堆中申请结点出现异常,构造单链表失败 \n"); 68 return ERROR; 69 } 70 71 //p_Work->m_data = 10*s_data[idx%10];//(rand()%(10)); //均为10以内的整数 72 p_Work->m_data = (rand()%(100))+1; //晕死,每次生产的随机数怎么都一样 73 p_Work->p_next = (*pL)->p_next; 74 (*pL)->p_next = p_Work; //逆序插入,第一个产生为表尾 75 } 76 printf("构造含【%d】个元素的单链表成功\n",num); 77 getch(); 78 return OK; 79 } 80 /* 81 *@:在pL指向的未知长度的单链表中找到中间元素,并将中间元素的值赋值给pe指向的内存 82 *@:返回值 83 * 找到 --> 返回OK 84 * 没找到 --> 返回ERROR 85 */ 86 87 StatusType GetMidNode(pLinkList *pL,ElemType *pe){ //找到未知长度链表的 中间元素 88 LNode * p_search = NULL; //快指针 89 LNode * p_mid = NULL; //慢指针 90 91 p_search = p_mid = *pL; // 都指向头结点 92 93 if((*pL)->p_next == NULL){ 94 printf("此单链表为空表,无法执行找到中间元素的操作 \n"); 95 return ERROR; 96 } 97 if(p_search->p_next->p_next == NULL){ 98 printf("此单链表的元素个数为1\n"); 99 *pe = p_search->p_next->m_data; 100 return OK; 101 } 102 103 while(p_search->p_next!=NULL){ 104 if(p_search->p_next->p_next!=NULL){ 105 p_mid = p_mid ->p_next; 106 p_search = p_search->p_next->p_next; 107 } 108 else{ 109 p_search = p_search->p_next;//让while跳出循环 110 } 111 } 112 113 *pe = p_mid->m_data; 114 return OK; 115 116 } 117 118 119 /* 120 *@: 输出显示pL指向的单链表所有的元素 121 */ 122 void DisplayList_L(pLinkList *pL){ //显示当前所有单链表的长度 123 124 int idx = 0; 125 LNode* p_Work = NULL; 126 127 if(*pL==NULL){ 128 printf("单链表还未构建,输不出东东 \n"); 129 return ; 130 } 131 132 idx = 0; 133 p_Work = (*pL); // 工作指针指向头结点,计数清零 134 if(p_Work->p_next==NULL){ 135 printf("当前单链表为空表,没什么东东好显示的 \n"); 136 return ; 137 } 138 else{ 139 while(p_Work->p_next){ //(p_Work->p_next!=NULL) 140 idx++; 141 p_Work = p_Work->p_next; 142 printf("单链表第【%d】个元素的值为【%d】\n",idx,p_Work->m_data); 143 } 144 return ; 145 } 146 147 148 } 149 150 151 /* 152 *@:删除pL指向的单链表的所有结点 153 */ 154 155 void ClearList_L(pLinkList *pL){ //整表删除 156 LNode* p_Work1 = NULL; 157 LNode* p_Work2 = NULL; //工作指针 158 159 if(*pL == NULL){ 160 printf("当前单链表未创建,无法执行整表删除操作 \n"); 161 return ; 162 } 163 else if((*pL)->p_next == NULL){ 164 printf("当前单链表为空表,不需要执行整表删除操作 \n"); 165 return; 166 } 167 else{ 168 p_Work1 = (*pL)->p_next; // 指向第一个结点(如果有的话) 169 while(p_Work1!=NULL){ 170 p_Work2 = p_Work1; 171 p_Work1 = p_Work2->p_next;//指向下一个 172 free(p_Work2); 173 } 174 175 // (*pL)->p_next = NULL; // 头结点指向NULL 176 (*pL)->m_data = 0; 177 return ; 178 } 179 }
1 #include <stdio.h> 2 #include "link_list.h" 3 4 5 6 int main(void){ 7 int num = 0; 8 ElemType e = 0; 9 pLinkList LinkList_Display = NULL; 10 printf("请输入你要构建单链表的个数 \n"); 11 scanf("%d",&num); 12 CreateList_L(&LinkList_Display,num); 13 DisplayList_L(&LinkList_Display); 14 15 if(OK == GetMidNode(&LinkList_Display,&e)){ 16 printf("中间元素的值为 【%d】\n",e); 17 } 18 19 getch(); 20 21 22 23 // 打扫堆战场 24 ClearList_L(&LinkList_Display); 25 if(LinkList_Display != NULL) 26 free(LinkList_Display); 27 return OK; 28 29 }