一、什么是链表
线性表的链式存储又称之为单链表,他是通过内存中任意一块区域来存储数据元素的,为了让每一块的元素建立逻辑关系,我们把每一块的数据存储单元分为两个部分,第一个部分为数据部分,第二个部分为指向下一个节点的指针,所以在插入和删除的时候,链表不需要对元素大量的进行移动,只需修改指针即可。
二、链表的特点
1.解决了顺序表在存储数据时需要大量连续的空间,属于非随机存储。
2.由于存在指针域,链表消耗的空间会比较大。
3.链表进行删除和插入时候时间复杂度为O(1),因为只需修改指针的指向而已。
4.查找时消耗比较大,需要从头开始遍历,时间复杂度为O(n)。
本人觉得顺序表和链表是一个互补的出现,往往某些场合需要两者结合才能完成。
三、单链表的头插法和尾插法
头插法时元素始终插入头节点后面,比如说插入的元素为1,2,3,4,5,所以在输出的时候为5,4,3,2,1
头插法代码如下
LinkList InsertHead(LinkList L) { //头插法 LinkNode *s; int n; scanf("%d", &n); while (n != -1) { //输入为-1时表示终止输入 s = (LinkNode*)malloc(sizeof(LinkNode)); s->data = n; s->next = L->next; L->next = s; scanf("%d", &n); } return L; }
尾插法在插入元素时候每次都在节点最后插入,所以元素的顺序不会变。
尾插法代码如下
LinkList InsertTail(LinkList L) { //尾插法 int n; LinkNode *s; LinkNode *end = L; //尾指针 scanf("%d", &n); while (n != -1) { //输入-1时退出 s = (LinkNode*)malloc(sizeof(LinkNode)); s->data = n; end->next = s; end = s; //end指向新的尾节点 scanf("%d", &n); } end->next = NULL; //尾节点指针置为空 return L; }
四、单链表的增、删、改、查操作
linkList.h头文件
#include<stdio.h> typedef int Status; /* Status是函数的类型,其值是函数结果状-1为出现错误1为正常态代码,如OK等 */ typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE 其中1为TRUE 0为FALSE */ typedef int ElemType; /*ElemType是数据的类型,我们这里用int类型表示*/ typedef struct { //定义单链表的节点类型 ElemType data; //数据 struct LinkNode *next; //指针域 }LinkNode, *LinkList; LinkList InitLinkList(LinkList L); //初始化单链表 int LengthLink(LinkList L);//返回单链表的长度 int LocateElemLink(LinkList L, ElemType e);//查找元素e在表中的位置 ElemType GetElemLink(LinkList L, int i);//获取表中第i个位置的元素,并返回 Status InsertLinkList(LinkList L, int i, ElemType e);//在表L中第i个位置插入元素e Status DeleteElemLink(LinkList L, int i, ElemType *e);//删除表中第i个元素,并用e返回其值 void PrintLinkList(LinkList L);//输出单链表的所有元素 Boolean IsEmptyLink(LinkList L);//判断单链表是否为空 Status DestroyLinkList(LinkList L);//销毁单链表,并释放所占用的空间
linkList.c函数文件
#include<stdio.h> #include"linkList.h" LinkList InitLinkList(LinkList L) { //初始化单链表 LinkNode *s; s = (LinkList)malloc(sizeof(LinkNode)); s->next = NULL; L = s; return L; } Status InsertLinkList(LinkList L, int i, ElemType e) { //在表L中第i个位置插入元素e,头插法 LinkList p = L; int j = 0; while (j < i-1) { p = p->next; j++; } LinkNode *newNode = (LinkNode*)malloc(sizeof(LinkNode)); newNode->data = e; newNode->next = p->next; //新节点指向原来位置节点的下一个 p->next = newNode; //原来位置节点指向新节点 return 1; } void PrintLinkList(LinkList L) { //输出单链表的所有元素 LinkList p = L; p = p->next; if (p == NULL) printf("链表为空"); else { while (p != NULL) { printf(" %d ", p->data); p = p->next; } } } int LengthLink(LinkList L) { //返回单链表的长度 int i = 0; LinkList p = L; p = p->next; while (p != NULL) { i++; p = p->next; } return i; } int LocateElemLink(LinkList L, ElemType e) { //查找元素e在表中的位置 LinkList p = L; int i = 0; while (p->next != NULL) { p = p->next; if (p->data == e) return i + 1; i++; } return -1; } ElemType GetElemLink(LinkList L, int i) { //获取表中第i个位置的元素,并返回 LinkList p = L; int j = 0; if (i <= 0 || i > LengthLink(L)) return NULL; while (p != NULL) { p = p->next; j++; if (j == i) return p->data; } } Status DeleteElemLink(LinkList L, int i, ElemType *e) { //删除表中第i个元素,并用e返回其值 LinkList p = L; LinkNode *n; ElemType *temp; int j = 0; if (i <= 0 || i > LengthLink(L)) return -1; while (p != NULL) { if (j == i-1) { n = p->next; p->next = n->next; *e = n->data; free(n); return 1; } p = p->next; j++; } return 1; } Boolean IsEmptyLink(LinkList L) { //判断单链表是否为空 if (L->next == NULL) return 1; else return 0; } Status DestroyLinkList(LinkList L) { //销毁单链表,并释放所占用的空间 L->next = NULL; free(L); return 1; }
main.c主函数文件
#include<stdio.h> #include"linkList.h" int main() { int i; int array[] = { 0,1,2,3,4,5 }; ElemType e; LinkList L = InitLinkList(&L); for (i = 1; i < 6; i++) { InsertLinkList(L, i, array[i]); } PrintLinkList(L); printf("\n"); printf("链表长度为%d\n",LengthLink(L)); printf("5在链表中第%d个位置\n", LocateElemLink(L, 5)); printf("第五个位置的元素为%d\n",GetElemLink(L, 5)); DeleteElemLink(L, 5, &e); printf("删除第二个元素,删除的元素为%d,打印删除之后的表\n",e); PrintLinkList(L); printf("\n"); if (IsEmptyLink(L) == 1) printf("此表为空\n"); else printf("此表不为空\n"); printf("销毁线性表"); if (DestroyLinkList(L) == 1) printf("销毁成功!\n"); else printf("销毁失败"); }