**单链表的面试题(二)**

        本文紧跟上一篇博客,主要是我对单链表面试题的一些理解。

        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;

}

        希望本文的简单说明能帮助到你,有哪些好的方法或者建议,欢迎留言评论。有哪些错误,欢迎批评指正,谢谢。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值