單鏈表基礎面試題

1.比較順序表和鏈表的優缺點,說說它們分別在什麼場景下使用?
2.從尾到頭打印單鏈表
3.刪除一個無頭單鏈表的非尾節點
4.在無頭單鏈表的一個節點前插入一個節點
5.單鏈表實現約瑟夫環
6.逆置/反轉單鏈表
7.單鏈表排序(冒泡排序&快速排序)
8.合併兩個有序鏈表,合併後依然有序
9.查找單鏈表的中間節點,要求只能遍歷一次鏈表

10.查找單鏈表的倒數第k個節點,要求只能遍歷一次鏈表                  


解答: 

1.比較順序表和鏈表的優缺點,說說它們分別在什麼場景下使用? 

 順序表:順序表的地址空間是連續的,空間利用不充分。 查找速度快,便於大量元素的查找訪問。但是不利於增、刪。
 鏈表:   鏈表的地址空間是不連續的,對於內存空間不會造成浪費。便於大量元素的指定位置增、刪。但查找速度相對較慢。 
 
二者特性剛好互補。)

2.從尾到頭打印單鏈表 

//遞歸解決

void printfromback(ListNode* mylist)
{
	//1沒有節點或者只有一個節點
	//2有多個節點
	if(mylist != NULL)
	{
		return ;
	}
	else	
	{
		printfromback(mylist->next);
		printf("%d ",mylist->data);
	}
}

3.刪除一個無頭單鏈表的非尾節點 

//無頭鏈表刪除
//後一個節點覆蓋前一個節點 在釋放後一個節點
void deletnoheadlist(ListNode** pos )
{
	ListNode* next;
	assert(*pos);
	assert((*pos)->next);
	next = (*pos)->next;
	(*pos)->data = next->data;
	(*pos)->next = next->next ;
	free(next);
}
4.在無頭單鏈表的一個節點前插入一個節點 

//無頭鏈表插入
//在pos後面插入一個數,再交換兩個節點的內容
void insertonheadlist(ListNode** pos, DataType input)
{
	int tmp;
	ListNode* cur = *pos;
	ListNode* NewNode = BuyNode(input);

	//插入新節點
	NewNode->next = (*pos)->next;
	(*pos)->next  = NewNode;

	//交換data
	tmp = NewNode->data ;
	NewNode->data = cur->data;
	(*pos)->data = tmp;
}
5.單鏈表實現約瑟夫環 

//約瑟夫環
//1把鏈表連起來
ListNode* JosephRing(ListNode** ppList, int k)
{
	//1空鏈表
	//2非空
	ListNode* cur = *ppList;
	if(*ppList == NULL)
	{
		return ;
	}
	while(cur->next != NULL)
	{
		cur = cur->next;
	}
	cur->next = (*ppList);
	while((*ppList)->next != *ppList)
	{
		int loop = k;
		while(--loop)
		{
			(*ppList) = (*ppList)->next;
		}
	//刪除
		(*ppList)->data = (*ppList)->next->data;
		(*ppList)->next = (*ppList)->next->next;
	}
	return  *ppList;
}
6.逆置/反轉單鏈表 

//鏈表逆置  頭插法
//建一個新鏈表    在新鏈表上頭插原來的節點元素
ListNode* ReverseList(ListNode** ppList)
{
	//1鏈表爲空 或者只有一個元素
	//2鏈表不爲空
	ListNode* cur = *ppList;
	ListNode* newlist=NULL ;
	if((*ppList)->next == NULL || *ppList == NULL)
	{
		return ;
	}
	else
	{
		ListNode* tmp;
		while(cur != NULL)
		{
			//摘節點
			tmp = cur;
			cur = cur->next;

			//放節點
			tmp->next =newlist;
			newlist = tmp;
		}
		return newlist;

	}

}

7.單鏈表排序(冒泡排序&快速排序) 
//冒泡排序鏈表
void bubble_sotr_list(ListNode* pList)
{
	//1鏈表爲空或者只有一個節點
	//2有多個節點
	ListNode* cur = pList;
	ListNode* nextnode = cur->next;
	ListNode* stop = NULL;
    DataType tmp;
	if((pList) == NULL || nextnode == NULL)
	{
		return ;
	}
	else
	{
		while(stop != (pList)->next)
		{
			cur = pList;
			nextnode = cur->next;
			while(nextnode != stop)
			{
			 if((cur->data) > (nextnode->data))
			 {
				tmp = cur->data;
				cur->data = nextnode->data;
				nextnode->data = tmp;
			 }
			cur =cur->next;
			nextnode = nextnode->next;
			}
			stop = cur;
		}
	}
}

8.合併兩個有序鏈表,合併後依然有序

//合併兩個有序鏈表,合併後依然有序
ListNode* MergeList(ListNode* List1,ListNode* List2)
{
	//1兩個鏈表都爲空
	//2其中一個鏈表爲空
	//3兩個鏈表都不爲空
	ListNode* Newlist = NULL;
	ListNode* Newlisthead = NULL;

	if(List1 == NULL  && List2 == NULL)
	{
		return NULL;
	}
	else if (List1 != NULL  && List2 == NULL)
	{
		return List1;
	}
	else if (List1 == NULL  && List2 != NULL)
	{
		return List2;
	}
	else
	{
		//摘鏈表頭
		if(List1->data < List2->data)
		{
			Newlist = List1;
			List1 = List1->next;
		}
		else
		{
			Newlist = List2;
			List2 = List2->next;
		}
		Newlisthead = Newlist;
	    //往節點後面加節點
		while(List1 !=NULL && List2 != NULL)
		{
			if(List1->data < List2->data)
			{
				Newlist->next = List1;
				Newlist = Newlist->next;
		        List1 = List1->next;

			}
			else
			{
				Newlist->next = List2;
				Newlist = Newlist->next;
		        List2 = List2->next;
			}
	    }
		//把剩餘的鏈表鏈接上
		if(List1 == NULL)
		{
		  Newlist->next = List2;
		}
		if(List2 == NULL)
		{
		  Newlist->next = List1;
		}
	    return Newlisthead;
	}
}

9.查找單鏈表的中間節點,要求只能遍歷一次鏈表 

//查找鏈表中心元素 (只能遍歷一次)
//快慢指針
ListNode* find_list_mid(ListNode* pList)
{
	//1爲空
	//2只有一個或者兩個節點
	//3有多個節點
	ListNode* slow = pList;
	ListNode* fast = pList;
	if(pList == NULL)
	{
		return NULL ;
	}
	else if(pList->next == NULL || pList->next->next == NULL)
	{
		return pList;
	}
	else
	{
	   while(fast && fast->next !=  NULL) //奇數偶數節點問題
	   {
			slow = slow->next;
			fast = fast->next->next;
	   }
	   return slow;
	}
}

10.查找單鏈表的倒數第k個節點,要求只能遍歷一次鏈表 

//找倒數第k個元素

ListNode* find_tail_k(ListNode* pList,int k)
{
	//1鏈表爲空
        //2鏈表元素少於k
	//3鏈表元素多餘k
	ListNode* slow = pList;
	ListNode* fast = pList;
	if(pList == NULL)
	{
		return NULL;
	}
	while(--k)    //先走k步                
	{

		fast = fast->next;
		if(fast == NULL)
		{
			return NULL ;
		}
	}
	while(fast->next != NULL)   //一起走
	{
	    slow = slow->next;
	    fast = fast->next;
	}
	return slow;
}






發佈了55 篇原創文章 · 獲贊 47 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章