1.单链表
ADT
typedef struct LNode { //定义单链表节点类型
int data; //每个节点存放一个数据元素
struct LNode* next; //每个节点存放一个指向下一个节点的指针
}LNode,*LinkList;
按位查找
根据所给的i值,返回第i个元素
带头结点:
LNode* GetElem(LinkList L, int i) {
if (i < 0)
return NULL;
LNode* p = L; //建立一个指向头节点的指针p
int j = 0; //它指向节点的序号初始值为0
while (p != NULL && j < i) { //循环找到第i个结点
p = p->next;
j++;
}
return p;
}
不带头结点:
LNode* GetElem(LinkList L, int i) {
if (i <= 0)
return NULL;
LNode* p = L; //建立一个指向第一个结点的指针p
int j = 1; //它指向节点的序号初始值为1
while (p != NULL && j < i) { //循环找到第i个结点
p = p->next;
j++;
}
return p;
}
带头结点的函数从0号结点开始循环,当i等于0时直接返回头节点;不带头节点的函数从1号结点开始循环,所以要增加i=0的判断
按位查找的时间复杂度为O(n)
按值查找
按值查找,若某节点数据域的值等于给定值e,返回该点的指针
带头结点:
LNode* LocateElem(LinkList L, int 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;
}
按值查找的时间复杂度为O(n)
插入结点
将值为x的新结点插入到单链表的第i个位置上
1.向前插入
带头结点:
bool ListInsert(LinkList& L, int i, int e) {
if (i < 1)
return false;
LNode* p = GetElem(L, i-1); //根据之前写的查找函数,查找第i-1个结点
if (p == NULL) //插入位置i不合法
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
不带头结点:
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 = GetElem(L, i - 1); //根据之前写的查找函数,查找第i-1个结点
if (p == NULL) //插入位置i不合法
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
插入节点所花费的时间主要用于查找前一个结点,时间复杂度为O(n),但如果给定结点插入,时间复杂度为O(1)
2.向后插入
带头结点与不带头结点一样
bool InsertNextNode(LinkList& L, int i, int e) {
if (i < 1)
return false;
LNode* p = GetElem(L, i);
if (p == NULL)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
3.更换结点内容的向前插入
在p结点之后创建新的结点s,并将e赋值,然后交换结点p与s的数据,相当于使结点s位于结点p之前,实现前插操作
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中元素复制到s中
p->data = e; //将e的值赋给p
return true;
}
删除结点
带头结点:
bool DeleteNode(LinkList& L, int i, int& e) {
if (i < 1)
return false;
LNode* p = GetElem(L, i - 1); //循环找到第i-1个结点
if (p == NULL)
return false;
if (p->next == NULL) //第i-1个结点后已无结点
return false;
LNode* q = p->next; //令q指向将要删除的结点
e = q->data; //用e返回元素的值
p->next = q->next; //令p指向被删除结点的下一个结点
free(q); //释放q
return true;
}
不带头结点:
bool DeleteNode(LinkList& L, int i, int& e) {
if (i < 1)
return false;
if (i == 1) {
L = L->next;
return true;
}
LNode* s = GetElem(L, i - 1); //循环找到第i-1个结点
if (s == NULL) //i-1的值不合法
return false;
if (s->next == NULL) //i-1结点后无后继节点
return false;
LNode* q = s->next; //令q指向将要删除的结点
e = q->data;
s->next = q->next; //令s指向被删除结点的下一个结点
free(q); //释放q
return false;
}
尾插法建立单链表
带头结点:
LinkList List_TailInsert(LinkList& L) { //正向建立单链表
int x; //设置ElemType为整型
L = (LNode*)malloc(sizeof(LNode)); //建立头节点
LNode* s;
LNode* r = L; //r为表尾指针
scanf("%d", &x);
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode)); //在r结点后插入数据x
s->data = x;
r->next = s;
r = s; //永远保持r指向最后一个节点
scanf("%d", &x);
}
r->next = NULL;
return L;
}
不带头结点:
LinkList LinkList_TailInsert(LinkList& L) {
int x;
scanf("%d", &x);
L = (LNode*)malloc(sizeof(LNode));
LNode* r = L;
LNode* s;
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode));
r->data = x;
r->next = s;
r = s;
scanf("%d", &x);
}
r->next = NULL;
return L;
}
注:VC++不支持使用scanf,可以用scanf_s替换,或者查找C4996解决方案
头插法建立单链表
带头结点:
LinkList List_HeadInsert(LinkList& L) { //逆向建立单链表
int x;
LNode* p;
L = (LNode*)malloc(sizeof(LNode)); //创建头结点
L->next = NULL; //初始为空链表
scanf_s("%d", &x);
while (x != 9999) {
p = (LNode*)malloc(sizeof(LNode)); //创建新节点
p->data = x;
p->next = L->next;
L->next = p; //将新结点插入表中,L为头指针
scanf_s("%d", &x);
}
return L;
}
不带头结点:
LinkList List_HeadInsert(LinkList &L) {
LNode* s;
L = NULL;
int x;
scanf_s("%d", &x);
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L;
L = s;
scanf_s("%d", &x);
}
return L;
}
2.双链表
typedef struct DNode {
int data;
struct DNode* next,* prior;
}DNode,*DLinkList;
//初始化双链表
bool InitDLinkList(DLinkList& L) {
L = (DNode*)malloc(sizeof(DNode)); //分配一个头结点
if (L == NULL) //内存不足,分配失败
return false;
L->prior = NULL; //头结点的prior永远指向NULL
L->next = NULL; //头结点之后暂时还没有结点
return false;
}
//在p结点后插入s结点
bool InsertNextNode(DNode* p, DNode* s) {
if (s == NULL || p == NULL)
return false;
s->next = p->next;
if(p->next !=NULL) //如果p结点有后继结点
p->next->prior = s;
p->next = s;
s->prior = p;
}
//删除p结点的后继结点
bool DeleteNextNode(DNode* p) {
if (p == NULL)
return false;
if (p->next == NULL);
return false;
DNode* q = p->next;
p->next = q->next;
if (q->next != NULL) //q结点不是最后一个结点
q->next->prior = p;
free(q);
return true;
}
//删除双链表,循环释放各个结点
void DestoryList(DLinkList &L) {
while (L->next != NULL)
DeleteNextNode(L);
free(L); //释放头结点
L = NULL; //头指针指向NULL
}
循环链表
在单链表和双链表中加入一些指针即可
静态链表
两种ADT,一种意思
#define MaxSize 50
struct Node {
int data;
int next;
};
typedef struct {
int data;
int next;
}SLinkList[MaxSize];
int main() {
struct Node a[MaxSize];
SLinkList b;
}