C語言實現帶頭節點的單鏈表及基本操作【線性表】(5)

LinkList.h

#pragma 

/*------------------------------------------------------------
// 鏈表結構的定義
------------------------------------------------------------*/

typedef int ElemType;


typedef struct _Node
{
	ElemType data;				// 元素數據
	struct _Node* next;			// 鏈表中結點元素的指針
}Node, * NodePtr;

/*------------------------------------------------------------
// 鏈表的基本操作
------------------------------------------------------------*/

void InitList(NodePtr head);//單鏈表初始化
void DestroyList(NodePtr head, ElemType * data);//銷燬
bool IsListEmpty(NodePtr head);//判空
int  ListLength(NodePtr head);//求鏈表長度
bool GetElem(NodePtr head, int pos,ElemType* data); //得到鏈表的第pos個元素
int LocateElem(NodePtr head, ElemType data);//得到鏈表指定元素的位置
Node* GetPosPrior(NodePtr head, int pos);//獲得pos位置節點的前驅節點
Node* GetPosNext(NodePtr head, int pos);//獲得pos位置節點的後繼節點
void Show(NodePtr head); //打印單鏈表
bool ListInsert(NodePtr head, int pos, ElemType data);//在指定位置插入元素
void ListInsertHead(NodePtr head, ElemType data);//在鏈表的頭部插入元素
void ListInsertTail(NodePtr head, ElemType data);//在鏈表的尾部插入元素
bool ListDeletePos(NodePtr head, int pos, ElemType* data);//刪除指定位置的元素
void ListDeleteHead(NodePtr head, ElemType* data);//刪除單鏈表的第一個元素
void ListDeleteTail(NodePtr head, ElemType* data);//刪除單鏈表的最後一個元素
void ListDeleteData(NodePtr head, ElemType data);//刪除與data相等數據的元素

LinkLlist.cpp

#include "LinkList.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>

#define		ERROR_JUDGEMENT 	assert(NULL != head);\
if (NULL == head)\
{\
	printf("%s %d error\n", __FUNCTION__, __LINE__);\
	exit(-1);\
}

/*------------------------------------------------------------
操作目的:	初始化單鏈表
初始條件:	單鏈表不存在
操作結果:	創建一個空的單鏈表
函數參數:
		NodePtr head	待初始化單鏈表的頭節點
返回值:
		void  無返回值
------------------------------------------------------------*/
void InitList(NodePtr head)
{
	ERROR_JUDGEMENT
	head->next = NULL;	
	head->data = 0;
}

/*------------------------------------------------------------
操作目的:	銷燬單鏈表
初始條件:	單鏈表head已存在
操作結果:	單鏈表不存在
函數參數:
		NodePtr head	待銷燬的單鏈表頭結點
返回值:
		void 無
------------------------------------------------------------*/
void DestroyList(NodePtr head, ElemType* data)
{
	ERROR_JUDGEMENT
	while (head->next)
		ListDeleteHead(head,data);
}

/*------------------------------------------------------------
操作目的:	判斷單鏈表是否爲空
初始條件:	線性表head已存在
操作結果:	若單鏈表head爲空表,則返回true,否則返回false
函數參數:
		NodePtr head	待判斷的單鏈表
返回值:
		bool	返回  true 表示單鏈表爲空				返回  false 表示單鏈表不爲空
------------------------------------------------------------*/
bool IsListEmpty(NodePtr head)
{
	ERROR_JUDGEMENT
	return head->next == NULL ? true : false;
}

/*------------------------------------------------------------
操作目的:	得到單鏈表的長度
初始條件:	單鏈表head已存在
操作結果:	返回L中數據元素的個數
函數參數:
		NodePtr head	單鏈表的head頭節點
返回值:
		int		單鏈表數據元素的個數
------------------------------------------------------------*/
int  ListLength(NodePtr head)
{
	ERROR_JUDGEMENT
	return head->data;
}

/*------------------------------------------------------------
操作目的:	得到單鏈表的pos位置元素
初始條件:	單鏈表L已存在,1<=i<=ListLength(head)
操作結果:	返回查找到的元素
函數參數:
		NodePtr head	單鏈表的head頭節點
		int pos			數據元素的位置
		ElemType *data	存儲查找到的元素數據
返回值:
		bool 查找到返回爲true   沒有找到返回爲false
------------------------------------------------------------*/
bool GetElem(NodePtr head, int pos,ElemType *data)
{
	ERROR_JUDGEMENT
	Node* tmp = head->next;
	int j = 1;
	while (tmp && j < pos)
	{
		tmp = tmp->next;
		j++;
	}
	if (!tmp || j > pos)
		return false;
	else
	{
		*data = tmp->data;
		return true;
	}
}

/*------------------------------------------------------------
操作目的:	得到單鏈表指定元素的位置
初始條件:	單鏈表head已存在
操作結果:	返回單鏈表中查找到的和指定 data 相等的元素的下標
			若這樣的元素不存在則返回0。
函數參數:
		NodePtr head	線性表head
		ElemType data	查找的元素
返回值:
		int   返回元素的位置  如果元素不存在則返回 0 
------------------------------------------------------------*/
int LocateElem(NodePtr head, ElemType data)
{
	ERROR_JUDGEMENT
	Node* tmp = head -> next;
	unsigned count = 0;
	while (tmp)
	{
		count++;
		if (data == tmp->data)
			return count;
		else
		{
			tmp = tmp->next;
		}
	}
	return 0;
}

/*------------------------------------------------------------
操作目的:	返回單鏈表中pos位置的前驅節點
初始條件:	單鏈表head已存在
操作結果:	返回單鏈表中pos位置的前驅節點的地址
函數參數:
		NodePtr head		線性表head
		int pos		   鏈表位置
返回值:
		Node* 返回前驅節點的指針
------------------------------------------------------------*/
Node* GetPosPrior(NodePtr head, int pos)
{
	ERROR_JUDGEMENT
	if (pos<1 || pos>head->data)
	{
		printf("pos error");
		exit(0);
	}
	Node* tmp =head;
	while (tmp && pos > 1)
	{
		tmp = tmp->next;
		pos--;
	}
	return tmp;
}

/*------------------------------------------------------------
操作目的:	返回單鏈表中pos位置的後繼節點
初始條件:	單鏈表head已存在
操作結果:	返回單鏈表中pos位置的後繼節點的地址
函數參數:
		NodePtr head		線性表head
		int pos				鏈表位置
返回值:
		返回pos位置的後繼節點
------------------------------------------------------------*/

Node* GetPosNext(NodePtr head, int pos)
{
	ERROR_JUDGEMENT
	if (pos<1 || pos>head->data)
	{
		printf("pos error");
		exit(0);
	}
	Node* tmp = head;
	while (tmp && pos > 0)
	{
		tmp = tmp->next;
		pos--;
	}
	return tmp->next;
}
/*------------------------------------------------------------
操作目的:	打印單鏈表
初始條件:	單鏈表head已存在
操作結果:	依次打印鏈表中所有元素的數據域
函數參數:
		NodePtr head		線性表head
返回值:
		void
------------------------------------------------------------*/
void Show(NodePtr head)
{
	ERROR_JUDGEMENT
	Node* tmp = head->next;
	while (tmp)
	{
		printf("%d\t", tmp->data);
		tmp = tmp->next;
	}
	printf("\n");

}


/*------------------------------------------------------------
操作目的:	在單鏈表的指定位置插入結點,插入位置i表示在第i個
			元素之前插入
初始條件:	線性表head已存在,0<=i<=ListLength(head)
操作結果:	在head中第pos個位置插入新的數據元素data,head的長度加1
函數參數:
		NodePtr head	線性表head
		int pos		插入位置
		ElemType data	待插入的數據元素
返回值:
		void
------------------------------------------------------------*/
bool ListInsert(NodePtr head, int pos, ElemType data)
{
	ERROR_JUDGEMENT
	if (pos<1 || pos>head->data + 1)
	{
		printf("pos error");
		exit(0);
	}
	NodePtr p = head;
	int j = 0;
	while (p && j < pos - 1)
	{
		p = p->next;
		++j;
	}
	if (p && j > pos - 1)
	{
		return false;
	}
	NodePtr tmp = (NodePtr)malloc(sizeof(Node));
	tmp->data = data;
	tmp->next = p->next;
	p->next = tmp;
	head->data++;
	return true;
}


/*------------------------------------------------------------
操作目的:	在單鏈表的頭部插入元素
初始條件:	單鏈表L已存在
操作結果:	在單鏈表的頭部插入元素,head的長度加1
函數參數:
		NodePtr head	線性表head
		ElemType data	待插入的數據元素
返回值:
		bool		操作是否成功
------------------------------------------------------------*/
void ListInsertHead(NodePtr head, ElemType data)
{

	ERROR_JUDGEMENT
	ListInsert(head, 1, data);
}


/*------------------------------------------------------------
操作目的:	在單鏈表的尾部位置插入節點
初始條件:	單鏈表head已存在
操作結果:	在L中尾部插入節點,head的長度加1
函數參數:
		NodePtr head	    線性表head
		ElemType data	待插入的數據元素
返回值:
		無
------------------------------------------------------------*/
void ListInsertTail(NodePtr head, ElemType data)
{

	ERROR_JUDGEMENT
	ListInsert(head, head->data + 1, data);
}




/*------------------------------------------------------------
操作目的:	刪除單鏈表的第i個結點
初始條件:	單鏈表存在
操作結果:	刪除head的第i個數據元素
函數參數:
		NodePtr head	線性表head
		int pos   		刪除位置

返回值:
		無返回值
------------------------------------------------------------*/
bool ListDeletePos(NodePtr head, int pos,ElemType * data)
{
	ERROR_JUDGEMENT
	if (pos<1 || pos>head->data)
		exit(0);
	NodePtr p = head, q;
	int j = 0;
	while (p->next && j < pos - 1)
	{
		p = p->next;
		++j;
	}
	if (!(p->next) || j > pos - 1)
		return false;

	q = p->next;
	p->next = q->next;
	*data = q->data;
	free(q);
	head->data--;
	return true;
}

/*------------------------------------------------------------
操作目的:	刪除單鏈表的頭節點
初始條件:	單鏈表head已存在且非空
操作結果:	刪除head的頭節點
函數參數:
		NodePtr head	線性表head
返回值:
		無返回值
------------------------------------------------------------*/
void ListDeleteHead(NodePtr head,ElemType *data)
{
	ERROR_JUDGEMENT
	ListDeletePos(head, 1, data);
}


/*------------------------------------------------------------
操作目的:	刪除單鏈表的尾節點
初始條件:	單鏈表head已存在且非空
操作結果:	刪除head的尾節點
函數參數:
		LinkList head	線性表head
返回值:
		無返回值
------------------------------------------------------------*/
void ListDeleteTail(NodePtr head, ElemType* data)
{
	ERROR_JUDGEMENT
	ListDeletePos(head, head->data,data);
}


/*------------------------------------------------------------
操作目的:	刪除鏈表數據域爲data的節點
初始條件:	線性表head已存在且非空
操作結果:	刪除鏈表數據域爲data的節點
函數參數:
		NodePtr head	線性表head
		ElemType data	被刪除的數據元素值
返回值:
		無返回值
------------------------------------------------------------*/
void ListDeleteData(NodePtr head, ElemType data)   //刪除與data相等數據的元素
{
	ERROR_JUDGEMENT
	Node* tmp = head->next;
	int count = 1;
	while (tmp)
	{
		if (tmp->data == data)
		{
			Node* PosPrior = GetPosPrior(head, count);
			Node* PosNode = PosPrior->next;
			PosPrior->next = PosNode->next;
			free(PosNode);
			return;
		}
		else
		{
			tmp = tmp->next;
			count++;
		}
	}
}

main.cpp

#include "LinkList.h"
#include <stdio.h>

int main()
{
	Node Head;
	ElemType data = 0;
	int pos = 1;

	InitList(&Head);//初始化

	for (int i = 1; i <= 10; i++)//調用頭插法
	{
		ListInsertHead(&Head, i * 10);
	}
	Show(&Head);

	data = 999;
	pos = 4;
	printf("在單鏈表的第%d位置插入數據:%d\n",pos, data);
	ListInsert(&Head, pos, data);
	Show(&Head);

	data = 666;
	printf("在單鏈表的尾部插入數據%d:\n", data);
	ListInsertTail(&Head,data);
	Show(&Head);

	data = 119;
	printf("在單鏈表的頭部插入數據%d:\n", data);
	ListInsertHead(&Head, data);
	Show(&Head);

	pos = 4;
	printf("刪除單鏈表的%d位置元素:\n",pos);
	ListDeletePos(&Head, pos, &data);
	Show(&Head);

	printf("刪除單鏈表頭部位置的元素:\n");
	ListDeleteHead(&Head, &data);
	Show(&Head);

	printf("刪除單鏈表頭尾位置的元素:\n");
	ListDeleteTail(&Head, &data);
	Show(&Head);

	printf("獲得單鏈表長度:\n");
	printf("%d\n", ListLength(&Head));

	pos = 3;
	printf("%d\n", GetElem(&Head, pos, &data));
	printf("獲得單鏈表的第%d個位置的數據元素爲%d\n",pos,data);

	data = 70;
	printf("數據元素%d所在的位置爲%d\n", data, LocateElem(&Head, data));

	pos = 7;
	printf("獲得第%d個數據元素的前驅結點數據:\n",pos);
	Node* PosPrior = GetPosPrior(&Head, pos);
	printf("pos %d prior node data : %d\n", pos, (*PosPrior).data);


	pos = 7;
	printf("獲得第%d個數據元素的後繼結點數據:\n", pos);
	PosPrior = GetPosNext(&Head, pos);
	printf("pos %d next node data : %d\n", pos, (*PosPrior).data);
	if (IsListEmpty(&Head))
		printf("單鏈表爲空\n");
	else
		printf("單鏈表不爲空\n");

	printf("銷燬單鏈表\n");
	DestroyList(&Head, &data);
	if (!Head.next)
		printf("單鏈表銷燬成功");
	return 0;
}

測試運行結果

單鏈表的基本使用測試結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章