一:结点的定义:
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode {//定义一个结点结构
ElemType data;//数据域
struct LNode* next;//指针域,next是下一个结点的地址
}LNode,*LinkList;
(1)注意: LNode *相当于LinkList
(2)搞清楚带头结点和不带头结点的区别(下面按顺序分别是带头结点链表,不带头结点单链表)
二:单链表的初始化(带头结点)
bool HaveHead_InitList(LinkList& L) {
L = (LNode*)malloc(sizeof(LNode));//创建一个头结点,并为该头结点开辟一个结点所需要的空间(所以后面要是要加新结点,则需要另辟结点空间)
if (L == NULL) return false;//即:如果空间分配失败
L->next = NULL;
return true;
}
三:单链表的初始化(不带头结点)
bool NoHead_InitList(LinkList& L) {
L== NULL;//即空表,需要特别初始化为空 是因为:防止L在没有赋值的情况下携带脏数据而影响后序操作
return true;
}
四:判空(带头结点)
bool HaveHead_Empty(LinkList L) {
if (L->next == NULL) //不带头结点则是 if(L==NULL) return true; else return false;
return true;
else return false;
}
五:判空(不带头结点)
bool HaveHead_Empty(LinkList L) {
if(L==NULL) return true;
else return false;
}
六:建单链表----头插法(带头结点)
//建单链表----头插法(逆向建立单链表)(带头结点)
LinkList Havehead_List_HeadInsert(LinkList& L) {
L = (LinkList)malloc(sizeof(LNode)); //建立头结点
L->next = NULL; //初始尾空链表 (必须初始化)
LNode* s;
int x;
scanf("%d", &x);
while (x != -1) {
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s; //即头结点指向新的结点
scanf("%d", &x);
}
return L;
}
七:建单链表----头插法(不带头结点)
//建单链表----头插法(逆向建立单链表)(不带头结点)
LinkList Nohead_List_HeadInsert(LinkList& L){
LNode* s; //声明一个临时结点
int x;
L = NULL;
scanf("%d", &x); //输入结点的值
while (x != -1){
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x;
if (L == NULL) { // 若第一次创建节点,则将该点设置为头结点
L = s;
s->next = NULL;
}else { // 若不是第一次创建节点,则直接将新节点接到链表头
s->next = L;
L = s;
}
scanf("%d", &x);
}
return L;
}
八:建单链表----尾插法(带头结点)
//建单链表----尾插法(正向建立单链表)(带头结点)
LinkList Havehead_List_TailInsert1(LinkList &L){ //采用带有头结点的尾插法正向建立单链表
int x;
L = (LinkList)malloc(sizeof(LNode)); //创建头结点
LNode* s;
LNode *r=L; //s为临时结点,r为表尾指针
scanf("%d", &x); //输入结点的值
while (x != -1){
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x;
r->next = s;
r = s; //r指向新的表尾结点
scanf("%d", &x);
}
r->next = NULL; //尾结点指针置空
return L;
}
九:建单链表----尾插法(不带头结点)
//建单链表----尾插法(正向建立单链表)(不带头结点)
LinkList Nohead_List_TailInsert(LinkList& L) //采用不带有头结点的尾插法正向建立单链表
{
int x;
LNode* s;
LNode* r = L=NULL; //s为临时结点,r为表尾指针
scanf("%d", &x); //输入结点的值
while (x != -1) {
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x;
if (L == NULL){ // 创建链表的第一个节点
L = s;
r = s;
s->next = NULL;
} else {
r->next = s;
r = s;
}
scanf("%d", &x);
}
r->next = NULL; //尾结点指针为空
return L;
}
十:按位查找,返回第i位的地址(带头结点)
//按位查找,返回第i位的地址(带头结点)
LNode* Head_GetElem(LinkList L, int i) {
if (i < 1) return NULL; //位置是第负数个的结点不存在
LNode* p = L->next; //因为头结点不保存数据,数据从头结点的下一个结点才开始保存
int j = 0;//因为指针的值的是下一个结点的地址,所以注意这里不是int j=1;
while (p != NULL && j < i) {//即当j=i的时候跳出循环
p = p->next;
j++;
}
return p;
}
十一:按位查找,返回第i位的地址(不带头结点)
//按位查找(不带头结点),返回第i位的地址
LNode* NoHead_GetElem(LinkList L, int i) {
if (L == NULL || i <= 0) {
return NULL;
}
LNode* p = L;
int j = 0;//因为指针的值的是下一个结点的地址,所以注意这里不是int j=1;
while (p != NULL && j < i) {
p = p->next;
j++;
}
return p;
}
十二:按位序插入(带头结点)
//按位序插入(带头结点)
bool Havehead_ListInsert(LinkList& L, int i, ElemType e) {//即插入在第几个,插入的元素是i
if (i < 1) return false;
/*如果是不带头结点的话,,则如果删除或插在第一个位置(这里是插入的情况下),需要更改头指针L,即加上下面的判断
if (i==1){
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = L;
L= s;
return true;
}
*/
LNode* p = L;
int j = 0;//表示当前p指向的是第几个结点,如果是不带头结点的话,则是 int j=1;
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
}
十三:按位序插入(不带头结点)
//按位序插入(不带头结点)
//即插入在第几个,插入的元素是i
bool Nohead_ListInsert(LinkList & L, int i, ElemType e) {
if (i < 1) return false;
if (i == 1) {
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = L;
L = s;
return true;
}
LNode* p = L;
int j = 1;
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
}
十四:按位序删除(带头结点)
//按位序删除(带头结点)
bool HaveHead_ListDelete(LinkList& L, int i) {
if (i < 1) return false;
LNode* p; //指针p指向当前扫描到的节点
p = L; //令L指向头节点,头节点是第0个节点(不存数据)
int j = 0; // 当前p指向的是第几个节点
while (p != NULL && j < i - 1) { //循环到第i-1个节点
p = p->next;
j++;
}
if (p == NULL) return false; //前面和插入操作差不多
if (p->next == NULL) return false; //第i-1个节点之后没有其他节点
LNode* q = p->next; //q指向被删除的节点
p->next = q->next;
free(q);
return true;
}
十五:按位序删除(不带头结点)
//按位序删除(不带头结点)
bool NoHead_ListDelete(LinkList& L, int i) {
if (i < 1) {
return false;
}
if (i == 1) {
LNode* q = L; // 头指针L指向链表第一个结点,声明一个指针变量q用来存储链表的第一个结点
L = q->next; //让头指针L指向链表的第二个结点
free(q); // 释放q结点,头指针L又指向原链表的第二个结点,那么就表示q结点被删了
}
LNode* p=L;
int j = 0;
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
if (p = NULL) {
return false;
}
LNode* q = p->next;
p->next = q->next;
free(q);
return true;
}
十六:求表长
int Length(LinkList L) {//不带头结点的单链表操作中, //除了初始化InitList(),判空isEmpty(),按位查找GetElem(),插入ListInsert(),删除ListDelete()操作与带头结点的单链表有差别外,其它的操作基本上一样。
int len = 0;
LNode* p = L;//定义一个结点指向第一个结点
while (p->next != NULL) {
p = p->next;
len++;
}
return len;
}
十七:基本测试代码
int main() {
LinkList L;
printf("下面先展示带头结点的单链表基本操作测试");
printf("利用头插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
L = Havehead_List_HeadInsert(L);
HaveHead_PrintList(L);
printf("利用尾插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
L = Havehead_List_TailInsert1(L);
HaveHead_PrintList(L);
printf("在第1个位置插入元素11后:\n");
Havehead_ListInsert(L, 1, 11);
HaveHead_PrintList(L);
printf("删除第一个元素后:\n");
HaveHead_ListDelete(L, 1);
HaveHead_PrintList(L);
printf("查找第一个元素:\n");
Head_GetElem(L, 1);
HaveHead_PrintList(L);
int len = Length(L);
printf("表长 = %d\n",len);
printf("\n***************************************************************************************************************************\n");
printf("下面展示不带头结点的单链表基本操作测试");
printf("利用头插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
L = Nohead_List_HeadInsert(L);
NoHead_PrintList(L);
printf("利用尾插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
L = Nohead_List_TailInsert(L);
NoHead_PrintList(L);
printf("在第1个位置插入元素11后:\n");
Nohead_ListInsert(L, 1, 11);
NoHead_PrintList(L);
printf("删除第一个元素后:\n");
NoHead_ListDelete(L, 1);
NoHead_PrintList(L);
printf("查找第一个元素:\n");
NoHead_GetElem(L, 1);
NoHead_PrintList(L);
return 0;
}
十八:运行截图
十九:完整代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode {//定义一个结点结构
ElemType data;//数据域
struct LNode* next;//指针域,next是下一个结点的地址
}LNode,*LinkList;
//初始化(带头结点)
bool HaveHead_InitList(LinkList& L) {
L = (LNode*)malloc(sizeof(LNode));//创建一个头结点,并为该头结点开辟一个结点所需要的空间(所以后面要是要加新结点,则需要另辟结点空间)
if (L == NULL) return false;//即:如果空间分配失败
L->next = NULL;
return true;
}
//初始化(不带头结点)
bool NoHead_InitList(LinkList& L) {
L== NULL;//即空表,需要特别初始化为空 是因为:防止L在没有赋值的情况下携带脏数据而影响后序操作
return true;
}
//判空(带头结点)
bool HaveHead_Empty(LinkList L) {
if (L->next == NULL) //不带头结点则是 if(L==NULL) return true; else return false;
return true;
else return false;
}
//建单链表----头插法(逆向建立单链表)(带头结点)
LinkList Havehead_List_HeadInsert(LinkList& L) {
L = (LinkList)malloc(sizeof(LNode)); //建立头结点
L->next = NULL; //初始尾空链表 (必须初始化)
LNode* s;
int x;
scanf("%d", &x);
while (x != -1) {
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s; //即头结点指向新的结点
scanf("%d", &x);
}
return L;
}
//建单链表----头插法(逆向建立单链表)(不带头结点)
LinkList Nohead_List_HeadInsert(LinkList& L){
LNode* s; //声明一个临时结点
int x;
L = NULL;
scanf("%d", &x); //输入结点的值
while (x != -1){
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x;
if (L == NULL) { // 若第一次创建节点,则将该点设置为头结点
L = s;
s->next = NULL;
}else { // 若不是第一次创建节点,则直接将新节点接到链表头
s->next = L;
L = s;
}
scanf("%d", &x);
}
return L;
}
//建单链表----尾插法(正向建立单链表)(带头结点)
LinkList Havehead_List_TailInsert1(LinkList &L){ //采用带有头结点的尾插法正向建立单链表
int x;
L = (LinkList)malloc(sizeof(LNode)); //创建头结点
LNode* s;
LNode *r=L; //s为临时结点,r为表尾指针
scanf("%d", &x); //输入结点的值
while (x != -1){
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x;
r->next = s;
r = s; //r指向新的表尾结点
scanf("%d", &x);
}
r->next = NULL; //尾结点指针置空
return L;
}
//建单链表----尾插法(正向建立单链表)(不带头结点)
LinkList Nohead_List_TailInsert(LinkList& L) //采用不带有头结点的尾插法正向建立单链表
{
int x;
LNode* s;
LNode* r = L=NULL; //s为临时结点,r为表尾指针
scanf("%d", &x); //输入结点的值
while (x != -1) {
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x;
if (L == NULL){ // 创建链表的第一个节点
L = s;
r = s;
s->next = NULL;
} else {
r->next = s;
r = s;
}
scanf("%d", &x);
}
r->next = NULL; //尾结点指针为空
return L;
}
//按位查找,返回第i位的地址(带头结点)
LNode* Head_GetElem(LinkList L, int i) {
if (i < 1) return NULL; //位置是第负数个的结点不存在
LNode* p = L->next; //因为头结点不保存数据,数据从头结点的下一个结点才开始保存
int j = 0;//因为指针的值的是下一个结点的地址,所以注意这里不是int j=1;
while (p != NULL && j < i) {//即当j=i的时候跳出循环
p = p->next;
j++;
}
return p;
}
//按位查找(不带头结点),返回第i位的地址
LNode* NoHead_GetElem(LinkList L, int i) {
if (L == NULL || i <= 0) {
return NULL;
}
LNode* p = L;
int j = 0;//因为指针的值的是下一个结点的地址,所以注意这里不是int j=1;
while (p != NULL && j < i) {
p = p->next;
j++;
}
return p;
}
//按位序插入(带头结点)
bool Havehead_ListInsert(LinkList& L, int i, ElemType e) {//即插入在第几个,插入的元素是i
if (i < 1) return false;
/*如果是不带头结点的话,,则如果删除或插在第一个位置(这里是插入的情况下),需要更改头指针L,即加上下面的判断
if (i==1){
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = L;
L= s;
return true;
}
*/
LNode* p = L;
int j = 0;//表示当前p指向的是第几个结点,如果是不带头结点的话,则是 int j=1;
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
}
//按位序插入(不带头结点)
//即插入在第几个,插入的元素是i
bool Nohead_ListInsert(LinkList & L, int i, ElemType e) {
if (i < 1) return false;
if (i == 1) {
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = L;
L = s;
return true;
}
LNode* p = L;
int j = 1;
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
}
//按位序删除(带头结点)
bool HaveHead_ListDelete(LinkList& L, int i) {
if (i < 1) return false;
LNode* p; //指针p指向当前扫描到的节点
p = L; //令L指向头节点,头节点是第0个节点(不存数据)
int j = 0; // 当前p指向的是第几个节点
while (p != NULL && j < i - 1) { //循环到第i-1个节点
p = p->next;
j++;
}
if (p == NULL) return false; //前面和插入操作差不多
if (p->next == NULL) return false; //第i-1个节点之后没有其他节点
LNode* q = p->next; //q指向被删除的节点
p->next = q->next;
free(q);
return true;
}
//按位序删除(不带头结点)
bool NoHead_ListDelete(LinkList& L, int i) {
if (i < 1) {
return false;
}
if (i == 1) {
LNode* q = L; // 头指针L指向链表第一个结点,声明一个指针变量q用来存储链表的第一个结点
L = q->next; //让头指针L指向链表的第二个结点
free(q); // 释放q结点,头指针L又指向原链表的第二个结点,那么就表示q结点被删了
}
LNode* p=L;
int j = 0;
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
if (p = NULL) {
return false;
}
LNode* q = p->next;
p->next = q->next;
free(q);
return true;
}
//求表长
int Length(LinkList L) {//不带头结点的单链表操作中, //除了初始化InitList(),判空isEmpty(),按位查找GetElem(),插入ListInsert(),删除ListDelete()操作与带头结点的单链表有差别外,其它的操作基本上一样。
int len = 0;
LNode* p = L;//定义一个结点指向第一个结点
while (p->next != NULL) {
p = p->next;
len++;
}
return len;
}
//带头结点的打印
void HaveHead_PrintList(LinkList L)
{
LinkList p;
p = L->next;
printf("链表元素如下:\n");
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
//不带头结点的打印
void NoHead_PrintList(LinkList L)
{
LinkList p;
p = L;
printf("链表元素如下:\n");
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main() {
LinkList L;
printf("下面先展示带头结点的单链表基本操作测试");
printf("利用头插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
L = Havehead_List_HeadInsert(L);
HaveHead_PrintList(L);
printf("利用尾插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
L = Havehead_List_TailInsert1(L);
HaveHead_PrintList(L);
printf("在第1个位置插入元素11后:\n");
Havehead_ListInsert(L, 1, 11);
HaveHead_PrintList(L);
printf("删除第一个元素后:\n");
HaveHead_ListDelete(L, 1);
HaveHead_PrintList(L);
printf("查找第一个元素:\n");
Head_GetElem(L, 1);
HaveHead_PrintList(L);
int len = Length(L);
printf("表长 = %d\n",len);
printf("\n***************************************************************************************************************************\n");
printf("下面展示不带头结点的单链表基本操作测试");
printf("利用头插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
L = Nohead_List_HeadInsert(L);
NoHead_PrintList(L);
printf("利用尾插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
L = Nohead_List_TailInsert(L);
NoHead_PrintList(L);
printf("在第1个位置插入元素11后:\n");
Nohead_ListInsert(L, 1, 11);
NoHead_PrintList(L);
printf("删除第一个元素后:\n");
NoHead_ListDelete(L, 1);
NoHead_PrintList(L);
printf("查找第一个元素:\n");
NoHead_GetElem(L, 1);
NoHead_PrintList(L);
return 0;
}