1. 程式人生 > >連結串列基本操作及部分面試題

連結串列基本操作及部分面試題

連結串列基本操作

連結串列的定義
typedef int DataType;
typedef struct SListNode
{
	DataType data;         //當前節點中儲存的元素
	struct SListNode* next;//指向連結串列中的下一個節點
}SListNode;
建立一個新的節點
SListNode* BuySListNode(DataType d)
{
	SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
	if (newNode == NULL)//建立不成功時
	{
		perror("BuySListNode::malloc");
		return NULL;
	}
	newNode->data = d;
	newNode->next = NULL;
	return newNode;
}
連結串列初始化
void SListInit(SListNode** pHead)
{
	assert(pHead);
	*pHead = NULL;
}
尾插
void SListPushBack(SListNode** pHead, DataType d)  //尾插
{
	//空連結串列,直接插入
	//非空連結串列,找最後一個結點
	assert(pHead);     //連結串列是否存在
	if (*pHead == NULL)//空連結串列時
	{
		*pHead = BuySListNode(d);
	}
	else//非空連結串列
	{
		SListNode*  pcur = *pHead;
		while (pcur->next != NULL)
			pcur = pcur->next;
		pcur->next = BuySListNode(d);
	}
}
尾刪
void SListPopBack(SListNode** pHead)//尾刪
{
	//空連結串列時
	//只有一個結點時
	//有兩個及以上結點時
	assert(pHead);
	if (*pHead == NULL)
		return;
	else if ((*pHead)->next == NULL)
	{
		free(*pHead);
		*pHead = NULL;
	}
	else
	{
		SListNode*  pcur = *pHead;
		while (pcur->next->next)//找倒數第二個節點,把它的next置空
			pcur = pcur->next;
		free(pcur->next);
		pcur->next = NULL;
	}
}
頭插
void SListPushFront(SListNode** pHead, DataType d)//頭插
{
	SListNode* newNode = BuySListNode(d);
	assert(pHead);
	newNode->next = *pHead;
	*pHead = newNode;
}
頭刪
void SListPopFront(SListNode** pHead)//頭刪
{
	SListNode* pDel = NULL;
	assert(pHead);
	if (*pHead == NULL)
		return;
	else
	{
		pDel = *pHead;
		*pHead = pDel->next;
		free(pDel);
	}
}
銷燬
void Destroy(SListNode** pHead)//銷燬
{
	SListNode* pcur = *pHead;
	assert(pHead);
	while (pcur != NULL)
	{
		SListNode* del = pcur;
		pcur = pcur->next;
		free(del);
		del = NULL;
	}
	*pHead = NULL;
}

連結串列面試題

從尾至頭列印
void PrintListFromTailToFront(SListNode* pHead)//從尾到頭列印(遞迴)
{
	if (pHead)
	{
		PrintListFromTailToFront(pHead->next);
		printf("%d ", pHead->data);
	}
}
刪除非尾節點
(偽刪除法)
void DeleteListNotTail(SListNode* pos)//刪除非尾結點(不能遍歷連結串列)
{
	SListNode* pDel;
	if (pos == NULL || pos->next == NULL)
		return;
	pDel = pos->next;                //pos後面的數交給pos,刪掉pos後面的節點
	pos->data = pDel->data;
	pos->next = pDel->next;
	free(pDel);
	pDel = NULL;
}
在指定位置前面插入
void InsertPosFront(SListNode* pos, DataType d)//在指定位置前面插入(不能遍歷連結串列)                  
{
	SListNode* newNode;
	if (pos == NULL)
		return;
	newNode = BuySListNode(pos->data);//建立新節點(資料就為pos位置的資料)
	newNode->next = pos->next;      //插在pos位置的後面
	pos->next = newNode;
	pos->data = d;                  //然後將要插入的資料放在pos位置
}
查詢指定資料的位置
SListNode* SListFind(SListNode* pHead, DataType d)//找
{
	SListNode* pCur = pHead;
	while (pCur)
	{
		if (pCur->data == d)
			return pCur;
		pCur = pCur->next;
	}
}
單鏈表排序(冒泡)
void BubbleSort(SListNode* pHead)//單鏈表排序(冒泡)
{
	SListNode* pTailNode = NULL;//定義尾部節點
	if (pHead == NULL || pHead->next == NULL)
		return;
	while (pHead != pTailNode)
	{
		SListNode* pPre = pHead;
		SListNode* pCur = pPre->next;
		while (pCur != pTailNode)
		{
			if (pPre->data>pCur->data)
			{
				DataType temp = pPre->data;
				pPre->data = pCur->data;
				pCur->data = temp;
			}
			pPre = pCur;
			pCur = pCur->next;
		}
		pTailNode = pPre;
	}
}
查詢單鏈表中間結點,要求只遍歷一次
SListNode* FindMiddleNode(SListNode* pHead)//查詢中間結點,只遍歷一次
{
	SListNode* pFast = pHead;
	SListNode* pSlow = pHead;
	while (pFast && pFast->next)
	{
		pFast = pFast->next->next;//一次移動兩步
		pSlow = pSlow->next;//一次走一步
	}
	return pSlow;//pSlow不一定是中間位置,連結串列中節點個數可能是奇數(Fast->next是空的)或者偶數(Fast是空的)
}
查詢倒數第k個,要求只遍歷一次
SListNode* FindListNode(SListNode* pHead, DataType k)//查詢倒數第k個
{
	SListNode* pFast = pHead;
	SListNode* pSlow = pHead;
	if (pHead == NULL || k <= 0)
		return NULL;
	while (k--)//先讓fast走k步(也可以走k-1步,那就讓fast走到倒數第二步)
	{
		if (pFast == NULL)
			return NULL;
		pFast = pFast->next;
	}
	while (pFast->next)//然後fast和slow一起走
	{
		pFast = pFast->next;
		pSlow = pSlow->next;
	}
	return pSlow;
}