一,(1)有头结点用头插法创建单链表,输出后是倒序
//头插法建立单链表:读入数据的顺序和生成的链表中元素的顺序是相反的;郝斌老师的里面加入了一个新的结点pTail,pTail和L是一样的也是指向头结点,
/*pNew->data = val;
pTail->pNext = pNew;
pNew->pNext = NULL;
pTail = pNew;*/ //通过将pTail与pNew互换,这样就可以是pTail继续指向下一个新增结点,顺序是正序
LinkList List_HeadInsert(LinkList &L)
{
LNode *s;//强调这是一个指向结点的指针
int x;
L = (LinkList)malloc(sizeof(LNode));//创建一个头结点,动态分配内存,使得指针L指向这块区域也就是头结点
L->next = NULL;//初始为空链表
scanf("%d\n",&x);//输入结点的值
while(x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;//将输入的结点的值赋值给新创建的结点指s所值结点的数据域中
s->next = L->next;//s->next里存放的地址是L->next里的地址,就使得s所指结点指向了头指针所指的那个结点
L->next = s;//将L->next的地址改为s,这样就会使头结点指向s所指的那个结点
scanf("%d",&x);
}
return L;
}
(2)无头结点用头插法创建单链表
//头插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
printf("请输入链表的值\n");
int x;
scanf("%d",&x);
while(x != 9999)
{
LNode * s = (LNode *)malloc(sizeof(LNode));//动态分配空间,使s指向这片空间
s->data = x;//将定义的值赋值到这个结构体的数据域
s->next = L;//这样s指向的这个结点指向L指向的这个结点,因为头结点,所以最开始L指向的是NULL,s指向的这个结点指向NULL
L = s;//将s赋给L,这样L就指向了s指向的那个结点
scanf("%d",&x);
}
return L;
}
(2)有头结点尾插法创建单链表
//尾插法建立单链表:正序
//郝斌老师里的加入了len,这样就可以规定链表的长度,这样就不需要规定“x != 9999”,省得取值还有限制
LinkList List_TailInsert(LinkList &L)
{
int x; //设元素类型为整数型
L = (LinkList)malloc(sizeof(LNode));
LNode *r = L;//表尾指针,最开始使其也指向头指针
LNode *s;
scanf("%d",&x);
while(x != 9999)
{
s = (LNode *)malloc(sizeof(LNode));//动态分配空间,使s指向刚分配空间的结点
s->data = x;//将x的值赋值给s所指结点的数据域中
r->next = s;//将s所指结点的地址给头结点,这样头结点就指向了s所指向的那个结点
r = s;//在将s的地址赋给r,这样r也就指向了s所指的那个结点
scanf("%d",&x);
}
r->next = NULL;
return L;
}
无头结点用尾插法创建单链表
//用尾插法建立单链表
LinkList List_TailInsert(LinkList &L)
{
LNode *r;
r = L;
LNode *s;
int x;
scanf("%d",&x);
while(x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = NULL;//该处和 if else 我想了很久都想不出来,是从博主“夕演_hd99”里看的
if(L == NULL)
{
L = s;
r = s;
}//用这个if条件之后,就可以是L,r都是指向了最开始输入的结构体,这样就可以用r->next,就可以使结构体连接在一起形成链表,若是没有这一步,最开始直接使用r->next会错误,因为最开始r = NULL
else
{
r->next = s;
r = s;
}
scanf("%d",&x);
}
return L;
}
二,(1)有头结点按序号查找某一结点
//按序号查找结点
//时间复杂度为O(n)
LNode *GetElem(LinkList L, int i)//i为位序,是从1开始的
{
if(i<1)
return NULL;
int j = 1;
LNode *p = L->next;//第一个结点指针赋给p,表示p指向第一个结点
while(p != NULL && j<i)
{
p = p->next;
++j;
}
return p;
}
无头结点按序号查找表结点
//按位查找
LNode *GetElem(LinkList L, int i)
{
if(i<1)
return false;
else
{
LNode *p = L;
int j = 0;
while(p != NULL && j < i-2)//因为没有了头结点,所以L指向的就是首节点,因为i是位序是从1开始的,而链表是从0开始的,所以是i-2
{
p = p->next;
++j;
}
return p;
}
}
(2)有头结点按值查找表结点
//按值查找表结点
//时间复杂度为O(n)
LNode * LocateElem(LinkList L, int e)//e表示的是链表中的某一值
{
LNode *p = L->next;
while(p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
无头结点查找表结点
//按值查找
LNode *LocateElem(LinkList L, int e)
{
LNode *p = L;
while(p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
三,(1)时间复杂度位O(n) 有头结点插入某一结点
//插入结点操作
//时间复杂度为O(n)
bool ListInsert(LinkList L, int i,int e)
{
LNode *p = GetElem(L, i-1);
if(NULL == p)
return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
无头结点插入某一结点
//给定位置和值,插入某一结点
bool InsertList(LinkList L, int i, int e)
{
LNode *p = GetElem(L, i-1);
if(NULL == p)
return false;
LNode *q = (LNode*)malloc(sizeof(LNode));
q->data = e;
q->next = p->next;
p->next = q;
return true;
}
(2)扩展,时间复杂度为O(1),给定某一指针,然后进行插入
有头结点,后插操作
//后插操作:在p1结点之后插入元素e,因为没有循环,所以时间复杂度为O(1)
bool InsertNextNode(LNode *p,int e)
{
if(NULL == p)
return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->next = p->next;
p->next = s;
return true;
}
无头结点,后插操作
//给定某一结构体指针,进行后插操作
bool InsertNextNode(LNode *p, int e)
{
if(NULL == p)
return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
有头结点,前插操作
//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p, int e)
{
if(NULL == p)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if(NULL == s)
return false;
s->next = p->next;
p->next = s;//新结点s连接到p之后
s->data = p->data;//将p中的元素复制到s中
p->data = e;//p中元素被e覆盖
return true;
}
无头结点,前插操作
//给定一个结构体指针,进行前插操作
bool InserPriorNode(LNode* p, int e)
{
if(NULL == p)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = e;
return true;
}
四,删除操作
(1)时间复杂度O(n)
有头结点删除操作
bool ListDelete(LinkList &L, int i, int &e)
{
LNode *p = GetElem(L, i-1);
if(NULL == p)
return false;
if(NULL == p->next)//因为p是i的前一个结点,如果p->next == NULL,则说明位置i的结构体为NULL,这样就不要删除
return false;
LNode *q = p->next;
e = q->data;
p->next = q->next;
free(q);
return true;
}
无头结点删除操作
bool ListDelete(LinkList &L, int i, int &e)
{
LNode *p = GetElem(L, i-1);
if(NULL == p)
return false;
if(NULL == p->next)
return false;
LNode *q = p->next;
e = q->data;
p->next = p->next->next;
free(q);
return true;
}
(2)指定某一结点删除,时间复杂度O(1)
有头结点,删除指定的某一结点
//删除指定结点p,时间1复杂度O(1)
//如果p是指向链表最后一个结点,则此时就会出现错误,若是想删除指定p结点,则只能从表头往后寻找p的直接前驱
bool DeleteNode(LNode *p)
{
if(NULL == p)
return false;
LNode *q = p->next;
p->data = p->next->data;
p->next = q->next;
free(q);
return true;
}
无头结点删除指定的某一结点
//删除指定结点
bool DeleteNode(LNode *p)
{
if(NULL == p)
return false;
LNode *q = p->next;
p->data = q->data;
p->next = q->next;
return true;
}
五,计算链表的长度
(1)有头结点
//求表的长度
//时间复杂度为O(n)
int length(LinkList L)
{
int len = 0;//统计链表的长度
LNode *p = L;
while(p->next != NULL)
{
p = p->next;
len++;
}
return len;
}
(2)无头结点计算链表的长度
//链表的长度
int Length(LinkList L)
{
int len = 0;
LNode *p = L;
while(NULL != p)
{
len++;
p = p->next;
}
return len;
}
六,(1)有头结点遍历输出
//遍历输出
void PrintLinkList(LinkList L)
{
LinkList p = L->next;
while(NULL != p)
{
printf("%d\n",p->data);
p = p->next;
}
printf("\n");
return;
}
(2)无头结点遍历输出
void PrintList(LinkList L)
{
LinkList p = L;
while(NULL != p)
{
printf("%d\n",p->data);
p = p->next;
}
printf("\n");
return;
}
有头结点的全部代码
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct LNode//定义单链表结点类型
{
int data;//数据域:每个结点存放一个数据元素
struct LNode *next;//指针域:指针指向下一个节点;因为指针域要指向下一个结点,所以指针的类型肯定要和结点类型一致
}LNode, *LinkList;
//使用LinkList--强调这是一个单链表; 使用LNode* -- 强调这是一个结点
//函数说明
LinkList List_HeadInsert(LinkList &L);
LinkList List_TailInsert(LinkList &L);//必须得用&L,因为该函数是要对L进行更改的,所以得是L的地址,不然是无法更改的
void PrintLinkList(LinkList L);
LNode *GetElem(LinkList L, int i);
LNode * LocateElem(LinkList L, int e);
bool ListInsert(LinkList L, int i, int e);
int length(LinkList L);
bool ListDelete(LinkList &L, int i, int &e);
int main(void)
{
LinkList L = NULL;//强调这是一个头指针指向一个链表,先使其初始化,避免垃圾值
//L = List_HeadInsert(L);
printf("创造一个链表:\n");
L = List_TailInsert(L);
printf("链表的值为:\n");
PrintLinkList(L);
ListInsert(L, 3, 10);
printf("插入元素之后链表的值为:\n");
PrintLinkList(L);
int len = length(L);
printf("链表的长度为:%d\n",len);
int e;
ListDelete( L,3,e);
printf("删除元素是:%d\n",e);
return 0;
}
//头插法建立单链表:读入数据的顺序和生成的链表中元素的顺序是相反的;郝斌老师的里面加入了一个新的结点pTail,pTail和L是一样的也是指向头结点,
/*pNew->data = val;
pTail->pNext = pNew;
pNew->pNext = NULL;
pTail = pNew;*/ //通过将pTail与pNew互换,这样就可以是pTail继续指向下一个新增结点,顺序是正序
LinkList List_HeadInsert(LinkList &L)
{
LNode *s;//强调这是一个指向结点的指针
int x;
L = (LinkList)malloc(sizeof(LNode));//创建一个头结点,动态分配内存,使得指针L指向这块区域也就是头结点
L->next = NULL;//初始为空链表
scanf("%d\n",&x);//输入结点的值
while(x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;//将输入的结点的值赋值给新创建的结点指s所值结点的数据域中
s->next = L->next;//s->next里存放的地址是L->next里的地址,就使得s所指结点指向了头指针所指的那个结点
L->next = s;//将L->next的地址改为s,这样就会使头结点指向s所指的那个结点
scanf("%d",&x);
}
return L;
}
//尾插法建立单链表:正序
//郝斌老师里的加入了len,这样就可以规定链表的长度,这样就不需要规定“x != 9999”,省得取值还有限制
LinkList List_TailInsert(LinkList &L)
{
int x; //设元素类型为整数型
L = (LinkList)malloc(sizeof(LNode));
LNode *r = L;//表尾指针,最开始使其也指向头指针
LNode *s;
scanf("%d",&x);
while(x != 9999)
{
s = (LNode *)malloc(sizeof(LNode));//动态分配空间,使s指向刚分配空间的结点
s->data = x;//将x的值赋值给s所指结点的数据域中
r->next = s;//将s所指结点的地址给头结点,这样头结点就指向了s所指向的那个结点
r = s;//在将s的地址赋给r,这样r也就指向了s所指的那个结点
scanf("%d",&x);
}
r->next = NULL;
return L;
}
//遍历输出
void PrintLinkList(LinkList L)
{
LinkList p = L->next;
while(NULL != p)
{
printf("%d\n",p->data);
p = p->next;
}
printf("\n");
return;
}
//按序号查找结点
//时间复杂度为O(n)
LNode *GetElem(LinkList L, int i)//i为位序,是从1开始的
{
if(i<1)
return NULL;
int j = 1;
LNode *p = L->next;//第一个结点指针赋给p,表示p指向第一个结点
while(p != NULL && j<i)
{
p = p->next;
++j;
}
return p;
}
//按值查找表结点
//时间复杂度为O(n)
/*LNode * LocateElem(LinkList L, int e)//e表示的是链表中的某一值
{
LNode *p = L->next;
while(p != NULL && p->data != e)
{
p = p->next;
}
return p;
}*/
//插入结点操作
//时间复杂度为O(n)
bool ListInsert(LinkList L, int i,int e)
{
LNode *p = GetElem(L, i-1);
if(NULL == p)
return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
//下面两个插入就是指定将某个结点插入在某个指针的位置
//后插操作:在p1结点之后插入元素e,因为没有循环,所以时间复杂度为O(1)
bool InsertNextNode(LNode *p,int e)
{
if(NULL == p)
return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->next = p->next;
p->next = s;
return true;
}
//拓展:对某一结点进行前插操作
//时间复杂度为:O(1)
//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p, int e)
{
if(NULL == p)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if(NULL == s)
return false;
s->next = p->next;
p->next = s;//新结点s连接到p之后
s->data = p->data;//将p中的元素复制到s中
p->data = e;//p中元素被e覆盖
return true;
}
//按位序删除结点
//时间复杂度O(n)
bool ListDelete(LinkList &L, int i, int &e)
{
LNode *p = GetElem(L, i-1);
if(NULL == p)
return false;
if(NULL == p->next)//因为p是i的前一个结点,如果p->next == NULL,则说明位置i的结构体为NULL,这样就不要删除
return false;
LNode *q = p->next;
e = q->data;
p->next = q->next;
free(q);
return true;
}
//指定结点的删除
//删除指定结点p,时间1复杂度O(1)
//如果p是指向链表最后一个结点,则此时就会出现错误,若是想删除指定p结点,则只能从表头往后寻找p的直接前驱
bool DeleteNode(LNode *p)
{
if(NULL == p)
return false;
LNode *q = p->next;
p->data = p->next->data;
p->next = q->next;
free(q);
return true;
}
//求表的长度
//时间复杂度为O(n)
int length(LinkList L)
{
int len = 0;//统计链表的长度
LNode *p = L;
while(p->next != NULL)
{
p = p->next;
len++;
}
return len;
}
后插法创建链表
无头结点全部代码
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct LNode
{
int data;
struct LNode *next;
}LNode, *LinkList;
//函数说明
LinkList List_HeadInsert(LinkList &L);
LinkList List_TailInsert(LinkList &L);
void PrintList(LinkList L);
LNode *GetElem(LinkList L, int i);//按位查找
LNode *LocateElem(LinkList L, int e);//按值查找
bool InsertList(LinkList L, int i, int e);//插入某一结点
bool ListDelete(LinkList &L, int i, int &e);//删除某一结点
int Length(LinkList L);//求链表的长度
int main(void)
{
LinkList L = NULL;
printf("创建一个链表\n");
L = List_HeadInsert(L);
//List_TailInsert(L);
printf("链表的数据域为\n");
PrintList(L);
InsertList(L,2,10);
printf("插入之后链表的值为:\n");
PrintList(L);
int e;
if(ListDelete(L,4,e))
{
printf("删除成功,删除的元素是:%d\n",e);
}
else
{
printf("删除失败!\n");
}
printf("删除元素之后链表的值为:\n");
PrintList(L);
int len = Length(L);
printf("链表的长度:%d\n",len);
return 0;
}
//头插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
printf("请输入链表的值\n");
int x;
scanf("%d",&x);
while(x != 9999)
{
LNode * s = (LNode *)malloc(sizeof(LNode));//动态分配空间,使s指向这片空间
s->data = x;//将定义的值赋值到这个结构体的数据域
s->next = L;//这样s指向的这个结点指向L指向的这个结点,因为头结点,所以最开始L指向的是NULL,s指向的这个结点指向NULL
L = s;//将s赋给L,这样L就指向了s指向的那个结点
scanf("%d",&x);
}
return L;
}
//用尾插法建立单链表
LinkList List_TailInsert(LinkList &L)
{
LNode *r;
r = L;
LNode *s;
int x;
scanf("%d",&x);
while(x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = NULL;//该处和 if else 我想了很久都想不出来,是从博主“夕演_hd99”里看的
if(L == NULL)
{
L = s;
r = s;
}//用这个if条件之后,就可以是L,r都是指向了最开始输入的结构体,这样就可以用r->next,就可以使结构体连接在一起形成链表,若是没有这一步,最开始直接使用r->next会错误,因为最开始r = NULL
else
{
r->next = s;
r = s;
}
scanf("%d",&x);
}
return L;
}
void PrintList(LinkList L)
{
LinkList p = L;
while(NULL != p)//已经多次失误用成if
{
printf("%d\n",p->data);
p = p->next;
}
printf("\n");
return;
}
//按位查找
LNode *GetElem(LinkList L, int i)
{
if(i<1)
return false;
else
{
LNode *p = L;
int j = 0;
while(p != NULL && j < i-2)//因为没有了头结点,所以L指向的就是首节点,因为i是位序是从1开始的,而链表是从0开始的,所以是i-2
{
p = p->next;
++j;
}
return p;
}
}
//按值查找
LNode *LocateElem(LinkList L, int e)
{
LNode *p = L;
while(p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
//给定位置和值,插入某一结点
bool InsertList(LinkList L, int i, int e)
{
LNode *p = GetElem(L, i-1);
if(NULL == p)
return false;
LNode *q = (LNode*)malloc(sizeof(LNode));
q->data = e;
q->next = p->next;
p->next = q;
return true;
}
//给定某一结构体指针,进行后插操作
bool InsertNextNode(LNode *p, int e)
{
if(NULL == p)
return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
//给定一个结构体指针,进行前插操作
bool InserPriorNode(LNode* p, int e)
{
if(NULL == p)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = e;
return true;
}
//删除某一结点
bool ListDelete(LinkList &L, int i, int &e)
{
LNode *p = GetElem(L, i-1);
if(NULL == p)
return false;
if(NULL == p->next)
return false;
LNode *q = p->next;
e = q->data;
p->next = p->next->next;
free(q);
return true;
}
//删除指定结点
bool DeleteNode(LNode *p)
{
if(NULL == p)
return false;
LNode *q = p->next;
p->data = q->data;
p->next = q->next;
return true;
}
//链表的长度
int Length(LinkList L)
{
int len = 0;
LNode *p = L;
while(NULL != p)
{
len++;
p = p->next;
}
return len;
}
前插法创建单链表