单链表
n个结点链结成一个链表。每个结点由数据域和指针域两部分组成,单链表是只含一个指针域的链表。
特点:顺序存储
基本操作的实现
单链表的初始化:
构造一个如图的空表
(1)生成新节点作为头节点,用头指针L指向头节点;
(2)头节点的指针域置空。
LinkList initLinkList() {
NodePtr tempHeader = (NodePtr)malloc (sizeof(LNode));
tempHeader->data = '\0';
tempHeader->next = NULL;//将tempHeader的next域置空,赋一个空值
return tempHeader;
}
判断链表是否为空:
思路:判断头节点指针域是否为空
空表:链表中无元素,称为空链表(头指针和头结点仍然存在)
void ListEmpty(NodePtr paraHeader) {
if(paraHeader->next)
printf("The list is not empty.\n");
else
printf("The list is empty.\n");
}
单链表的销毁:
思路:从头指针开始,依次释放所有节点(销毁后链表不存在)
LinkList DestroyList(NodePtr paraHeader) {
NodePtr p;
while(paraHeader != NULL) {
p = paraHeader;
paraHeader = paraHeader->next;
free(p);
}
}
清空链表:
链表仍存在 ,但链表中无元素,成为空链表(头指针和头结点仍存在)
思路:依次释放所有节点,并将指针域设置为空
LinkList ClearList(NodePtr paraHeader) {
NodePtr p, q;
p = paraHeader->next;
while(p!=NULL) {
q = q->next;
free(p);
p = q;
}
paraHeader->next = NULL;//头节点指针域为空
}
求单链表的表长:
思路:从首元节点开始,依次计数所有结点
void lengthList(NodePtr paraHeader) {
NodePtr p = paraHeader->next;//p指向第一个节点
int i = 0;
while (p != NULL) {
i ++;
p = p->next;//p指向下一节点
}
printf("The length of list is:%d\r\n",i);
}
单链表的取值:
1.从第一个节点(L->next)顺链扫描,用指针p指向当前扫描到的节点,p初值p = L->next
2.j做计数器,累计当前扫描过的节点数,j初值为1
3.当p指向扫描到的下一节点时,计数器j加1
4.当j == i时,p所指的节点就是要找的第i个节点
LinkList GetElemList(NodePtr paraHeader, int i, char e) {
//获取线性表中某个元素,通过变量e返回
NodePtr p = paraHeader->next;//初始化,p指向首元节点,j赋值1
int j = 1;
while(p&&j<i) {//向后扫描,直到p指向地i个元素或p为空
p = p->next;
j ++;
}
if(!p||j>i)
printf("第%d个元素不存在\n", i); //第i个元素不存在
else
e = p->data;//取第i个元素
printf("第%d个元素:%c\n", i, e);
}
单链表的查找:
按值查找——根据指定数据获取该数据所在位置(地址)
1.从第一个节点起,依次和e相比较
2.如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”或地址
3.如果查遍整个链表都没有找到其值和e相等的元素,则输出"ERROR"
void LocateELemList(NodePtr paraHeader, char paraChar) {
NodePtr p = paraHeader->next;
int j = 1;
while(p&&p->data!=paraChar) {
p = p->next;
j ++;
}
if(p)
printf("%c的位置序号为:%d\n", paraChar, j);
else
printf("ERROR\n");
}
打印链表:
void printList(NodePtr paraHeader) {//NodePtr--指针类型,定义头指针paraHeader,因此paraHeader前不需要加*
NodePtr p = paraHeader->next;//p指向首元节点
while (p != NULL) {
printf("%c",p->data);
p = p->next;//p指向下一节点
}
printf("\r\n");
}
头插法:
1.从一个空表开始,重复读入数据
2.生成新节点,将读入数据存放到新节点的数据域中
3.从最后一个节点开始,依次将各节点插入到链表的前端
void Createalist(NodePtr tempHeader, int n) {
tempHeader = (NodePtr)malloc (sizeof(LNode));
tempHeader->next = NULL;
for(int i = 0; i < n; i ++) {
NodePtr p = (NodePtr)malloc (sizeof(LNode));
scanf("%c", &p->data);
p->next = tempHeader->next;
tempHeader->next = p;
}
}
尾插法:
void appendElement(NodePtr paraHeader, char paraChar) {
NodePtr p, q;
q = (NodePtr)malloc(sizeof(LNode));
q->data = paraChar;//将节点*q的数据域置为paraChar
q->next = NULL;//将p的next域置空,赋一个空值
p = paraHeader;//p指向头节点
while(p->next != NULL) {
p = p->next;//p指向下一节点
}
p->next = q;//将节点*p的指针域指向节点*q
}
给定位置插入元素:
void insertElement(NodePtr paraHeader, char paraChar, int paraPosition) {
//paraChar给定字符 paraPosition给定位置
NodePtr p, q;
p = paraHeader;
for(int i = 0; i < paraPosition; i ++) {
p = p->next;
if(p == NULL) {
printf("The position %d is beyond the scope of the list.",paraPosition);
return;
}
}
q = (NodePtr)malloc(sizeof(LNode));
q->data = paraChar;
printf("linking\r\n");
q->next = p->next;//将节点*q的指针域指向第i个节点
p->next = q;
}
从列表中删除元素:
void deleteElement(NodePtr paraHeader, char paraChar) {
NodePtr p, q;
p = paraHeader;
while((p->next != NULL) && (p->next->data != paraChar)) {
p = p->next;
}
if(p->next == NULL) {
printf("Cannot dalete %c\r\n", paraChar);
return;
}
q = p->next;
p->next = p->next->next;
free(q);//释放删除节点的空间
}
总代码:
#include<stdio.h>
#include<malloc.h>
//typedef重命名结构类型为LNode
typedef struct LinkNode {//声明结点的类型和指向节点的指针类型
char data;//节点的数据域
struct LinkNode *next;//节点的指针域
} LNode, *LinkList, *NodePtr;//节点,链表指针,节点指针 LinkList为指向结构体Lnode的指针类型
//单链表的初始化
LinkList initLinkList() {
NodePtr tempHeader = (NodePtr)malloc (sizeof(LNode));
tempHeader->data = '\0';
tempHeader->next = NULL;//将tempHeader的next域置空,赋一个空值
return tempHeader;
}
//判断链表是否为空
void ListEmpty(NodePtr paraHeader) {
if(paraHeader->next)
printf("The list is not empty\n");
else
printf("The list is empty\n");
}
//单链表的销毁
LinkList DestroyList(NodePtr paraHeader) {
NodePtr p;
while(paraHeader != NULL) {
p = paraHeader;
paraHeader = paraHeader->next;
free(p);
}
}
//清空链表
LinkList ClearList(NodePtr paraHeader) {
NodePtr p, q;
p = paraHeader->next;
while(p!=NULL) {
q = q->next;
free(p);
p = q;
}
paraHeader->next = NULL;//头节点指针域为空
}
//求单链表的表长
void lengthList(NodePtr paraHeader) {
NodePtr p = paraHeader->next;
int i = 0;
while (p != NULL) {
i ++;
p = p->next;//p指向下一节点
}
printf("The length of list is:%d\r\n",i);
}
//单链表的取值
LinkList GetElemList(NodePtr paraHeader, int i, char e) {
//获取线性表中某个元素,通过变量e返回
NodePtr p = paraHeader->next;//初始化,p指向首元节点,j赋值1
int j = 1;
while(p&&j<i) {//向后扫描,直到p指向地i个元素或p为空
p = p->next;
j ++;
}
if(!p||j>i)
printf("第%d个元素不存在\n", i); //第i个元素不存在
else
e = p->data;//取第i个元素
printf("第%d个元素:%c\n", i, e);
}
//单链表的查找
void LocateELemList(NodePtr paraHeader, char paraChar) {
NodePtr p = paraHeader->next;
int j = 1;
while(p&&p->data!=paraChar) {
p = p->next;
j ++;
}
if(p)
printf("%c的位置序号为:%d\n", paraChar, j);
else
printf("ERROR\n");
}
//打印链表
void printList(NodePtr paraHeader) {//NodePtr--指针类型,定义头指针paraHeader,因此paraHeader前不需要加*
NodePtr p = paraHeader->next;//p指向首元节点
while (p != NULL) {
printf("%c",p->data);
p = p->next;//p指向下一节点
}
printf("\r\n");
}
//头插法
void Createalist(NodePtr tempHeader, int n) {
tempHeader = (NodePtr)malloc (sizeof(LNode));
tempHeader->next = NULL;
for(int i = 0; i < n; i ++) {
NodePtr p = (NodePtr)malloc (sizeof(LNode));
scanf("%c", &p->data);
p->next = tempHeader->next;
tempHeader->next = p;
}
}
//尾插法
void appendElement(NodePtr paraHeader, char paraChar) {
NodePtr p, q;
q = (NodePtr)malloc(sizeof(LNode));
q->data = paraChar;//将节点*q的数据域置为paraChar
q->next = NULL;//将p的next域置空,赋一个空值
p = paraHeader;//p指向头节点
while(p->next != NULL) {
p = p->next;//p指向下一节点
}
p->next = q;//将节点*p的指针域指向节点*q
}
//给定位置插入元素
void insertElement(NodePtr paraHeader, char paraChar, int paraPosition) {
//paraChar给定字符 paraPosition给定位置
NodePtr p, q;
p = paraHeader;
for(int i = 0; i < paraPosition; i ++) {
p = p->next;
if(p == NULL) {
printf("The position %d is beyond the scope of the list.",paraPosition);
return;
}
}
q = (NodePtr)malloc(sizeof(LNode));
q->data = paraChar;
printf("linking\r\n");
q->next = p->next;//将节点*q的指针域指向第i个节点
p->next = q;
}
//从列表中删除元素
void deleteElement(NodePtr paraHeader, char paraChar) {
NodePtr p, q;
p = paraHeader;
while((p->next != NULL) && (p->next->data != paraChar)) {
p = p->next;
}
if(p->next == NULL) {
printf("Cannot dalete %c\r\n", paraChar);
return;
}
q = p->next;
p->next = p->next->next;
free(q);//释放删除节点的空间
}
void appendInsertDeleteTest() {
LinkList tempList = initLinkList();
printList(tempList);
ListEmpty(tempList);
lengthList(tempList);
ClearList(tempList);
appendElement(tempList,'H');
appendElement(tempList,'e');
appendElement(tempList,'l');
appendElement(tempList,'l');
appendElement(tempList,'o');
appendElement(tempList,'!');
printList(tempList);
deleteElement(tempList,'e');
deleteElement(tempList,'a');
deleteElement(tempList,'o');
printList(tempList);
LocateELemList(tempList,'H');
char e;
GetElemList(tempList, 4, e);
insertElement(tempList,'o',1);
printList(tempList);
}
void basicAddressTest() {
LNode tempNode1, tempNode2;
tempNode1.data = 4;
tempNode1.next = NULL;
tempNode2.data = 6;
tempNode2.next = NULL;
printf("The first node: %d, %d, %d\r\n",&tempNode1, &tempNode1.data, &tempNode1.next);
printf("The second node: %d, %d, %d\r\n",&tempNode2, &tempNode2.data, &tempNode2.next);
tempNode1.next = &tempNode2;
}
int main() {
appendInsertDeleteTest();
}
运行结果: