单链表的定义
定义一个单链表
typedef struct LNode
{
int data;
struct LNode *next;
} LNode, *LinkList;
初始化不带头结点的单链表
bool InitList(LinkList &L)
{
L = NULL;
return true;
}
初始化带头结点的单链表
bool InitList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode)); //分配一个头结点
if (L = NULL)
{ //内存不足,分配失败
return false;
}
L->next = NULL; //头结点之后暂时还没有结点,所以指空
return true;
}
单链表的插入
按位序插入带头结点的单链表
bool ListInsert(LinkList &L, int i, int e)
{
if (i < 1)
{
return false;
}
LNode *p; //用于指向当前扫描到的结点
int j = 0; //p指向第几个结点
p = L; //p指向为头结点(第0个,不存数据)
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
{ //当i大于最后一个结点时,p最后指向空
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s; //这两个指向不能变,要是p的next结点先指向s,s的后继结点会指向s本身
return true;
}
最好情况时间复杂度:O(1);
最坏情况时间复杂度:O(n);
平均情况时间复杂度:O(n)。
按位序插入不带头结点的单链表
bool ListInsert(LinkList &L, int i, int 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;
int j = 1; //不带头结点,不是在第一个结点插入,所以p指针一开始是指向第一个结点
p = L;
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
{
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
最好情况时间复杂度:O(1);
最坏情况时间复杂度:O(n);
平均情况时间复杂度:O(n)。
通过对比可知,带头结点的操作比不带头结点的操作相对简单。
指定结点的后插操作
bool InsertNextNode(LNode *p, int e)
{
if (p == NULL)
{
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s == NULL) //空间不足分配失败
{
return false;
}
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
时间复杂度:O(1)。
指定结点的前插操作
bool InsertPriorNode(LNode *p, int e)
{
if (p == NULL)
{
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s == NULL)
{
return false;
}
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = e;
return true;
}
时间复杂度:O(1)。
单链表的删除
按位序删除带头结点的单链表
bool ListDelete(LinkList &L, int i, int &e)
{
if (i < 1)
{
return false;
}
LNode *p;
int j = 0;
p = L;
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL || p->next == NULL) //i值不合法或者p结点已经是最后一个结点
{
return false;
}
LNode *q = p->next; //q指向被删除结点
e = q->data;
p->next = q->next;
free(q);
return true;
}
最好情况时间复杂度:O(1);
最坏情况时间复杂度:O(n);
平均情况时间复杂度:O(n)。
删除指定结点
bool DeleteNode(LNode *p) //p是最后一个结点这段代码不行
{
if (p == NULL)
{
return false;
}
LNode *q = p->next;
p->data = q->data;
p->next = q->next;
free(q);
return true;
}
时间复杂度:O(1)。
单链表的查找
查找操作默认是带头结点的单链表
单链表的位序查找
LNode *GetElem(LinkList L, int i)
{
if (i < 0)
{
return NULL;
}
LNode *p;
int j = 0;
p = L;
while (p != NULL && j < i)
{
p = p->next;
j++;
}
return p;
}
平均情况时间复杂度:O(n)。
单链表的按值查找
LNode *LocateElem(LinkList L, int e)
{
LNode *p = L->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
平均情况时间复杂度:O(n)。
求单链表的长度(不带头结点)
int Length(LinkList L)
{
int len = 0;
LNode *p = L;
while (p->next != NULL)
{
p = p->next;
len++;
}
return len;
}
平均情况时间复杂度:O(n)。
单链表的建立
尾插法建立单链表
LinkList List_TailInsert(LinkList &L)
{
int x; //要插入的元素数值
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
LNode *s, *r = L;
scanf("%d", &x);
while (x != 9999)
{
s = (LNode *)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;
scanf("%d", &x);
}
r->next = NULL;
return L;
}
平均情况时间复杂度:O(n)。
头插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
int x = 0;
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
LNode *s;
scanf("%d", &x);
while (x != 9999)
{
s = (LNode *)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d", &x);
}
return L;
}
平均情况时间复杂度:O(n)。
头插法可以用于链表的逆置。