定义
线性表的链式存储又称单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表节点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。
单链表的优缺点
优点 :
1、增加、删除元素方便,不用大量移动元素
2、不需要空间提前开辟,易扩充
缺点 :
1、不支持随机存储
2、开辟了指针域,会浪费额外的空间
单链表的初始化
LinkList InitList(){ //初始化
LinkList L = (LinkList)malloc(sizeof(LNode)); //C开辟动态内存
//L = new (LNode); //C++开辟动态内存
if (L == NULL){
return NULL; //内存不足,分配失败
}
L->next = NULL; //将L的指针域设为空
return L;
}
单链表的头插法的构建
优点:可用于链表的逆置
LinkList List_Front_Insert(LinkList L){ //初始化头插
printf("请输入数据(-1结束):"); //连续输入数据,-1结束
int n;
LNode* newNode; //新节点
scanf("%d", &n);
while (n != -1){
newNode = (LNode*)malloc(sizeof(LNode)); //为新节点开辟空间
newNode->data = n;
newNode->next = L->next;
L->next = newNode;
scanf("%d", &n);
}
return L;
}
单链表的尾插法的构建
LinkList List_Tail_Insert(LinkList L){ //初始化尾插
printf("请输入数据(-1结束):");
int n;
LNode* newNode; //新节点
LNode* tail = L; //尾结点
scanf("%d", &n);
while ( n!=-1 ){
newNode = (LNode*)malloc(sizeof(LNode)); //为新节点开辟空间
newNode->data = n;
tail->next = newNode;
tail = newNode;
scanf("%d", &n);
}
tail->next = NULL; //尾结点指向空,很重要
return L;
}
单链表的查找操作
从单链表的第一个结点开始,由前往后依次比较表中各节点数据域的值,若某结点数据域的值等于给定值elem,则返回该节点的指针;否则该链表中没有该元素,返回NULL。
LNode* LocatElem(LinkList L, ElemType elem){ //查找
LNode* p = L->next;
while (p != NULL && p->data != elem){
p = p->next;
}
return p; //返回该结点
}
单链表的插入操作
LinkList ListInsert(LinkList L, int index, ElemType elem){ //插入
LNode* newNode = (LNode*)malloc(sizeof(LNode));
newNode->data = elem; //待插入的结点
if (index == 1){ //类似头插
newNode->next = L->next;
L->next = newNode;
return L;
}
LNode* p = getElem(L, index - 1); //找到待插入位置的前一个结点
newNode->next = p->next;
p->next = newNode;
return L;
}
单链表的删除操作
LinkList ListDelete(LinkList L, int index){ //删除
//方法一:通过获取index前面一个元素的结点,指向index后面一个元素的结点
//方法二:
LNode* front = L->next; //当前结点的前一个
LNode* cur = NULL; //当前结点
if (index == 1){ //删除第一个结点
L->next = front->next;
free(front);
return L;
}
while (index > 2){ //遍历寻找当前结点的前一个结点
front = front->next;
index--;
}
cur = front->next;
front->next = cur->next;
free(cur); //释放被删除结点的空间
return L;
}
单链表的销毁操作
LinkList ListDestory(LinkList L){
L->next = NULL; //将头节点的next置空
free(L); //释放头节点的空间
return L;
}
单链表的输出操作
void printList(LinkList L){ //输出
LNode* p = L->next;
while (p != NULL){
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
单链表的取值操作
在单链表中从第一个结点出发,顺指针的next域逐个往下搜索,直到找到第index个结点位置,否在返回最后一个指针的域NULL。
LNode* getElem(LinkList L, int index){//取值
LNode* p = L->next;
int i = 1;
if (index == 0) { //返回头节点
return L;
}
if (index < 0){ //index不合法
return NULL;
}
while (i < index && p){ //i小于index,且p不为空
p = p->next;
i++;
}
return p;
}
源码
Linklist.h
#include <stdio.h>
#include <windows.h>
#include <malloc.h>
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode* next;
}LNode, *LinkList;
void menu(); //菜单
LinkList InitList(); //初始化
void printList(LinkList L); //输出
LNode* getElem(LinkList L, int index); //取值
LNode* LocatElem(LinkList L, ElemType elem); //查找
LinkList ListInsert(LinkList L, int index, ElemType elem); //插入
LinkList ListDelete(LinkList L, int index); //删除
LinkList ListDestory(LinkList L); //销毁
LinkList List_Tail_Insert(LinkList L); //尾插
LinkList List_Front_Insert(LinkList L);//头插
Linklist.c
#include "Linklist.h"
void menu(){
printf("< G取值 P打印 L查找 I插入 D删除 X销毁 Q退出 >\n");
printf("请选择您的操作:");
}
LinkList InitList(){ //初始化
LinkList L = (LinkList)malloc(sizeof(LNode)); //C开辟动态内存
//L = new (LNode); //C++开辟动态内存
if (L == NULL){
return NULL; //内存不足,分配失败
}
L->next = NULL; //将L的指针域设为空
return L;
}
LNode* getElem(LinkList L, int index){//取值
LNode* p = L->next;
int i = 1;
if (index == 0) { //返回头节点
return L;
}
if (index < 0){ //index不合法
return NULL;
}
while (i < index && p){ //i小于index,且p不为空
p = p->next;
i++;
}
return p;
}
void printList(LinkList L){ //输出
LNode* p = L->next;
while (p != NULL){
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
LNode* LocatElem(LinkList L, ElemType elem){ //查找
LNode* p = L->next;
while (p != NULL && p->data != elem){
p = p->next;
}
return p; //返回该结点
}
LinkList ListInsert(LinkList L, int index, ElemType elem){ //插入
LNode* newNode = (LNode*)malloc(sizeof(LNode));
newNode->data = elem; //待插入的结点
if (index == 1){ //类似头插
newNode->next = L->next;
L->next = newNode;
return L;
}
LNode* p = getElem(L, index - 1); //找到待插入位置的前一个结点
newNode->next = p->next;
p->next = newNode;
return L;
}
LinkList ListDelete(LinkList L, int index){ //删除
//方法一:通过获取index前面一个元素的结点,指向index后面一个元素的结点
//方法二:
LNode* front = L->next; //当前结点的前一个
LNode* cur = NULL; //当前结点
if (index == 1){
L->next = front->next;
free(front);
return L;
}
while (index > 2){ //遍历寻找当前结点的前一个结点
front = front->next;
index--;
}
cur = front->next;
front->next = cur->next;
free(cur);
return L;
}
LinkList ListDestory(LinkList L){
L->next = NULL;
free(L);
return L;
}
LinkList List_Front_Insert(LinkList L){ //初始化头插
printf("请输入数据(-1结束):");
int n;
LNode* newNode; //新节点
scanf("%d", &n);
while (n != -1){
newNode = (LNode*)malloc(sizeof(LNode));
newNode->data = n;
newNode->next = L->next;
L->next = newNode;
scanf("%d", &n);
}
return L;
}
LinkList List_Tail_Insert(LinkList L){ //初始化尾插
printf("请输入数据(-1结束):");
int n;
LNode* newNode; //新节点
LNode* tail = L; //尾结点
scanf("%d", &n);
while ( n!=-1 ){
newNode = (LNode*)malloc(sizeof(LNode));
newNode->data = n;
tail->next = newNode;
tail = newNode;
scanf("%d", &n);
}
tail->next = NULL;
return L;
}
test.c
#include "Linklist.h"
int main(){
LinkList L = InitList(); // 初始化
L = List_Tail_Insert(L); //数据尾插
//L = List_Front_Insert(L); //数据头插
while (1){
menu();
char key;
int n = 0;
int index = 0;
LNode* p = NULL;
getchar(); //释放scanf读取的\n
scanf("%c", &key);
switch(key){
case 'G':
printf("要查找第几个元素:");
scanf("%d", &n);
p = getElem(L, n);
if (p != NULL){
printf("%d\n", p->data);
}
else{
printf("输入有误!\n");
}
break;
case 'P':
printList(L);
break;
case 'L':
printf("要查找的元素:");
scanf("%d", &n);
p = LocatElem(L, n);
if (p != NULL){
printf("找到了该元素:%d\n", p->data);
}
else{
printf("没有该元素\n");
}
break;
case 'I':
printf("请输入插入的下标和数:");
scanf("%d %d", &index, &n);
L = ListInsert(L, index, n);
printf("插入成功!\n");
break;
case 'D':
printf("要删除第几个元素:");
scanf("%d", &n);
p = ListDelete(L, n);
if (p != NULL){
printf("删除成功!\n");
}
else{
printf("删除失败!\n");
}
break;
case 'X':
L = ListDestory(L);
if (L == NULL){
printf("链表已经销毁!\n");
}
else{
printf("链表销毁失败!\n");
}
break;
case 'Q':
printf("退出成功!");
exit(0);
}
}
system("pause");
}