线性表的链式存储又称为单链表,通过一组任意的存储单元来存储线性表中的数据元素。
这种方式,当head为null时,单链表L为空。
这种方式,当head->next为null时,单链表L为空。
优点:链表的第一个位置和其他位置的操作统一空表和非空表的操作统一。
有单链表的性质可知,单链表中包含着结点,结点又由两部分组成,一部分为数据,一部分为下一个结点的地址。所以可以将结点定义为:
//链表结点
typedef struct LinkNode {void* data; //void* 无类型指针,可以指向任何类型的数据struct LinkNode* next;
}LinkNode;
为了方便表述链表,这里使用有头结点的链表结构,并且需要一个int类型的变量来记录链表的长度。
//链表结构体
typedef struct LinkList {LinkNode* head; //头节点int size; //大小//不需要容量
}LinkList;
这里编写一个函数,进行链表的初始化操作。
//初始化链表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;
}
由图可以看出,想要实现头插入操作时,只需要将上一个结点的地址指向要插入结点的头部,而将要插入结点的地址指针指向原先上一个结点指向的地址即可。该头插法插入的特点为,后面插入的元素在链表的头部。
//头插法建立单链表
LinkList* List_HeadInsert(int size) {//创建链表LinkList* list = Init_LinkList();//用户输入size个整数int x;scanf("%d\n",&x);LinkNode* newNode = (LinkNode*)malloc(sizeof(LinkNode));for(int i = 0;i
}
该算法的时间复杂度为O(n)
使用尾插法建立单链表,就是在尾部进行链表结点的加入,使得辅助指针后移,实现尾部插入。该插入方法的特点为,后来的元素在链表后面。
//尾插法
LinkList* List_TailInsert(int size) {//创建链表LinkList* list = Init_LinkList();//用户输入size个整数int x;scanf("%d\n",&x);LinkNode* newNode = (LinkNode*)malloc(sizeof(LinkNode));//找结点//辅助指针变量LinkNode* pCurrent = list->head;for(int i = 0; i
}
该算法的时间复杂度为O(n)
按序号查找,就是通过辅助指针遍历到需要查找的序号的位置,并且将该结点进行返回,代码如下。
//按序号查找
LinkNode* getElem(LinkList* list,int pos) {if(list &#61;&#61; NULL) return NULL;if(pos &#61;&#61; 0) return list->head;if(pos <1 || pos > list->size) return NULL;//找结点//辅助指针变量LinkNode* pCurrent &#61; list->head->next;//遍历查找for(int i &#61; 0; i
}
按值查找&#xff0c;就是循环遍历整个链表&#xff0c;然后于传入的值进行匹配&#xff0c;如果相等&#xff0c;则返回该结点。
//查找
int Find_LinkList(LinkList* list,void* data) {if(list &#61;&#61; NULL) return -1;if(data &#61;&#61; NULL) return -1;//定义辅助指针LinkNode* pCurrent &#61; list->head->next;for(int i &#61; 1;i <&#61; list->size;i&#43;&#43;) {if(pCurrent->data &#61;&#61; data) {return i;}pCurrent &#61; pCurrent->next;}return -1;
}
这两个查找的算法都为O(n)
右图可以看出&#xff0c;插入操作以头插法建立单链表的操作几乎一样&#xff0c;只不过在这里是把头结点替换成了任意结点。
//插入
void Insert_LinkList(LinkList* list, int pos,void* data) {if(list &#61;&#61; NULL) return;if(data &#61;&#61; NULL) return;//将用户的从1开始排序&#xff0c;转换成为程序员理解的从0开始排序pos &#61; pos - 1;if(pos <0 || pos > list->size) return;//创建新的结点LinkNode* newNode &#61; (LinkNode*)malloc(sizeof(LinkNode));newNode->data &#61; data;newNode->next &#61; NULL;//找结点//辅助指针变量LinkNode* pCurrent &#61; list->head;for(int i &#61; 0; i
在单链表中&#xff0c;如果要删除一个结点&#xff0c;只需要将待删除结点的前一个结点指向待删除结点的下一个结点即可。
//删除指定位置的值
void RemoveByPos_LinkList(LinkList* list,int pos) {if(list &#61;&#61; NULL) return;if(pos <1 || pos > list->size) return;//找结点//辅助指针变量LinkNode* pCurrent &#61; list->head;//指向前一个结点for(int i &#61; 1; i
}
LinkList.h文件中的内容&#xff0c;该文件内容定义了该单链表具有的方法
#ifndef XGP_STUDY_DEMO40_LINKLIST_H
#define XGP_STUDY_DEMO40_LINKLIST_H#include
#include
#include
typedef struct LinkNode {void* data; //void* 无类型指针&#xff0c;可以指向任何类型的数据struct LinkNode* next;
}LinkNode;//链表结构体
typedef struct LinkList {LinkNode* head; //头节点int size; //大小//不需要容量
}LinkList;typedef void(*PRINTLINKNODE)(void*);//初始化链表
LinkList* Init_LinkList();
//插入错作
void Insert_LinkList(LinkList* list, int pos,void* data);
//头插法建立整数型单链表
LinkList* List_HeadInsert(int size);
//尾插法
LinkList* List_TailInsert(int size);
//按序号查找
LinkNode* getElem(LinkList* list,int pos);
//按值查找
int Find_LinkList(LinkList* list,void* data);
//删除指定位置的值
void RemoveByPos_LinkList(LinkList* list,int pos);
//获得链表的长度
int Size_LinkList(LinkList* list);
//释放链表内存
void FreeSpace_LinkList(LinkList* list);
//打印
void Print_LinkList(LinkList* list,PRINTLINKNODE print);
#endif //XGP_STUDY_DEMO40_LINKLIST_H
LinkList.c文件的内容&#xff0c;该内容是对上述头文件中的方法做具体得实现。
#include "LinkList.h"//初始化链表LinkList* Init_LinkList() {LinkList* list &#61; (LinkList*)malloc(sizeof(LinkList));list->size &#61; 0;//头节点&#xff0c;不保存数据信息list->head &#61; (LinkNode*)malloc(sizeof(LinkNode));list->head->data &#61; NULL;list->head->next &#61; NULL;return list;
}//插入
void Insert_LinkList(LinkList* list, int pos,void* data) {if(list &#61;&#61; NULL) return;if(data &#61;&#61; NULL) return;//将用户的从1开始排序&#xff0c;转换成为程序员理解的从0开始排序pos &#61; pos - 1;if(pos <0 || pos > list->size) return;//创建新的结点LinkNode* newNode &#61; (LinkNode*)malloc(sizeof(LinkNode));newNode->data &#61; data;newNode->next &#61; NULL;//找结点//辅助指针变量LinkNode* pCurrent &#61; list->head;for(int i &#61; 0; i
LinkList* List_HeadInsert(int size) {//创建链表LinkList* list &#61; Init_LinkList();//用户输入size个整数int x;scanf("%d\n",&x);LinkNode* newNode &#61; (LinkNode*)malloc(sizeof(LinkNode));for(int i &#61; 0;i
}//尾插法
LinkList* List_TailInsert(int size) {//创建链表LinkList* list &#61; Init_LinkList();//用户输入size个整数int x;scanf("%d\n",&x);LinkNode* newNode &#61; (LinkNode*)malloc(sizeof(LinkNode));//找结点//辅助指针变量LinkNode* pCurrent &#61; list->head;for(int i &#61; 0; i
}//按序号查找
LinkNode* getElem(LinkList* list,int pos) {if(list &#61;&#61; NULL) return NULL;if(pos &#61;&#61; 0) return list->head;if(pos <1 || pos > list->size) return NULL;//找结点//辅助指针变量LinkNode* pCurrent &#61; list->head->next;//遍历查找for(int i &#61; 0; i
}//查找
int Find_LinkList(LinkList* list,void* data) {if(list &#61;&#61; NULL) return -1;if(data &#61;&#61; NULL) return -1;//定义辅助指针LinkNode* pCurrent &#61; list->head->next;for(int i &#61; 1;i <&#61; list->size;i&#43;&#43;) {if(pCurrent->data &#61;&#61; data) {return i;}pCurrent &#61; pCurrent->next;}return -1;
}//删除指定位置的值
void RemoveByPos_LinkList(LinkList* list,int pos) {if(list &#61;&#61; NULL) return;if(pos <1 || pos > list->size) return;//找结点//辅助指针变量LinkNode* pCurrent &#61; list->head;//指向前一个结点for(int i &#61; 1; i
}
//打印
void Print_LinkList(LinkList* list,PRINTLINKNODE print) {if(list &#61;&#61; NULL) return;//定义辅助指针变量LinkNode* pCurrent &#61; list->head->next;for(int i &#61; 0;i
}//释放链表内存
void FreeSpace_LinkList(LinkList* list) {if(list &#61;&#61; NULL) return;//辅助指针变量LinkNode* pCurrent &#61; list->head;for(int i &#61; 0;i <&#61; list->size;i&#43;&#43;) {//缓存下一个结点LinkNode* pNext &#61; pCurrent->next;free(pCurrent);pCurrent &#61; pNext;}//释放链表内存list->size &#61; 0;free(list);}//获得链表的长度
int Size_LinkList(LinkList* list) {if(list &#61;&#61; NULL)return -1;return list->size;
}
main.c文件中的内容&#xff0c;该内容的代码是用来测试该单链表中的方法。
#include "LinkList.h"typedef struct Person {char name[64];int age;int score;
}Person;void MyPrint(void* data) {Person* p &#61; (Person*)data;printf("Name:%s Age:%d Score:%d\n",p->name,p->age,p->score);
}int main() {//创建链表LinkNode* list &#61; Init_LinkList();//创建数据Person p1 &#61; {"aaa",23,80};Person p2 &#61; {"bbb",24,81};Person p3 &#61; {"ccc",25,82};Person p4 &#61; {"ddd",26,83};Person p5 &#61; {"eee",27,84};//数据插入链表Insert_LinkList(list,0,&p1);Insert_LinkList(list,1,&p2);Insert_LinkList(list,2,&p3);Insert_LinkList(list,3,&p4);Insert_LinkList(list,4,&p5);//打印Print_LinkList(list,MyPrint);printf("&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;\n");//删除RemoveByPos_LinkList(list,3);Print_LinkList(list,MyPrint);//销毁链表FreeSpace_LinkList(list);return 0;
}
测试结果
Name:bbb Age:24 Score:81
Name:ccc Age:25 Score:82
Name:ddd Age:26 Score:83
Name:eee Age:27 Score:84
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
Name:bbb Age:24 Score:81
Name:ccc Age:25 Score:82
Name:eee Age:27 Score:84Process finished with exit code 0
#ifndef XGP_STUDY_DEMO43_MYLINKLIST_H
#define XGP_STUDY_DEMO43_MYLINKLIST_H#include
using namespace std;typedef void(*PRINTLINKNODE)(void*);template
class MyLinkNode {
public:T* data; //存放T类型的数据MyLinkNode* next; //下一个结点
};template
class MyLinkList {private:MyLinkNode
#include "MyLinkList.h"template
MyLinkList
}template
void MyLinkList
}template
MyLinkList
}template
MyLinkList
}template
MyLinkNode
}template
int MyLinkList
}template
void MyLinkList
}template
int MyLinkList
}template
void MyLinkList
}template
void MyLinkList
}
#include
#include "MyLinkList.cpp"class Person {
public:string name;int age;int score;Person(const string &name, int age, int score) : name(name), age(age), score(score) {}};void MyPrint(void* data) {Person* p &#61; (Person*)data;cout<
aaa 23 80
bbb 24 81
ccc 25 82
ddd 26 83
eee 27 84
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
ccc 25 82Process finished with exit code 0
package com.xgp.单链表;public class MyLinkNode
}
package com.xgp.单链表;public interface MyLinkList
}
package com.xgp.单链表;import java.util.Scanner;public class MyLinkListImpl
}
package com.xgp.单链表;public class Person {private String name;private int age;private int score;public Person(String name, int age, int score) {this.name &#61; name;this.age &#61; age;this.score &#61; score;}&#64;Overridepublic String toString() {return "Person{" &#43;"name&#61;&#39;" &#43; name &#43; &#39;\&#39;&#39; &#43;", age&#61;" &#43; age &#43;", score&#61;" &#43; score &#43;&#39;}&#39;;}
}
package com.xgp.单链表;public class Main {public static void main(String[] args) {MyLinkList
}
Person{name&#61;&#39;aaa&#39;, age&#61;23, score&#61;80}
Person{name&#61;&#39;bbb&#39;, age&#61;24, score&#61;81}
Person{name&#61;&#39;ccc&#39;, age&#61;25, score&#61;82}
Person{name&#61;&#39;ddd&#39;, age&#61;26, score&#61;83}
Person{name&#61;&#39;eee&#39;, age&#61;27, score&#61;84}
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
Person{name&#61;&#39;aaa&#39;, age&#61;23, score&#61;80}
Person{name&#61;&#39;bbb&#39;, age&#61;24, score&#61;81}
Person{name&#61;&#39;ddd&#39;, age&#61;26, score&#61;83}
Person{name&#61;&#39;eee&#39;, age&#61;27, score&#61;84}进程完成&#xff0c;退出码 0
class Person {constructor(name,age,score) {this.name &#61; name;this.age &#61; age;this.score &#61; score;}print() {return "name:" &#43; this.name &#43; "&#xff0c;age: " &#43; this.age &#43; "&#xff0c;score:" &#43; this.score;}
}//创建结点类
class LinkNode {}class LinkList {//初始化链表Init_LinkList() {var node &#61; new LinkNode();node.data &#61; null;node.next &#61; null;this.head &#61; node;this.size &#61; 0;return this;}//插入错作Insert_LinkList(pos,data) {if(data &#61;&#61; null) return;if(pos <1 || pos > this.size &#43; 1) return;//建立新结点var newNode &#61; new LinkNode();newNode.data &#61; data;newNode.next &#61; null;//建立辅助指针var pCurrent &#61; this.head;for(var i &#61; 1;i
name:aaa&#xff0c;age: 23&#xff0c;score:80 MyLinkList.js:135:25
name:bbb&#xff0c;age: 24&#xff0c;score:81 MyLinkList.js:135:25
name:ccc&#xff0c;age: 25&#xff0c;score:82 MyLinkList.js:135:25
name:ddd&#xff0c;age: 26&#xff0c;score:83 MyLinkList.js:135:25
name:eee&#xff0c;age: 27&#xff0c;score:84 MyLinkList.js:135:25
5 MyLinkList.html:30:17
Object { name: "ccc", age: 25, score: 82 }
MyLinkList.html:32:17
4 MyLinkList.html:34:17
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61; MyLinkList.html:36:17
name:aaa&#xff0c;age: 23&#xff0c;score:80 MyLinkList.js:135:25
name:ccc&#xff0c;age: 25&#xff0c;score:82 MyLinkList.js:135:25
name:ddd&#xff0c;age: 26&#xff0c;score:83 MyLinkList.js:135:25
name:eee&#xff0c;age: 27&#xff0c;score:84 MyLinkList.js:135:25
# 定义一个Person类
class Person:def __init__(self,name,age,score):self.name &#61; nameself.age &#61; ageself.score &#61; scoredef toString(self):print("name: ",self.name,"&#xff0c;age:",self.age,"&#xff0c;score:",self.score)class LinkNode:passclass LinkList:# 初始化链表def Init_LinkList(self):node &#61; LinkNode()node.data &#61; Nonenode.next &#61; Noneself.head &#61; nodeself.size &#61; 0return self# 插入错作def Insert_LinkList(self,pos,data):if(data &#61;&#61; None):returnif(pos <1 or pos > self.size &#43; 1):return# 创立待插入的新节点newNode &#61; LinkNode()newNode.data &#61; datanewNode.next &#61; None# 辅助指针pCurrent &#61; self.headfor i in range(1,pos):pCurrent &#61; pCurrent.next# 进行插入newNode.next &#61; pCurrent.nextpCurrent.next &#61; newNodeself.size &#43;&#61; 1# 头插法建立整数型单链表def List_HeadInsert(self,size):for i in range(1,size &#43; 1):newNode &#61; LinkNode()newNode.data &#61; inewNode.next &#61; self.head.nextself.head.next &#61; newNodeself.size &#43;&#61; 1return self# 尾插法def List_TailInsert(self,size):pCurrent &#61; self.headfor i in range(1,self.size &#43; 1):pCurrent &#61; pCurrent.nextfor i in range(1,size &#43; 1):newNode &#61; LinkNode()newNode.data &#61; inewNode.next &#61; NonepCurrent.next &#61; newNodepCurrent &#61; pCurrent.nextself.size &#43;&#61; 1return self# 按序号查找def getElem(self,pos):if(pos <1 or pos > self.size):return NonepCurrent &#61; self.headfor i in range(1,pos&#43;1):pCurrent &#61; pCurrent.nextreturn pCurrent.data# 按值查找def Find_LinkList(self,data):if(data &#61;&#61; None):return -1pCurrent &#61; self.headfor i in range(1,self.size &#43; 1):pCurrent &#61; pCurrent.nextif(pCurrent.data &#61;&#61; data):return ireturn 0# 删除指定位置的值def RemoveByPos_LinkList(self,pos):if(pos <1 or pos > self.size):return NonepCurrent &#61; self.headfor i in range(1,pos):pCurrent &#61; pCurrent.nextsaveNode &#61; pCurrent.nextpCurrent.next &#61; saveNode.nextsaveNode.next &#61; Noneself.size -&#61; 1# 获得链表的长度def Size_LinkList(self):if(self &#61;&#61; None):return -1return self.size# 释放链表内存def FreeSpace_LinkList(self):self.head &#61; Noneself.size &#61; 0# 打印def Print_LinkList(self):pCurrent &#61; self.headfor i in range(1,self.size &#43; 1):pCurrent &#61; pCurrent.nextp &#61; pCurrent.datap.toString()
from MyLinkList import *list &#61; LinkList()
list.Init_LinkList();# 创建数据
p1 &#61; Person("aaa", 23, 80)
p2 &#61; Person("bbb", 24, 81)
p3 &#61; Person("ccc", 25, 82)
p4 &#61; Person("ddd", 26, 83)
p5 &#61; Person("eee", 27, 84)# 插入数据
list.Insert_LinkList(1, p1)
list.Insert_LinkList(2, p2)
list.Insert_LinkList(3, p3)
list.Insert_LinkList(4, p4)
list.Insert_LinkList(5, p5)# 打印
list.Print_LinkList()
print(list.Size_LinkList())
print(list.getElem(3))
print(list.Find_LinkList(p4))
print("&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;")
list.RemoveByPos_LinkList(2)
list.Print_LinkList()list.FreeSpace_LinkList()
name: aaa &#xff0c;age: 23 &#xff0c;score: 80
name: bbb &#xff0c;age: 24 &#xff0c;score: 81
name: ccc &#xff0c;age: 25 &#xff0c;score: 82
name: ddd &#xff0c;age: 26 &#xff0c;score: 83
name: eee &#xff0c;age: 27 &#xff0c;score: 84
5
4
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
name: aaa &#xff0c;age: 23 &#xff0c;score: 80
name: ccc &#xff0c;age: 25 &#xff0c;score: 82
name: ddd &#xff0c;age: 26 &#xff0c;score: 83
name: eee &#xff0c;age: 27 &#xff0c;score: 84Process finished with exit code 0