無頭單向非循環鏈表的實現

簡介

鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域,由於不必按順序存儲,鏈表在插入的時候可以達到O(1)的複雜度,比順序錶快得多,但是查找一個節點或者訪問特定編號的節點則需要O(n)的時間,而線性表和順序表相應的時間複雜度分別是O(logn)和O(1)。

分類

鏈表分爲帶頭、不帶頭,單向、雙向,循環、非循環,所以共有 8 種情況,但並不是 8 種情況都常用,我們挑出兩種極端的情況進行演示,即無頭單向非循環鏈表和帶頭雙向循環鏈表。

無頭單向非循環鏈表:結構簡單,一般不會單獨用來存數據。實際中更多是作爲其他數據結構的子結構,如哈希桶、圖的鄰接表等等。另外這種結構在筆試面試中出現很多。

在這裏插入圖片描述
帶頭雙向循環鏈表:結構最複雜,一般用在單獨存儲數據。 實際中使用的鏈表數據結構,都是帶頭雙向循環鏈表。另外這個結構雖然結構複雜,但是使用代碼實現以後會發現結構會帶來很多優勢,實現反而簡單了,後面我們代碼實現了就知道了。
在這裏插入圖片描述

具體實現

帶頭雙向循環鏈表的實現
常見的單鏈表面試題

無頭單向非循環鏈表:

LinkList.h

#pragma once 
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
//無頭單向非循環鏈表增刪查改實現 
typedef size_t LDataType;

//鏈表的單個節點
typedef struct ListNode 
{
	LDataType data;
	struct ListNode* next;
}ListNode;

//鏈表
typedef struct List
{
	ListNode* head;
}List;

void ListInit(List* plist); 
void ListDestory(List* plist);
ListNode* BuyListNode(LDataType data);
void ListPrint(List* plist);

void ListPushFront(List* plist, LDataType data);
void ListPopFront(List* plist);
void ListPushBack(List* plist, LDataType data);
void ListPopBack(List* plist);

ListNode* ListFind(List* plist, LDataType data);
void ListInsertAfter(ListNode* pos, LDataType data); // 在pos的後面進行插入 
void ListErase(List* plist, ListNode* pos);
void ListEraseAfter(ListNode* pos); 
void ListRemove(List* plist, LDataType data);

LinkList.c

#include"LinkList.h"

void ListInit(List* plist)
{
	assert(plist);
	plist->head = NULL;
}


void ListDestory(List* plist)
{
	assert(plist);
	for (ListNode* cur = plist->head; cur != NULL; cur = cur->next)
	{
		ListNode* next = cur->next;
		free(cur);
	}
	plist->head = NULL;
}

ListNode* BuyListNode(LDataType data)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	assert(node);
	node->data = data;
	node->next = NULL;
	return node;
}

void ListPrint(List* plist)
{
	assert(plist);
	for (ListNode *cur = plist->head; cur != NULL; cur = cur->next)
	{
		printf("%d->", cur->data);
	}
	printf("NULL\n");
}


void ListPushFront(List* plist, LDataType data)
{
	assert(plist);
	ListNode* node = BuyListNode(data);
	assert(node);
	node->next = plist->head;
	plist->head = node;
}

void ListPopFront(List* plist)
{
	assert(plist != NULL);//保證鏈表存在
	assert(plist->head);//保證鏈表不爲空
	ListNode* tmp = plist->head;
	plist->head = tmp->next;
	free(tmp);
}

void ListPushBack(List* plist, LDataType data)
{
	assert(plist);
	if (plist->head == NULL) {
		ListPushFront(plist, data);
		return;
	}
	ListNode *node = BuyListNode(data);
	assert(node); 
	ListNode* cur = plist->head;
	for (; cur->next != NULL; cur = cur->next)
	{ }
	cur->next = node;
}

void ListPopBack(List* plist)
{
	assert(plist);
	assert(plist->head);
	ListNode* cur = plist->head;
	if (cur->next == NULL) {
		ListPopFront(plist);
		return;
	}
	ListNode* pos = plist->head;
	for (; cur->next != NULL; cur = cur->next)
	{
		pos = cur;
	}
	free(cur);
	pos->next = NULL;
}

//查找給定數據在鏈表中的位置
ListNode* ListFind(List* plist, LDataType data)
{
	assert(plist);
	assert(plist->head);
	ListNode* cur = plist->head;
	while (cur!=NULL)
	{
		if (cur->data == data)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

 // 在pos的後面進行插入 
void ListInsertAfter(ListNode* pos, LDataType data)
{
	ListNode* node = BuyListNode(data);
	node->next = pos->next;
	pos->next = node;
}

//根據位置刪除元素
void ListErase(List* plist, ListNode* pos)
{
	assert(plist);
	if (plist->head == pos)
	{
		ListPopFront(plist);
	}
	else if (pos->next == NULL)
	{
		ListPopBack(plist);
	}
	else
	{
		ListNode* cur = plist->head;
		for (; cur != NULL; cur = cur->next)
		{
		}
		cur->next = pos->next;
		free(pos);
	}
}

//刪除給定位置後面的元素
void ListEraseAfter(ListNode* pos)
{
	ListNode* next = pos->next;
	pos->next = next->next;
	free(next);
}

//根據數據刪除元素
void ListRemove(List* plist, LDataType data)
{
	assert(plist);
	ListNode* cur = plist->head;
	ListNode* temp = NULL;
	if (cur->data == data) //當該數據是第一個節點時,直接頭刪
	{
		ListPopFront(plist);
		return;
	}
	else
	{
		while (cur) //頭節點不爲空
		{
			temp = cur;
			cur = cur->next;
			//這裏的if...else語句順序不能交換,需要先排除掉特殊情況,即要刪除的數據不存在
			//如果交換,當要刪除的數據不存在時,會陷入死循環
			if (NULL == cur)
			{
				printf("Data is not exist!\n");
				return;
			}
			else if (cur->data == data)
			{
				temp->next = cur->next;
				free(cur);
				break;
			}
		}
	}
}

test.c

#include"LinkList.h"

void test()
{
	List plist;
	ListInit(&plist);
	ListPushBack(&plist, 1);
	ListPushBack(&plist, 2);
	ListPushBack(&plist, 3);
	ListPushBack(&plist, 4);
	ListPushBack(&plist, 5);
	ListPushBack(&plist, 6);
	ListPrint(&plist);
	ListPopFront(&plist);
	ListPrint(&plist);

	//ListNode* pos = ListFind(&plist, 2);
	//ListErase(&plist, pos);
	//ListPrint(&plist);

	ListRemove(&plist, 8);
	ListNode* pos = ListFind(&plist, 3);
	ListInsertAfter(pos, 9);
	ListPrint(&plist);
	ListDestory(&plist);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章