1. 程式人生 > >單鏈表的基本操作及實現詳解

單鏈表的基本操作及實現詳解

連結串列是最基本的線性資料結構之一,單向連結串列(單鏈表)是連結串列的一種,其特點是連結串列的連結方向是單向的,對連結串列的訪問要通過順序讀取從頭部開始。

 一、單鏈表的概述

    1.單鏈表的分類

          單鏈表的最大特點是可以將實體地址上不連續的資料連線起來,通過指標來對實體地址進行操作,實現增刪改查等功能。

          單鏈表分為兩種:無頭單鏈表和有頭單鏈表。

                  無頭單鏈表:pHead只是一個指標,指向連結串列的第一個節點。

                 

               有頭單鏈表:pHead是連結串列的頭結點,只不過頭結點裡的data不儲存資訊。

                  

    2.單鏈表的儲存方式

          鏈式儲存結構的線性表將採用一組任意的儲存單元存放線性表中的資料元素。由於不需要按順序儲存,連結串列在插入、刪除資料元素時比順序儲存要快,但是在查詢一個節點時則要比順序儲存要慢。

         使用鏈式儲存可以克服順序線性表需要預先知道資料大小的缺點,連結串列結構可以充分利用記憶體空間,實現靈活的記憶體動態管理。但是鏈式儲存失去了陣列隨機存取的特點,同時增加了節點的指標域,空間開銷較大。

     3.單鏈表的優缺點

   連結串列的優點:

  • 插入刪除速度快(因為有next指標指向其下一個節點,通過改變指標的指向可以方便的增加刪除元素)。
  • 記憶體利用率高,不會浪費記憶體(可以使用記憶體中細小的不連續空間(大於node節點的大小),並且在需要空間的時候才建立空間)。
  • 大小沒有固定,拓展很靈活。

   連結串列的缺點:

  • 不能隨機查詢,必須從第一個開始遍歷,查詢效率低。

二、單鏈表的基本操作

     初始化Init

     列印Print

     頭插PushFront    頭刪PopFront

     尾插PushBack     尾刪PopBack

     查詢Find

     銷燬Destroy

      ...

三、單鏈表的實現

 無頭單鏈表的實現:

----------------------------------LinkList.h-----------------------------------------
#pragma once
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
typedef int DataType;
typedef struct Node
{
	DataType data;
	struct Node* next;
}Node,*pNode,List,*pList;

void InitLinkList(pList *pplist);//初始化
void PushBack(pList *pplist,DataType d);//尾插
void PrintLinkList(pList plist);//列印
void DestroyLinkList(pList* pplist);//銷燬
int GetListLength(pList plist); //連結串列長度
void PopBack(pList* pplist);//尾刪
void PushFront(pList* pplist, DataType d);//頭插
void PopFront(pList* pplist);//頭刪
pNode Find(pList plist, DataType d);//查詢
void Insert(pList* pplist, pNode pos, DataType d);//在指定位置之前插入一個值 
void Erase(pList* pplist, pNode pos);//指定位置刪除 
void Remove(pList* pplist, DataType d);//刪除指定元素
void RemoveAll(pList* pplist, DataType d);//刪除指定所有元素
void EraseNotTailNode(pNode pos);//刪除一個無頭單鏈表的非尾節點 

----------------------------------LinkList.c--------------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include"LinkList.h" 
void InitLinkList(pList *pplist)//初始化
{
	assert(pplist != NULL);
	*pplist = NULL;

}
void PrintLinkList(pList plist)//列印
{
	pNode cur = plist;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}
void DestroyLinkList(pList* pplist)//銷燬
{
	pNode cur = *pplist;
	assert(pplist != NULL);
	while (cur != NULL)
	{
		pNode del = cur;
		cur = cur->next;
		free(del);
		del = NULL;
	}
	*pplist = NULL;//空連結串列

}
pNode BuyNode(DataType d)//建立新節點
{
	pNode newNode = (pNode)malloc(sizeof(Node));
	if (newNode == NULL)
	{
		perror("BuyNode : :malloc");
		return NULL;
	}
	newNode->data = d;
	newNode->next = NULL;
	return newNode;
}                 
int GetListLength(pList plist)  //連結串列長度
{
	pNode cur = plist;
	DataType n = 0;
	while (cur)
	{
		n++;
		cur = cur->next;
	}
	return n;
}
void PushBack(pList *pplist, DataType d)//尾插
{
	pNode newNode = NULL;
	assert(pplist != NULL);
	newNode = BuyNode(d);
	if (newNode == NULL)
	{
			return;
	}
	if (*pplist == NULL)
	{
		*pplist = newNode;
	}//無節點
	else
	{
		pNode cur = *pplist;
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		cur->next = newNode;
	}//有節點
}
void PopBack(pList* pplist)//尾刪
{
	pNode del = *pplist;
	pNode cur = *pplist;
	if (*pplist == NULL)
	{
		return;
	}
	while (del->next!=NULL)
	{
		cur = del;
		del = del->next;
	}
	cur->next = NULL;
	free(del);
	del = NULL;
}
void PushFront(pList* pplist, DataType d)//頭插
{
	assert(pplist != NULL);
	pNode newNode = NULL;
	newNode = BuyNode(d);
	newNode->next = *pplist;
	*pplist = newNode;
}

void PopFront(pList* pplist)//頭刪
{
	pNode del = *pplist;
	*pplist = del->next;
	free(del);
	del = NULL;
}
pNode Find(pList plist, DataType d) //查詢
{
	pNode cur = plist;
	while (cur != NULL)
	{
		if (cur->data == d)
		{
			return cur;
		}
		cur = cur->next;
	}
	return cur;
}
void Insert(pList* pplist, pNode pos, DataType d)//插入(插入的位置在pos前,利用Find找到pos)
{
	assert(pos != NULL);
	assert(pplist != NULL);
	if (*pplist == NULL)//空連結串列
	{
		return;
	}
	if (*pplist == pos)//一個節點
	{
		PushFront(pplist, d);
	}
	else//兩個及以上節點
	{
		pNode cur = *pplist;
		pNode newNode = NULL;
		newNode = BuyNode(d);
		while (cur && cur->next!= pos)
		{
			cur = cur->next;
		}
		if (cur != NULL)
		{
			newNode->next = cur->next;
			cur->next = newNode;
		}
	}
}
void Erase(pList* pplist, pNode pos)//刪除pos
{
	assert(pplist != NULL);
	assert(pos != NULL);
	if (*pplist == NULL)
	{
		return;
	}
	if (*pplist == pos)
	{
		PopFront(pplist);
	}
	else
	{
		pNode cur = *pplist;
		while (cur && cur->next != pos)
		{
			cur = cur->next;
		}
		if (cur != NULL)
		{
			cur->next = pos->next;
			free(pos);
			pos = NULL;
		}
	}
}
void Remove(pList* pplist, DataType d)//刪除指定元素
{
	assert(pplist != NULL);
	pNode cur = *pplist;
	pNode pre = NULL;
	while (cur)
	{
		if (cur->data == d)
		{
			if ((*pplist)->data == d)
			{
				PopFront(pplist);
			}
			else
			{
				pre->next = cur->next;
				free(cur);
				cur = NULL;
			}
			return;
		}
		pre = cur;
		cur = cur->next;
	}
}
void RemoveAll(pList* pplist, DataType d)//刪除指定所有元素
{
	assert(pplist != NULL);
	pNode cur = *pplist;
	pNode pre = NULL;
	pNode tmp = NULL;
	while (cur)
	{
		if (cur->data == d)
		{
			if ((*pplist)->data == d)
			{
				PopFront(pplist);
			}
			else
			{   
				tmp = cur;
				pre->next = cur->next;
				free(tmp);
				tmp = NULL;
			}
			cur = pre;
		}
		else
		{
			pre = cur;
			cur = cur->next;
		}
	}
}
void EraseNotTailNode(pNode pos)//刪除一個無頭單鏈表的非尾節點 
{
	pNode del = NULL;
	if (pos == NULL || pos->next == NULL)
		return;
	del = pos->next;
	pos->data = del->data;
	pos->next = del->next;
	free(del);
	del = NULL;
}

--------------------------------------test.c-----------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include "LinkList.h"
void test()
{
	List* plist = NULL;//指向一條連結串列的指標
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 2);
	PushBack(&plist, 4);

	//int i = GetListLength(plist);
	//printf("連結串列長度為:%d\n", i);
	
	//PopBack(&plist);
	//PrintLinkList(plist);
	//PushFront(&plist, 5);
	//PrintLinkList(plist);
	//PopFront(&plist);
	//PrintLinkList(plist);
	
	//Remove(&plist, 2);
	//PrintLinkList(plist);

	/*pNode to_insert = Find(plist, 3);
	Insert(&plist, to_insert, 5);
	PrintLinkList(plist);*/

	/*pNode to_erase = Find(plist, 5);
	Erase(&plist, to_erase);
	PrintLinkList(plist);*/

	//pNode to_erase_NTN = Find(plist, 3);
	//EraseNotTailNode(to_erase_NTN);
	//PrintLinkList(plist);
	
	RemoveAll(&plist, 2);
	PrintLinkList(plist);


	DestroyLinkList(&plist);
}
int main()
{
	test();
	system("pause");
	return 0;
}

 有頭單鏈表的實現:

----------------------------------List.h---------------------------------------------
#pragma once
#ifndef __LIST_H__
#define __LIST_H__
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
typedef int DataType;
typedef struct SHListNode
{
	DataType data;
	struct SHListNode* next;
}Node;

void InitSHListNode(Node** pHead);//初始化
void SHListPushBack(Node* pHead, DataType data);//尾插
void SHListPopBack(Node* pHead);//尾刪
void SHListPushFront(Node* pHead, DataType data);//頭插
void SHListPopFront(Node* pHead);//頭刪
void PrintLinkList(Node* pHead);//列印
void DestroySHList(Node** pHead);//銷燬

---------------------------------List.c------------------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"

Node* BuySHListNode(DataType data)//建立新結點
{
	Node* pNewNode = (Node*)malloc(sizeof(Node));
	if (NULL == pNewNode)
	{
		assert(0);
		return NULL;
	}
	pNewNode->data = data;
	pNewNode->next = NULL;
	return pNewNode;
}

void InitSHListNode(Node** pHead)//初始化
{
	assert(pHead);
	*pHead = BuySHListNode(0);
}

void SHListPushBack(Node* pHead, DataType data)//尾插
{
	Node* pNewNode = NULL;
	pNewNode = BuySHListNode(data);
	assert(pHead);
	Node* pCur = NULL;
	pCur = pHead;
	while (pCur->next != NULL)
	{
		pCur = pCur->next;
	}
	pCur->next = pNewNode;
}

void SHListPopBack(Node* pHead)//尾刪
{
	Node* pCur = pHead;
	Node* pPre = NULL;
	assert(pHead);
	if (NULL == pHead->next)
		return;
	while (pCur->next)
	{
		pPre = pCur;
		pCur = pCur->next;
	}
	free(pCur);
	pPre->next = NULL;
}

void SHListPushFront(Node* pHead,DataType data)//頭插
{
	assert(pHead);
	Node* pNewNode = NULL;
	pNewNode = BuySHListNode(data);
	pNewNode->next = pHead->next;
	pHead->next = pNewNode;
}

void SHListPopFront(Node* pHead) //尾插
{
	assert(pHead);
	Node* pDel = NULL;
	if (NULL == pHead->next)
		return;
	pDel = pHead->next;
	pHead->next = pDel->next;
	free(pDel);
}

void PrintLinkList(Node* pHead) //列印
{
	assert(pHead);
	Node* pCur = pHead;
	while (pCur)
	{
		printf("%d->", pCur->data);
		pCur = pCur->next;
	}
	printf("NULL\n");
}

void DestroySHList(Node** pHead)//銷燬
{
	Node* pCur = *pHead;
	assert(pHead != NULL);
	while (pCur != NULL)
	{
		Node* pDel = pCur;
		pCur = pCur->next;
		free(pDel);
		pDel = NULL;
	}
	*pHead = NULL;//空連結串列
}

--------------------------------------test.c--------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"
void test()
{
	Node* pHead = NULL;
	InitSHListNode(&pHead);
	SHListPushBack(pHead, 1);
	SHListPushBack(pHead, 2);
	SHListPushBack(pHead, 3);
	SHListPushBack(pHead, 4);
	PrintLinkList(pHead);
	SHListPopBack(pHead);
	PrintLinkList(pHead);
	SHListPushFront(pHead, 3);
	PrintLinkList(pHead);
	SHListPopFront(pHead);
	PrintLinkList(pHead);
	DestroySHList(&pHead);
}
int main()
{
		test();
		system("pause");
		return 0;
}