鏈表:
鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點組成,結點可以在運行時動態生成。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。 相比於線性表順序結構,鏈表比較方便插入和刪除操作。
下面直接通過代碼進行展示:包括初始化一個可以指向任何數據類型的鏈表、鏈表中指定位置插入節點元素、鏈表中刪除指定位置的節點元素、獲取鏈表的長度、在鏈表中查找指定的元素並返回當前元素所在的索引值、返回鏈表第一個節點、釋放鏈表內存、打印鏈表、交換鏈表節點(鏈表從前向後第K個節點與從後向前第K個節點進行交換)。
LinkList.h
#pragma once
#include <windows.h>
#include <stdio.h>
// 鏈表結點
typedef struct LINKNODE
{
void* data; // 可以指向任何類型的數據
LINKNODE* next;
}LinkNode;
// 鏈表結構體
typedef struct LINKLIST
{
int size;
LinkNode* head;
}LinkList;
// 打印函數指針
typedef void(*PRINTLINKNODE)(void*);
// 初始化鏈表
LinkList* Init_LinkList();
// 指定位置插入
void Insert_LinkList(LinkList* list, int pos, void* data);
// 交換順序與逆序對應的第Key個值
void Key_LinkList(LinkList* list, int key);
// 指定位置刪除
void RemoveByPos_LinkList(LinkList* list, int pos);
// 獲得鏈表的長度
int GetLinkListSize(LinkList* list);
// 查找(根據數據返回索引)
int Find_LinkList(LinkList* list, void* data);
// 返回第一個結點
void* Front_LinkList(LinkList* list);
// 釋放鏈表內存
void FreeMem_LinkList(LinkList* list);
// 打印鏈表
void Print_LinkList(LinkList* list, PRINTLINKNODE);
LinkList.cpp
#include "LinkList.h"
// 初始化鏈表
LinkList* Init_LinkList()
{
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
list->size = 0;
// 頭結點是不保存數據的
list->head = (LinkNode*)malloc(sizeof(LinkNode));
list->head->data = NULL;
list->head->next = NULL;
return list;
}
// 指定位置插入
void Insert_LinkList(LinkList* list, int pos, void* data)
{
if (list == NULL || data == NULL)
{
return;
}
if (pos < 0 || pos > list->size)
{
pos = list->size;
}
// 創建新的結點
LinkNode* InsertNode = (LinkNode*)malloc(sizeof(LinkNode));
InsertNode->data = data;
InsertNode->next = NULL;
// 找結點
LinkNode* pCurrent = list->head;
for (int i = 0; i < pos; i++)
{
pCurrent = pCurrent->next;
}
// 將新結點插入鏈表
InsertNode->next = pCurrent->next;
pCurrent->next = InsertNode;
// 鏈表大小加1
list->size++;
}
// 指定位置刪除
void RemoveByPos_LinkList(LinkList* list, int pos)
{
if (list == NULL)
{
return;
}
if (pos < 0 || pos >= list->size)
{
return;
}
LinkNode* pCurrent = list->head;
for (int i = 0; i < pos; i++)
{
pCurrent = pCurrent->next;
}
LinkNode* pDel = pCurrent->next;
pCurrent->next = pCurrent->next->next;
free(pDel);
// 鏈表長度減一
list->size--;
}
// 獲得鏈表的長度
int GetLinkListSize(LinkList* list)
{
if (list == NULL)
{
return -1;
}
return list->size;
}
// 查找(根據數據返回索引)
int Find_LinkList(LinkList* list, void* data)
{
if (list == NULL || data == NULL)
{
return -1;
}
int pos = -1;
LinkNode* pCurrent = list->head->next;
for (int i = 0; i < list->size; i++)
{
if (pCurrent->data == data)
{
pos = i;
break;
}
pCurrent = pCurrent->next;
}
return pos;
}
// 返回第一個結點
void* Front_LinkList(LinkList* list)
{
return list->head->next->data;
}
// 釋放鏈表內存
void FreeMem_LinkList(LinkList* list)
{
if (list == NULL)
{
return;
}
LinkNode* pCurrent = list->head;
while (pCurrent != NULL)
{
LinkNode* pDel = pCurrent;
pCurrent = pCurrent->next;
free(pDel);
}
list->size = 0;
free(list);
}
// 打印鏈表
void Print_LinkList(LinkList* list, PRINTLINKNODE print)
{
if (list == NULL)
{
return;
}
LinkNode* pCurrent = list->head->next;
while (pCurrent != NULL)
{
print(pCurrent->data);
pCurrent = pCurrent->next;
}
}
// 交換 順序與逆序對應的第Key個值
void Key_LinkList(LinkList* list, int key)
{
int total_len;
int change;
//獲取鏈表長度
total_len = GetLinkListSize(list);
if (key / 2 == 1)
{
printf("交換後與交換前,鏈表數據無變化 !!\n");
return;
}
if (key < (total_len - key))
{
change = key;
}
else
{
change = total_len - key - 1;
}
LinkNode* pCurrent = list->head;
for (int i = 0; i < total_len; i++)
{
pCurrent = pCurrent->next;
if (i == change)
{
Insert_LinkList(list, total_len - change, pCurrent->data);
}
else if (i == total_len - change - 1)
{
Insert_LinkList(list, change, pCurrent->data);
}
}
RemoveByPos_LinkList(list, change + 1);
RemoveByPos_LinkList(list, total_len - change - 1);
}
main.cpp
// list.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
#include <iostream>
#include "LinkList.h"
//自定義數據類型
typedef struct PERSON
{
char name[64];
int age;
int score;
}Person;
//打印函數
void MyPrint(void* data)
{
Person* p = (Person*)data;
printf("Name:%s Age:%d Score:%d\n", p->name, p->age, p->score);
}
int main()
{
//創建鏈表
LinkList* list = Init_LinkList();
//創建數據
Person p1 = { "aaa", 6, 6 };
Person p2 = { "bbb", 5, 5 };
Person p3 = { "ccc", 4, 4 };
Person p4 = { "ddd", 3, 3 };
Person p5 = { "eee", 2, 2 };
Person p6 = { "fff", 1, 1 };
Person p7 = { "ggg", 0, 0 };
//數據插入鏈表
Insert_LinkList(list, 0, &p1);
Insert_LinkList(list, 0, &p2);
Insert_LinkList(list, 0, &p3);
Insert_LinkList(list, 0, &p4);
Insert_LinkList(list, 0, &p5);
Insert_LinkList(list, 0, &p6);
Insert_LinkList(list, 0, &p7);
//打印
printf("打印原始鏈表數據:\n");
Print_LinkList(list, MyPrint);
printf("\n");
printf("\n");
//交換,Key必須大於0
printf("給定一個數字Key,把從前向後第Key個節點與從後向前第Key個節點進行交換:\n");
int Key = 2;
if (Key < 1 || Key > (GetLinkListSize(list) -1 ))
{
printf("error: key invaid !!");
return 0;
}
printf("Key = %d\n",Key);
//交換
Key_LinkList(list, Key -1);
//打印
Print_LinkList(list, MyPrint);
printf("\n");
printf("\n");
//刪除3
printf("測試刪除某一個節點:\n");
RemoveByPos_LinkList(list, 3);
//打印
Print_LinkList(list, MyPrint);
printf("\n");
printf("\n");
//返回第一個結點
printf("-----查找鏈表首個節點------------\n");
Person* ret = (Person*)Front_LinkList(list);
printf("Name:%s Age:%d Score:%d\n", ret->name, ret->age, ret->score);
//銷燬鏈表
Front_LinkList(list);
getchar();
return 0;
}
如下效果圖: