链表、字符串和数组一直是很多互联网公司笔试题、面试题中经常出现的,但是变化万众,看起来各大IT巨头乐此不疲。能够很好的、熟练而巧妙的操作链表、字符串和数组也是一个码农必备的技能之一。下面对最近这段时间中看到的通过巧妙使用指针来解决此类问题的题目进行总结,方便归纳记忆。
【链表:寻找链表的中点、或者寻找链表倒数第n的节点】
此类问题利用快慢指针(此处将起跳时间不同的指针也认为是快慢指针)。
演示效果图如下:
具体代码如下:
#include <stdio.h> #include <iostream> /*---------------------链表的操作----------------------*/ //也可以直接使用STL中的双向链表结构list。 typedef struct ListNode { int val; ListNode* pNext; } ListNode,*PListNode; //快速寻找链表的中间节点 //【注】:对于寻找链表倒数第n个节点也是同样的流程 ListNode* FindMidNodeInList(PListNode ListHead) { if(ListHead==NULL) return NULL; if(ListHead->pNext==NULL) return ListHead; PListNode pFast=ListHead; PListNode pSlow=ListHead; while(pFast->pNext) { pSlow=pSlow->pNext; pFast=pFast->pNext->pNext; }; return pSlow; } int main() { //构造链表数据 printf("请输入链表长度:\n"); int len; scanf("%d",&len); PListNode ListHead=new ListNode; PListNode CurNode=ListHead; int i=1; while(i<=len) { printf("请输入第%d个链表元素\n",i); int val; scanf("%d",&val); CurNode->val=val; if(i==len) CurNode->pNext=NULL; else { CurNode->pNext=new ListNode; CurNode=CurNode->pNext; } ++i; } CurNode->pNext=NULL; PListNode pMid=FindMidNodeInList(ListHead); return 0; }【字符串操作:
此问题的直接思路就是逐个读取字符串中的每个字符然后判别是否是要删除的字符,此种方法在删除完每个字符后,需要将后续的字符前移,比较复杂。
下面展示一种通过巧妙利用快慢指针来实现字符串中删除特定字符的操作(此处的快慢指针是指两个指针跳动的次数不同),该方法不需要删除每个字母后移动后续字符串。
示意图如下:
具体代码如下:
#include <stdio.h> #include <iostream> #include <map> using std::map; /*-----------构建被删除字符串的哈希表---------------*/ //为了快速确定当前字符是否属于可删除字符,可通过构建 //可删除字符的哈希表 //此处利用了STL中的关联容器,map map<char,int> DelCharMap; void BuildDelCharMap(char* delchar) { char* pCur=delchar; while(*pCur!='\0') { DelCharMap[*pCur]=1; ++pCur; } } void DelCharsFromString(char* str,map<char,int>& DelCharMap) { char* pFirst=str; char* pSec=str; while(*pFirst!='\0') { if(DelCharMap[*pFirst])//发现要删除的字符 ++pFirst; else //未发现要删除的字符,将两个指针的数据交换 { char temp=*pFirst; *pFirst=*pSec; *pSec=temp; ++pFirst; ++pSec; } } *pSec='\0'; } int main() { char str[]="They are students."; char del[]="aeiou"; BuildDelCharMap(del); DelCharsFromString(str,DelCharMap); return 0; }
具体代码如下:
#include <stdio.h> #include <iostream> /*-------------------数组中的奇偶数分开排列-------------------*/ void OddEvenClassify(int* data,int num) { int* pBegin=data; int* pEnd=data+num-1; while(pBegin<=pEnd) { //从左寻找第一个偶数 while(*pBegin%2) ++pBegin; //从右寻找第一个奇数 while(!(*pEnd%2)) --pEnd; //两者进行交换 if(pBegin>=pEnd) break; int temp=*pBegin; *pBegin=*pEnd; *pEnd=temp; }; } int main() { int test[]={1,5,9,6,4,2,1,3,7,1,0}; OddEvenClassify(test,11); return 0; }
【快排中“分类”代码的两种方式】
示例代码:
/*--------------------快排中的分组-------------------------*/ #include <stdio.h>
#include <iostream>
//算法导论中第七章原文中给出的方式,同侧的两个指针 void QuickSort1(int* data,int num,int r) { int val=data[r-1]; int* pFirst=data; int* pSec=data; while(pFirst<=data+r-1) { while(*pFirst<=val) { int temp=*pFirst; *pFirst=*pSec; *pSec=temp; if(pFirst==data+r-1) break; ++pFirst; ++pSec; } ++pFirst; } } //快排的初始HOARE版本,首尾的两个指针 void QuickSort2(int* data,int num,int r) { int val=data[r-1]; int* pBegin=data; int* pEnd=data+r-1; while(pBegin<=pEnd) { while(*pBegin<val) ++pBegin; while(*pEnd>val) --pEnd; if(pBegin>=pEnd) break; int temp=*pBegin; *pBegin=*pEnd; *pEnd=temp; } } int main() { int test[]={1,5,6,7,3,2,4}; QuickSort2(test,7,7); return 0; }
Author: ZSSURE
E-mail: [email protected]
Date: 2014-03-14