連結串列基本操作及部分面試題
阿新 • • 發佈:2018-12-16
連結串列基本操作
連結串列的定義
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;
}