c語言實現數據結構--鏈表

鏈表存儲結構:每個節點包含兩個數據域,一個用來存放數據,另一個數據域用來保存下一個節點的地址(指針 )。這樣就將一些物理上不連續的內存組成鏈式存儲結構。也稱單鏈表。
在這裏插入圖片描述
代碼實現:

初始化鏈表

void ListInit(LinkList*list)
{
	assert(list != NULL);
	*list = (ListNode*)malloc(sizeof(ListNode));
	if (*list == NULL)
	{
		exit(-1);
	}
	(*list)->next = NULL;//*list爲頭結點
}

銷燬鏈表

void ListDestory(LinkList*list)//不斷刪除頭結點之後的節點,最後將頭結點刪除
{
	assert(list != NULL);
	ListNode* tmp = (*list)->next;//tmp指向即將被刪除的節點,list之後的節點
	while (tmp)
	{
		(*list)->next = (*list)->next->next;
		free(tmp);
		tmp = (*list)->next;
	}
	free(*list);//釋放頭結點
	(*list) = NULL;
}

插入元素e

在第i個位置插入新節點,節點數據爲e,以頭節點之後爲第一個元素

Status InsertList(LinkList*list, int i, ListDataType e)
{
	assert(list != NULL);
	if (i < 1)
	{
		return ERROR;//位置從1開始
	}
	int j = 0;
	ListNode*new = (ListNode*)malloc(sizeof(ListNode));
	ListNode*cur = (*list);//將頭結點之後的節點作爲第一個節點
	for (cur; cur&&j < i-1; cur = cur -> next,j++)
	{
		
	}
	if (j == i - 1)//當j=i-1時,cur的後繼節點即就是要插入的節點new
	{
		new->data = e;
		new->next = cur->next;
		cur->next = new;
		return OK;//插入成功
	}
	else
	{
		return ERROR;//插入失敗,i位置超過了鏈表的長度
	}
}

刪除節點

刪除節點並用e返回刪除元素的數據,刪除失敗返回ERROR(0)

Status DeleteList(LinkList*list, int i, ListDataType *e)
{
	assert(list != NULL);
	int j = 0;
	ListNode* cur = (*list);
	ListNode*tmp=NULL;
	while (i>1&&cur!=NULL)
	{
		cur = cur->next;
		i--;
	}
	if (cur->next == NULL)
	{
		return ERROR;//未知錯誤,第i個位置不存在節點
	}
	else
	{
		tmp = cur->next;
		cur->next = cur->next->next;//刪除節點cur->next
		*e = tmp->data;
		free(tmp);//釋放節點
		return OK;
	}
}

清空鏈表

將鏈表置空,釋放除頭節點之外的所有節點

void ListClear(LinkList*list)
{
	assert(list != NULL);
	ListNode*cur = (*list)->next;
	while (cur)
	{
		(*list)->next = (*list)->next->next;
		free(cur);
		cur = (*list)->next;
	}
}

判斷鏈表是否爲空

其實就是判斷頭結點之後是否還有節點

Status ListIsEmpty(LinkList list)
{
	assert(list != NULL);
	return list->next == NULL ? TRUE : FALSE;
}

獲取鏈表的節點個數

統計鏈表中的節點個數(除頭結點之外)

int GetListLength(LinkList list)
{
	int count = 0;
	ListNode*cur = list->next;
	while (cur)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

獲取鏈表中第i個元素

找到鏈表中第i個節點,並將e記錄其數據,返回額,否則返回NULL表示未找到

ListDataType *GetListElem(LinkList list, int i, ListDataType *e)
{
	assert(list != NULL);
	ListNode* cur = list->next;
	while (cur && i > 1)
	{
		cur = cur->next;
		i--;
	}
	if (cur == NULL)
	{
		return NULL;//cur位置沒有數據,i值超過鏈表長度
	}
	else
	{
		*e = cur->data;
		return e;
	}
}

判斷鏈表中節點是否包含該數據

遍歷鏈表,判斷每個節點的數據是否等於e,若等於,返回TRUE,否則,返回FALSE,表示不包含

Status Locate_exist_Elem(LinkList list, ListDataType e)
{
	ListNode*cur = list->next;
	while (cur)
	{
		if (cur->data == e)
		{
			return TRUE;
		}
		cur = cur->next;
	}
	return FALSE;
}

單鏈表相對於順序表來講,插入和刪除操作比較方便,其時間複雜度爲O(1)。只需要改變next指針的指向就ok,不需要移動大量數據。

完整代碼及測試用例:

函數聲明和節點定義List.h文件:

#pragma once
#ifndef _LIST_H_
#define _LIST_H_

/*
帶頭指針的頭結點:統一第一個節點和後續節點的操作
動態實現單鏈表
*/
#define MAXSIZE 20//存儲空間
#define OK 1//函數狀態返回值,成功返回1,不成功返回0
#define ERROR 0//
#define TRUE 1//真假值,真爲1,假爲0
#define FALSE 0
typedef int Status;//Status是函數類型,其值是函數結果狀態代碼 
typedef int ListDataType;
//定義鏈表節點類型
typedef struct Node
{
	ListDataType data;
	struct Node *next;
}ListNode, *LinkList;
//typedef struct ListNode;
void ListInit(LinkList*list);//初始化鏈表
void ListDestory(LinkList*list);//銷燬鏈表
Status InsertList(LinkList*list, int i, ListDataType e);//在第i個位置上插入元素
Status DeleteList(LinkList*list, int i, ListDataType *e);//刪除第i位的元素,並將數據用e返回
void ListClear(LinkList*list);//清空鏈表
Status ListIsEmpty(LinkList list);//判斷線性表是否爲空
int GetListLength(LinkList list);//獲取線性表長度
ListDataType *GetListElem(LinkList list, int i, ListDataType *e);//取第i個元素給e返回
Status Locate_exist_Elem(LinkList list, ListDataType e);//list鏈表中是否存在e元素
void PrintList(LinkList list);//打印鏈表函數

#endif

List.c包含函數實現

#include"List.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void ListInit(LinkList*list)
{
	assert(list != NULL);
	*list = (ListNode*)malloc(sizeof(ListNode));
	if (*list == NULL)
	{
		exit(-1);
	}
	(*list)->next = NULL;//*list爲頭結點
}
void ListDestory(LinkList*list)//不斷刪除頭結點之後的節點,最後將頭結點刪除
{
	assert(list != NULL);
	ListNode* tmp = (*list)->next;//tmp指向即將被刪除的節點,list之後的節點
	while (tmp)
	{
		(*list)->next = (*list)->next->next;
		free(tmp);
		tmp = (*list)->next;
	}
	free(*list);//釋放頭結點
	(*list) = NULL;
}
Status InsertList(LinkList*list, int i, ListDataType e)
{
	assert(list != NULL);
	if (i < 1)
	{
		return ERROR;//位置從1開始
	}
	int j = 0;
	ListNode*new = (ListNode*)malloc(sizeof(ListNode));
	ListNode*cur = (*list);//將頭結點之後的節點作爲第一個節點
	for (cur; cur&&j < i-1; cur = cur -> next,j++)
	{
		
	}
	if (j == i - 1)//當j=i-1時,cur的後繼節點即就是要插入的節點new
	{
		new->data = e;
		new->next = cur->next;
		cur->next = new;
		return OK;//插入成功
	}
	else
	{
		return ERROR;//插入失敗,i位置超過了鏈表的長度
	}
}
Status DeleteList(LinkList*list, int i, ListDataType *e)
{
	assert(list != NULL);
	int j = 0;
	ListNode* cur = (*list);
	ListNode*tmp=NULL;
	while (i>1&&cur!=NULL)
	{
		cur = cur->next;
		i--;
	}
	if (cur->next == NULL)
	{
		return ERROR;//未知錯誤,第i個位置不存在節點
	}
	else
	{
		tmp = cur->next;
		cur->next = cur->next->next;//刪除節點cur->next
		*e = tmp->data;
		free(tmp);//釋放節點
		return OK;
	}
}
void ListClear(LinkList*list)
{
	assert(list != NULL);
	ListNode*cur = (*list)->next;
	while (cur)
	{
		(*list)->next = (*list)->next->next;
		free(cur);
		cur = (*list)->next;
	}
}
Status ListIsEmpty(LinkList list)
{
	assert(list != NULL);
	return list->next == NULL ? TRUE : FALSE;
}
int GetListLength(LinkList list)
{
	int count = 0;
	ListNode*cur = list->next;
	while (cur)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

ListDataType *GetListElem(LinkList list, int i, ListDataType *e)
{
	assert(list != NULL);
	ListNode* cur = list->next;
	while (cur && i > 1)
	{
		cur = cur->next;
		i--;
	}
	if (cur == NULL)
	{
		return NULL;//cur位置沒有數據,i值超過鏈表長度
	}
	else
	{
		*e = cur->data;
		return e;
	}
}
Status Locate_exist_Elem(LinkList list, ListDataType e)
{
	ListNode*cur = list->next;
	while (cur)
	{
		if (cur->data == e)
		{
			return TRUE;
		}
		cur = cur->next;
	}
	return FALSE;
}

void PrintList(LinkList list)
{
	assert(list != NULL);
	ListNode*cur = list->next;
	printf("Head->");
	for (; cur; cur = cur->next)
	{
		printf("%d->", cur->data);
	}
	printf("NULL\n");
}

test.c測試代碼:

#include<stdbool.h>
#include<stdlib.h>
#include"List.h"
void TestLink()
{
	LinkList list;
	ListDataType e;
	int length;
	bool empty;
	ListInit(&list);
	length = GetListLength(list);
	printf("鏈表長度爲:%d\n", length);
	empty = ListIsEmpty(&list);
	printf("鏈表爲空?%d\n", empty);
	InsertList(&list, 1, 1);
	InsertList(&list, 1, 2);
	InsertList(&list, 1, 3);
	InsertList(&list, 1, 4);
	InsertList(&list, 4, 5);
	InsertList(&list, 6, 6);
	InsertList(&list, 7, 7);
	PrintList(list);
	empty = Locate_exist_Elem(list, 9);
	printf("鏈表中存在9?%d\n", empty);
	empty = Locate_exist_Elem(list, 5);
	printf("鏈表中存在5?%d\n", empty);
	empty = ListIsEmpty(&list);
	printf("鏈表爲空?%d\n", empty);
	length = GetListLength(list);
	printf("鏈表長度爲:%d\n", length);
	PrintList(list);
	DeleteList(&list, 1, &e);
	length = GetListLength(list);
	printf("鏈表長度爲:%d\n", length);
	printf("刪除第1個的元素值爲%d\n", e);
	empty = Locate_exist_Elem(list, e);
	printf("鏈表中存在%d?%d\n", e,empty);
	PrintList(list);
	DeleteList(&list, 4, &e);
	length = GetListLength(list);
	printf("鏈表長度爲:%d\n", length);
	printf("刪除第4個的元素值爲%d\n", e);
	GetListElem(&list, 2, &e);
	PrintList(list);
	ListClear(&list);
	length = GetListLength(list);
	printf("鏈表長度爲:%d\n", length);
	PrintList(list);
	ListDestory(&list);
}
int main()
{
	TestLink();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章