本文紧跟上一篇博客,主要是我对单链表面试题的一些理解。
6 冒泡排序
主要分三步:1 比较相邻的两个数,如果后边的小于前边的,就交换他们两个;2 对每一组相邻的两个数进行比较,一次循环后最后的值最小;3 从头再次循环,得到新的排序(每次循环的数次逐次递减)。主要的代码如下:
// 冒泡排序
//1 比较相邻的两个数,如果后边的小于前边的,就交换他们两个
//2 对每一组相邻的两个数进行比较,一次循环后最后的值最小
//3 从头再次循环,得到新的排序(每次循环的数次逐次递减)
void BubbleSort(SListNode *pFirst)
{
SListNode * pre;//指向表头
SListNode * cur;//指向相邻元素中较后边的一个
SListNode * tail;//指向每轮结束的位置
int temp;//交换两个数据的中间变量
tail = NULL;
if(pFirst == NULL||pFirst->pNext == NULL)
{
return;
}
while(tail != pFirst->pNext)
{
pre = pFirst;
cur = pFirst->pNext;
while(cur != tail)
{
if(pre->data > cur->data)
{
temp = cur->data;
cur->data = pre->data;
pre->data = temp;
}
pre = cur;
cur = cur->pNext;
}
tail = pre;//尾指针前移
}
}
7 合并两个有序链表,合并后依然有序
主要分三步:1 给定两个链表,声明两个指针指向首元素;创建一个新的链表result;2 比较两个指针所指元素,小的先拿下来尾插在新链表中,同时指针后移;3 再次进行比较,直到其中某条链表为空。主要代码如下:
// 合并两个有序链表
//1 给定两个链表,声明两个指针指向首元素;创建一个新的链表result
//2 比较两个指针所指元素,小的先拿下来尾插在新链表中,同时指针后移
//3 再次进行比较,直到其中某条链表为空.
SListNode * MergeOrderedList(SListNode *p1First, SListNode *p2First)
{
SListNode * cur1 = p1First;
SListNode * cur2 = p2First;
SListNode * result = NULL;//结果链表
SListNode * tail = NULL;//结果链表的最后一个指针
SListNode * next;//保存遍历过程中的下个结点
while(cur1 != NULL && cur2 != NULL){
if(cur1 ->data < cur2 ->data)
{//应该取链表的结点
if(result != NULL){
//结果链表不为空,直接在最后一个结点上做插入
//保存链表的下一个结点,让循环继续
next = cur1 ->pNext;
//插入过程
tail->pNext = cur1;
cur1->pNext = NULL;
//保存新的最后一个结点
tail = cur1;
cur1 = next;
}
else{
next = cur1 ->pNext;
//插入过程
result = cur1;
cur1 ->pNext = NULL;
//保存新的最后一个结点
tail = cur1;
cur1 = next;
}
}
else{
//应该取链表的结点
if(result != NULL){
//结果链表不为空,直接在最后一个结点上做插入
//保存链表的下一个结点,让循环继续
next = cur2 ->pNext;
//插入过程
tail->pNext = cur2;
cur2->pNext = NULL;
//保存新的最后一个结点
tail = cur2;
cur2 = next;
}
else{
next = cur2 ->pNext;
//插入过程
result = cur2;
cur2 ->pNext = NULL;
//保存新的最后一个结点
tail = cur2;
cur2 = next;
}
}
}
//一个链表为空了
if(cur1 == NULL)
{
tail->pNext = cur2;
}
if(cur2 == NULL)
{
tail->pNext = cur1;
}
return result;
}
8 遍历一次链表,找到中间结点
主要思想是设置快慢指针,分两步:1 找两个指针,快慢指针.快指针每次走两个结点,慢指针每次走一个结点;2 等快指针走到最后一个节点的时候,慢指针刚好走到了中间结点。主要代码如下:
SListNode * FindMid(SListNode *pFirst)
{
//声明两个指针,一快一慢
SListNode *pfast = pFirst;
SListNode *pslow = pFirst;
while(1)
{
pfast = pfast->pNext;
if(pfast == NULL)
{
break;
}
pfast = pfast->pNext;
if(pfast == NULL)
{
break;
}
pslow = pslow->pNext;
}
return pslow;
}
9 遍历一次,找到倒数第k 个结点
主要分两步: 1 找两个指针,前后两个指针间距K个结点;2 依次遍历,等到前指针走到链尾null时,后指针恰好走到倒数第K个位置处。
// 遍历一次,找到倒数第k 个结点(k从开始)
//1 找两个指针,前后两个指针间距K个结点.
//2 依次遍历,等到前指针走到链尾null时,后指针恰好走到倒数第K个位置处
SListNode * FindK(SListNode *pFirst, int k)
{
//
SListNode *forward = pFirst;
SListNode *backward = pFirst;
//while循环使得前指针先走k个结点
while(k--)
{
forward = forward->pNext;
}
//依次遍历,等到等到前指针走到链尾null时,后指针恰好走到倒数第K个位置处
//即:循环的终止条件是forward==NULL;
while(forward != NULL)
{
forward = forward ->pNext;
backward = backward->pNext;
}
printf("%d\n",backward->data);
}
10 遍历一次,删除倒数第k 个结点(不用替换法)
主要分为两步:1 找倒数第k+1个结点pre;2 删除第k个结点,令pre->pNext = 删除结点->pNext;free(删除结点)即可。
// 遍历一次,删除倒数第k 个结点(k从开始),不能用替换删除法(意味着要找到倒数第k+1个结点)
//1 找倒数第k+1个结点pre
//2 删除第k个结点,令pre->pNext = 删除结点->pNext;free(删除结点)即可
SListNode * RemoveK(SListNode **pFirst, int k)
{
SListNode * forward = *pFirst;
SListNode * backward = *pFirst;
SListNode * pre = NULL;
if(*pFirst == NULL|| k<0)
{
return;
}
while(k--)
{
forward = forward->pNext;
}
while(1)
{
forward = forward->pNext;
backward = backward ->pNext;
if(forward->pNext == NULL)
{
pre = backward;
break;
}
}//找到了倒数第k+1个结点pre
backward = backward->pNext;
pre ->pNext = backward->pNext;
free(backward);
return *pFirst;
}
上述函数实现的过程中所需要的代码如下:
//创建单链表的成员,其实就是结点
typedef struct SListNode {
DataType data; // 值
struct SListNode *pNext; // 指向下一个结点
} SListNode; //SListNode为这个结构体的别名
// 初始化链表
void SListInit(SListNode **ppFirst)
{
*ppFirst = NULL;
}
//打印
void SListprint(SListNode *ppFirst)
{
SListNode *p = ppFirst;
if(p == NULL)
{
printf("空链表\n");
}
else{
for(p = ppFirst;p != NULL;p = p->pNext)
{
printf("%d ",p->data);
}
}
printf(" \n");
}
//创建新结点,结点的数据域为data,pNext域设置为空
SListNode *_CreateNode(DataType data)
{
SListNode *NewNode; //声明新结点
NewNode = (SListNode *)malloc(sizeof(SListNode));//创建新结点
if(NewNode == NULL)
{
return;
}//创建失败
NewNode ->data = data;
NewNode ->pNext = NULL;//创建成功
}
// 尾部插入(先找到最后一个结点,并把它记录下来,再把最后一个结点的pNext域指向新的结点)
void SListPushBack(SListNode** ppFirst, DataType data)
{
SListNode *p;//新结点p
SListNode *p1;
p = _CreateNode(data);
p1 = *ppFirst;//用来遍历链表(开始位于头结点处)
//空链表
if( (*ppFirst) == NULL ){
*ppFirst = p;
return;
} else{
for(p1 = *ppFirst; p1->pNext != NULL; p1 = p1->pNext)
{
}
p1 ->pNext = p;//此时p1为最后一个结点
}
}
//查找
SListNode * SListFind(SListNode *ppFirst, DataType data)
{
SListNode *cur;
//顺序查找,去遍历
for(cur = ppFirst; cur != NULL; cur = cur->pNext)
{
if( cur->data == data)
{
return cur;
}
}
return NULL;
}
void SListprint2(SListNode *ppFirst)
{
SListNode *p = ppFirst;
if(p == NULL)
{
printf("空链表\n");
}
else{
printf("%d ",p->data);
}
printf(" \n");
}
上边5道面试题的实现代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <windows.h>
int main()
{
SListNode *p1;
SListNode *p2;
SListNode *result;
SListInit(&p1);
SListInit(&p2);
SListPushBack(&p1,3);
SListPushBack(&p1,5);
SListPushBack(&p1,6);
SListPushBack(&p1,1);
SListPushBack(&p1,2);
SListPushBack(&p2,3);
SListPushBack(&p2,4);
SListPushBack(&p2,5);
SListprint(p1);
SListprint(p2);
result = RemoveK(&p1,3);
SListprint(result);
FindK(p1, 3);
result = FindMid(p1);
SListprint2(result);
result = MergeOrderedList(p1, p2);
SListprint(result);
BubbleSort(p1);
SListprint(p1);
system("pause");
return 0;
}
希望本文的简单说明能帮助到你,有哪些好的方法或者建议,欢迎留言评论。有哪些错误,欢迎批评指正,谢谢。