1.双链表
双链表是指在单链表的基础上,每一个结构体中多出来一个指针用来指向上一个结构体。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Lnode {
int value;
struct Lnode* next;
struct Lnode* previous;
}Lnode;
typedef struct DoubleList {
Lnode* head;
Lnode* tail;
int numofele;
}List;
List* CreatList() {
List* ret = (List*)malloc(sizeof(List));
if (ret == NULL) {
perror("malloc:");
return NULL;
}
ret->numofele = 0;
ret->head = (Lnode*)malloc(sizeof(Lnode));
if (ret->head == NULL) {
perror("malloc:");
return NULL;
}
ret->tail = (Lnode*)malloc(sizeof(Lnode));
if (ret->tail == NULL) {
perror("malloc:");
return NULL;
}
ret->head->next = NULL;
ret->head->previous = NULL;
ret->tail->previous = ret->head;
ret->tail->next = NULL;
return ret;
}
void DestroyList(List* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
Lnode* tmp = l->head;
while (tmp) {
Lnode* p = tmp->next;
free(tmp);
tmp = p;
}
free(l);
l = NULL;
}
List* ClearList(List* l) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
l->numofele = 0;
Lnode* tmp = l->head->next;
while (tmp != l->tail) {
Lnode* p = tmp->next;
free(tmp);
tmp = p;
}
l->head->next = NULL;//为了测试双链表删除等算法的边界情况,这里不使用尾节点,加入尾节点操作会更方便
l->tail->previous = l->head;
return l;
}
bool IsEmpty(List* l) {
if (l == NULL) {
printf("表不存在\n");
return false;
}
return l->numofele == 0;
}
int GetListLength(List* l) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
return l->numofele;
}
int GetElem(List* l, int pos) {//获得表中第pos个元素
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (IsEmpty(l)) {
printf("表为空\n");
return -1;
}
if (pos<1 || pos>l->numofele) {
printf("不存在第 %d 个元素\n", pos);
return -1;
}
int count = pos;
Lnode* tmp = l->head;
while (count--) {
tmp = tmp->next;
}
return tmp->value;
}
Lnode* GetElemPos(List* l, int k) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
if (IsEmpty(l)) {
printf("表为空\n");
return NULL;
}
Lnode* tmp = l->head->next;
while (tmp != l->tail) {
if (tmp->value == k)
return tmp;
tmp = tmp->next;
}
printf("不存在元素 %d\n", k);
return NULL;
}
Lnode* GetPre(List* l, int k) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
if (IsEmpty(l)) {
printf("表为空\n");
return NULL;
}
Lnode* tmp = l->head;
while (tmp->next != l->tail) {
if (tmp->next->value == k)
return tmp;
tmp = tmp->next;
}
printf("不存在元素 %d,所以没有前驱\n", k);
return NULL;
}
//在指定结点后插
void BackInsert(List* l, Lnode* object, int k) {
if (l == NULL) {
printf("表为空\n");
return;
}
Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
if (tmp == NULL) {
perror("malloc");
return;
}
if (object->next) {
tmp->next = object->next;
tmp->previous = object;
tmp->next->previous = tmp;
object->next = tmp;
tmp->value = k;
}
else {//带有尾节点的双链表不需要判断这一层
tmp->next = NULL;
tmp->previous = object;
object->next = tmp;
tmp->value = k;
}
}
//在指定结点前插
void PreInsert(List* l, Lnode* object, int k) {
if (l == NULL) {
printf("表为空\n");
return;
}
Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
if (tmp == NULL) {
perror("malloc");
return;
}
Lnode* pre = object->previous;
tmp->next = object;
tmp->previous = pre;
pre->next = tmp;
object->previous = tmp;
tmp->value = k;
}
//在指定位置插入
void Insert(List* l, int k, int pos) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (pos<1 || pos>l->numofele + 1) {
printf("插入位置不合法\n");
return;
}
int count = pos - 1;
Lnode* tmp = l->head;
while (count--) {
tmp = tmp->next;
}
Lnode* p = (Lnode*)malloc(sizeof(Lnode));
if (p == NULL) {
perror("malloc:");
return;
}
//如果不使用尾节点,对最后一个元素进行插入和删除就需要单独处理
if (tmp->next) {
p->next = tmp->next;
tmp->next = p;
p->previous = tmp;
p->next->previous = p;
p->value = k;
l->numofele++;
}
else {
tmp->next = p;
p->next = NULL;
p->previous = tmp;
p->value = k;
l->numofele++;
}
}
//删除指定结点
int ObjectDelete(List* l, Lnode* object) {
int ret = object->value;
if (l == NULL) {
printf("表为空\n");
return -1;
}
Lnode* pre = object->previous;
if (object->next) {
pre->next = object->next;
object->next->previous = pre;
free(object);
object = NULL;
}
else {
pre->next = NULL;
free(object);
object = NULL;
}
return ret;
}
//按位置删除结点
int Delete(List* l, int i) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (IsEmpty(l)) {
printf("表为空,无法删除\n");
return -1;
}
Lnode* tmp = l->head;
while (i--) {
tmp = tmp->next;
}
int ret = tmp->value;
Lnode* pre = tmp->previous;
if (tmp->next) {
pre->next = tmp->next;
tmp->next->previous = pre;
free(tmp);
tmp = NULL;
}
else {
pre->next = NULL;
free(tmp);
tmp = NULL;
}
return ret;
}
void Print(List* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (IsEmpty(l)) {
printf("表为空,无法打印\n");
return;
}
Lnode* tmp = l->head->next;
while (tmp) {
printf("%d ", tmp->value);
tmp = tmp->next;
}
printf(" 元素数量 = %d", l->numofele);
printf("\n");
}
void ReversePrint(List* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (IsEmpty(l)) {
printf("表为空,无法打印\n");
return;
}
Lnode* tmp = l->tail->previous;
while (tmp != l->head) {
printf("%d ", tmp->value);
tmp = tmp->previous;
}
printf(" 元素数量 = %d\n", l->numofele);
}
int main() {
List* l = CreatList();
Print(l);
for (int i = 0; i < 11; i++) {
Insert(l, i, i + 1);
}
Print(l);
Delete(l, 11);
Print(l);
return 0;
}
2.循环单链表
在单链表的基础上,使得表尾部的元素的next指针指向表头。
在实现单链表时,如果在表头加上哑节点,实现起来就会比较容易,因为这样表头的地址就是始终不变的。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Lnode {
int value;
struct Lnode* next;
}Lnode;
typedef struct List {
Lnode* head;
int numofele;
}List;
List* CreatList() {
List* ret = (List*)malloc(sizeof(List));
if (ret == NULL) {
perror("malloc:");
return NULL;
}
ret->head = (Lnode*)malloc(sizeof(Lnode));
if (ret->head == NULL) {
perror("malloc:");
return NULL;
}
ret->head->next = ret->head;
ret->numofele = 0;
return ret;
}
void DestroyList(List* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
Lnode* tmp = l->head->next;
while (tmp != l->head) {
Lnode* p = tmp->next;
free(tmp);
tmp = p;
}
free(tmp);
tmp = NULL;
free(l);
l = NULL;
}
List* ClearList(List* l) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
l->numofele = 0;
Lnode* tmp = l->head->next;
l->head->next = l->head;
while (tmp != l->head) {
Lnode* p = tmp->next;
free(tmp);
tmp = p;
}
return l;
}
bool IsEmpty(List* l) {
if (l == NULL) {
printf("表不存在\n");
return false;
}
return l->numofele == 0;
}
int GetListLength(List* l) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
return l->numofele;
}
int GetElem(List* l, int pos) {//获得表中第pos个元素,如果pos大于表中元素个数,则循环找
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (IsEmpty(l)) {
printf("表为空\n");
return -1;
}
if (pos < 1) {
printf("位置不合法\n");
return -1;
}
int realpos = pos % l->numofele;
realpos = (realpos == 0 ? l->numofele : realpos);
Lnode* tmp = l->head;
while (realpos--) {
tmp = tmp->next;
}
return tmp->value;
}
Lnode* GetElemPos(List* l, int k) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
if (IsEmpty(l)) {
printf("表为空\n");
return NULL;
}
Lnode* tmp = l->head->next;
while (tmp != l->head) {
if (tmp->value == k)
return tmp;
tmp = tmp->next;
}
printf("元素 %d 不存在\n", k);
return NULL;
}
Lnode* GetPre(List* l, int k) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
Lnode* tmp = l->head;
while (tmp->next != l->head) {
if (tmp->next->value == k)
return tmp;
}
printf("元素 %d 不存在,所以它在表中没有前驱\n", k);
return NULL;
}
//在指定结点前插
void PreInsert(List* l, Lnode* object, int k) {
if (l == NULL) {
printf("表为空\n");
return;
}
Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
if (tmp == NULL) {
perror("malloc");
return;
}
tmp->next = object->next;
object->next = tmp;
tmp->value = object->value;
object->value = k;
}
//在指定节点后插
void BackInsert(List* l, Lnode* object, int k) {
if (l == NULL) {
printf("表为空\n");
return;
}
Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
if (tmp == NULL) {
perror("malloc");
return;
}
tmp->next = object->next;
object->next = tmp;
tmp->value = k;
}
//在指定位置插入
void Insert(List* l, int k, int pos) {//在这里规定插入的位置要求要小于等于元素数量+1
if (l == NULL) {
printf("表不存在\n");
return;
}
if (pos<1 || pos>l->numofele + 1) {
printf("插入位置不合法\n");
return;
}
Lnode* tmp = l->head;
int count = pos - 1;
while (count--) {
tmp = tmp->next;
}
Lnode* p = (Lnode*)malloc(sizeof(Lnode));
if (p == NULL) {
perror("malloc:");
return;
}
p->next = tmp->next;
p->value = k;
tmp->next = p;
l->numofele++;
}
//删除指定结点
int ObjectDelete(List* l, Lnode* object) {
int ret = object->value;
//循环链表中每个结点都有后继,所以只需要考虑后继节点是否为头节点
Lnode* tmp = object->next;
if (tmp == l->head) {
l->head = object;
}
else {
object->value = tmp->value;
}
object->next = tmp->next;
free(tmp);
tmp = NULL;
return ret;
}
//删除指定位置的结点,规定i大于1小于等于表中元素个数
int Delete(List* l, int i) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (IsEmpty(l)) {
printf("表为空,无法删除\n");
return -1;
}
if (i<1 || i>l->numofele) {
printf("位置不合法\n");
return -1;
}
Lnode* tmp = l->head;
i--;
while (i--) {
tmp = tmp->next;
}
Lnode* p = tmp->next;
int ret = p->value;
tmp->next = p->next;
free(p);
p = NULL;
return ret;
}
void Print(List* l, Lnode* begin) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (IsEmpty(l)) {
printf("表为空,无法打印\n");
return;
}
Lnode* tmp = begin->next;
if (begin != l->head) {
printf("%d ", begin->value);
}
while (tmp != begin) {
if (tmp != l->head) {
printf("%d ", tmp->value);
}
tmp = tmp->next;
}
printf("元素数量 = %d\n", l->numofele);
}
int main() {
List* l = CreatList();
Print(l, l->head);
for (int i = 0; i < 11; i++) {
Insert(l, i, i + 1);
}
Print(l, l->head);
Delete(l, 1);
Print(l, GetElemPos(l, 10));
return 0;
}
3.循环双链表
在双链表的基础上,使表头能指向表尾,使表尾能指向表头。
最好在表头和表尾都加上哑节点,这样不论是增加还是删除,都不会改变表头和表尾的地址。因为在增删表头或表尾元素时,必须要记住表尾或是表头的地址,如果不适用哑节点的话,就需要两个专门的变量来存放表头和表尾的地址。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//循环双链表如果使用一个头节点和尾节点将会非常好实现
typedef struct Lnode {
int value;
struct Lnode* next;
struct Lnode* previous;
}Lnode;
typedef struct List {
Lnode* head;
Lnode* tail;
int numofele;
}List;
List* CreatList() {
List* ret = (List*)malloc(sizeof(List));
if (ret == NULL) {
perror("malloc");
return NULL;
}
ret->numofele = 0;
ret->head = (Lnode*)malloc(sizeof(Lnode));
if (ret->head == NULL) {
perror("malloc");
return NULL;
}
ret->tail = (Lnode*)malloc(sizeof(Lnode));
if (ret->tail == NULL) {
perror("malloc");
return NULL;
}
//为了测试删除等操作的边界情况,例如删除最后一个结点,所以这里不使用尾节点
//使用尾节点可以让操作更方便
ret->head->next = ret->head;
ret->head->previous = ret->head;
ret->tail->next = ret->head;
ret->tail->previous = ret->head;
return ret;
}
void DestroyList(List* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
Lnode* tmp = l->head->next;
while (tmp != l->head) {
Lnode* p = tmp->next;
free(tmp);
tmp = p;
}
free(l->head);
free(l);
l = NULL;
}
List* ClearList(List* l) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
Lnode* tmp = l->head->next;
while (tmp != l->tail) {
Lnode* p = tmp->next;
free(tmp);
tmp = p;
}
l->head->next = l->tail;
l->tail->previous = l->head;
l->numofele = 0;
return l;
}
bool IsEmpty(List* l) {
if (l == NULL) {
printf("表不存在\n");
return false;
}
return l->numofele == 0;
}
int GetListLength(List* l) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
return l->numofele;
}
int GetElem(List* l, int pos) {//获得表中第pos个元素,在循环链表中,不限制pos大小,可以循环找
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (IsEmpty(l)) {
printf("表为空\n");
return -1;
}
if (pos < 1) {
printf("输入位置不合法\n");
return -1;
}
int count = pos % l->numofele;
count = (count == 0 ? l->numofele : count);
Lnode* tmp = l->head;
while (count--) {
tmp = tmp->next;
}
return tmp->value;
}
Lnode* GetElemPos(List* l, int k) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
if (IsEmpty(l)) {
printf("表为空\n");
return NULL;
}
Lnode* tmp = l->head->next;
while (tmp != l->tail) {
if (tmp->value == k)
return tmp;
tmp = tmp->next;
}
printf("元素 %d 不存在\n", k);
return NULL;
}
Lnode* GetPre(List* l, int k) {
if (l == NULL) {
printf("表不存在\n");
return NULL;
}
if (IsEmpty(l)) {
printf("表为空\n");
return NULL;
}
Lnode* tmp = l->head;
while (tmp->next != l->tail) {
if (tmp->next->value == k)
return tmp;
tmp = tmp->next;
}
printf("元素 %d 不存在,所以没有前驱\n", k);
return NULL;
}
//在指定结点前插
void PreInsert(List* l, Lnode* object, int k) {
if (l == NULL) {
printf("表为空\n");
return;
}
Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
if (tmp == NULL) {
perror("malloc");
return;
}
Lnode* pre = object->previous;
tmp->next = pre->next;
tmp->previous = pre;
pre->next = tmp;
object->previous = tmp;
tmp->value = k;
}
//指定结点后插
void BackInsert(List* l, Lnode* object, int k) {
if (l == NULL) {
printf("表为空\n");
return;
}
Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
if (tmp == NULL) {
perror("malloc");
return;
}
tmp->next = object->next;
tmp->previous = object;
tmp->next->previous = tmp;
object->next = tmp;
tmp->value = k;
}
//在指定位置插入
void Insert(List* l, int k, int pos) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (pos<1 || pos>l->numofele + 1) {
printf("插入位置不合法\n");
return;
}
int count = pos - 1;
Lnode* tmp = l->head;
while (count--) {
tmp = tmp->next;
}
Lnode* p = (Lnode*)malloc(sizeof(Lnode));
if (p == NULL) {
perror("malloc");
return;
}
p->value = k;
p->next = tmp->next;
p->previous = tmp;
p->next->previous = p;
tmp->next = p;
l->numofele++;
}
//删除指定结点
int ObjectDelete(List* l, Lnode* object) {
int ret = object->value;
Lnode* pre = object->previous;
pre->next = object->next;
object->next->previous = pre;
free(object);
object = NULL;
return ret;
}
//删除指定位置的结点
int Delete(List* l, int i) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (IsEmpty(l)) {
printf("表为空,无法删除\n");
return -1;
}
Lnode* tmp = l->head;
while (i--) {
tmp = tmp->next;
}
int ret = tmp->value;
Lnode* pre = tmp->previous;
pre->next = tmp->next;
tmp->next->previous = pre;
free(tmp);
tmp = NULL;
return ret;
}
void Print(List* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (IsEmpty(l)) {
printf("表为空,无法打印\n");
return;
}
Lnode* tmp = l->head->next;
while (tmp != l->head) {
printf("%d ", tmp->value);
tmp = tmp->next;
}
printf("表中元素数量为 = %d\n", l->numofele);
}
void SetPosPrint(List* l, int pos) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (IsEmpty(l)) {
printf("表为空,无法打印\n");
return;
}
if (pos<1 || pos>l->numofele) {
printf("输入位置不合法\n");
return;
}
Lnode* begin = l->head;
while (pos--) {
begin = begin->next;
}
Lnode* tmp = begin->next;
while (tmp != begin) {
if (tmp != l->head && tmp != l->tail) {
printf("%d ", tmp->value);
}
tmp = tmp->next;
}
printf("%d 表中元素数量为 = %d\n", begin->value, l->numofele);
}
void ReversePrint(List* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (IsEmpty(l)) {
printf("表为空,无法打印\n");
return;
}
Lnode* tmp = l->head->previous;
while (tmp != l->head) {
printf("%d ", tmp->value);
tmp = tmp->previous;
}
printf("表中元素数量为 = %d\n", l->numofele);
}
void SetPosReversePrint(List* l, int pos) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (IsEmpty(l)) {
printf("表为空,无法打印\n");
return;
}
if (pos<1 || pos>l->numofele) {
printf("输入位置不合法\n");
return;
}
Lnode* begin = l->head;
while (pos--) {
begin = begin->next;
}
Lnode* tmp = begin->previous;
while (tmp != begin) {
if (tmp != l->head && tmp != l->tail) {
printf("%d ", tmp->value);
}
tmp = tmp->previous;
}
printf("%d 表中元素数量为 = %d\n", begin->value, l->numofele);
}
int main() {
List* l = CreatList();
for (int i = 0; i <= 10; i++) {
Insert(l, i, i + 1);
}
Print(l);
ReversePrint(l);
Delete(l, 11);
Print(l);
ReversePrint(l);
return 0;
}

被折叠的 条评论
为什么被折叠?



