写的比较简洁,只是实现插入,删除,反转,排序,遍历的功能,没有弄出错反馈,查和改比较简单故没写。
简单尝试了循环双链表
目录
一、带头结点的单链表
1、准备工作
#define TRUE 1
#define FALSE 0
#define INFEASIBLE - 1
#define OVERFLOW - 2
//本次只用到了这两个宏定义
#define OK 1
#define ERROR 0
typedef int ElemType; //数据的类型
typedef int Status; //函数的类型,其值是函数结果状态代码
typedef struct LNode
{
ElemType data; // 存放结点的数据元素。
struct LNode *next; // 指向下一个结点的指针。
}LNode,*LinkList;
2、任意位置插入元素
//难点在于第一个结点(非头结点)和最后一个结点的插入
//特别是不带头结点的不好处理
Status InsertList( LinkList LL, int n, ElemType e)
{
//找到第n-1个结点,n=1时为头结点
LNode *PNode=LL;
for(int i = 0;i<n-1;i++)
{
if(PNode != NULL)
PNode = PNode->next;
}
if(PNode == NULL){
return ERROR; //超出表长
}
//新结点,必须申请动态内存
LNode *NewNode = (LNode *)malloc(sizeof(LNode));
NewNode->data = e;
NewNode->next = NULL;
NewNode->next = PNode->next;
PNode->next= NewNode;
return OK;//插入成功
}
2、删除任意结点的元素
Status DeleteListN( LinkList LL,int n){
LNode *tmp = LL;
//拿到n-1
for(int i = 0;i<n-1;i++){
if(tmp != NULL){
tmp = tmp->next;
}
}
tmp->next = (tmp->next)->next;
printf("将位置 %d的元素删除\n",n);
free(tmp->next);
return OK;
}
3、反转链表(递归)
//头结点指向最后一个结点,其余结点指向反向
Status RReverseList(LNode *p,LinkList LL){
//退出条件
if(p->next == NULL){
LL->next = p;
printf("反转链表(递归)\n");
return OK;
}
RReverseList(p->next,LL);
LNode *nex = p->next;
nex->next = p;
p->next = NULL;
}
4、反转链表(迭代)
Status ReverseList(LinkList LL){
//当前结点,上一个结点,下一个结点
LNode *cur,*pre,*nex;
cur = LL->next;
pre = NULL;
while(cur != NULL){
nex = cur->next;
cur->next = pre;
pre = cur;
cur = nex;
}
LL->next = pre;
printf("反转链表\n");
return OK;
}
5、链表排序(逆序)
Status SortList(LinkList LL){
LNode *ctmp = LL->next;
LNode *ntmp = NULL;
int data;
while((ctmp->next) != NULL){
data = ctmp->data;
ntmp = ctmp->next;
while(ntmp != NULL){
if(data<(ntmp->data)){
ctmp->data = ntmp->data;
ntmp->data = data;
data = ctmp->data;
}
ntmp = ntmp->next;
}
ctmp = ctmp->next;
}
printf("排序\n");
return OK;
}
6、打印链表(迭代)
void PrintList(LinkList LL)
{
//不打印头结点
LNode *tmp = LL->next;
while(tmp != NULL){
printf("%d ",tmp->data);
tmp = tmp->next;
}
printf("\n");
}
7、打印链表(递归)(不建议用)
//传入第一个结点 p = head->next;
void PrintList(LNode *p)
{
//退出条件
if(p == NULL){
printf("\n");
return;
}
//递归实现打印,交换顺序可以逆序打出链表
printf("%d ",p->data);
PrintList(p->next);
}
二、带头结点的循环双链表
1、插入
Status InsertDList( DLinkList DLL, int n, ElemType e) {
DLNode *tmp = DLL;
int i = 0;
//拿到n结点即可
//可以插入的位置为表长+1
//头结点不计入表长
while (i<n) {
if(tmp->next != NULL){
tmp = tmp->next;
}
i++;
if(tmp->next == DLL && i<n-1){
printf("位置%d过长\n",n);
return ERROR;
}
}
DLNode *p = (DLNode *) malloc(sizeof(DLNode));
p->data = e;
//当链表为空时
if(tmp == DLL && tmp->next == NULL){
p->next = tmp;
p->prev = tmp;
tmp->next = p;
tmp->prev = p;
}
else{
p->next = tmp;
p->prev = tmp->prev;
(tmp->prev)->next = p;
tmp->prev = p;
}
return OK;
}
2、打印
void PrintDList(DLinkList DLL){
DLNode *tmp = DLL->next;//不打印头结点
while(tmp->next != DLL){
printf("%d ",tmp->data);
tmp = tmp->next;
}
printf("%d\n",tmp->data);
}
三、全部代码
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE - 1
#define OVERFLOW - 2
typedef int ElemType; //数据的类型
typedef int Status; //函数的类型,其值是函数结果状态代码
typedef struct LNode
{
ElemType data; // 存放结点的数据元素。
struct LNode *next; // 指向下一个结点的指针。
}LNode,*LinkList;
//双向链表
typedef struct DLNode
{
ElemType data; // 存放结点的数据元素。
struct DLNode *next; // 指向下一个结点的指针。
struct DLNode *prev; // 指向上一个结点的指针。
}DLNode,*DLinkList;
/*单链表*/
// 在链表任意位置插入,要传入链表的地址(增)
Status InsertList( LinkList LL, int n, ElemType e);
//删除指定的元素(删)
Status DeleteListN( LinkList LL,int e);
//反转链表(迭代)
Status ReverseList(LinkList LL);
//反转链表(递归recursive)
Status RReverseList(LNode *p,LinkList LL);
//链表排序
Status SortList(LinkList LL);
// 打印链表中全部的元素。
void PrintList(LinkList LL);
/*双链表*/
// 在链表任意位置插入,要传入链表的地址(增)
Status InsertDList( DLinkList DLL, int n, ElemType e);
//删除指定的元素(删)
Status DeleteDListN( DLinkList DLL,int e);
// 打印链表中全部的元素。
void PrintDList(DLinkList DLL);
int main()
{
LinkList LL = (LinkList) malloc(sizeof(LNode));
LL->next = NULL;
DLinkList DLL = (DLinkList) malloc(sizeof(DLNode));
DLL->next = NULL;
DLL->prev = NULL;
ElemType e[10] = {2,3,5,6,1,7,4,8,9,10};
Status s;
//赋初值
for(int i = 1;i<11;i++){
s = InsertList(LL,i,e[i-1]);//s判断是否插入成功
}
PrintList(LL);
printf("单链表操作:\n");
printf("在第1位插入111\n");
s = InsertList(LL,1,111);
PrintList(LL);
DeleteListN(LL,1);
PrintList(LL);
SortList(LL);
PrintList(LL);
ReverseList(LL);
PrintList(LL);
RReverseList(LL->next,LL);
PrintList(LL);
printf("\n双链表操作:\n");
for(int i = 1;i<11;i++){
InsertDList(DLL,i,e[i-1]);
}
PrintDList(DLL);
printf("在第1位插入111\n");
InsertDList(DLL,1,111);
PrintDList(DLL);
printf("在第13位插入222\n");
InsertDList(DLL,13,222);
PrintDList(DLL);
return 0;
}
//难点在于第一个结点(非头结点)和最后一个结点的插入
//特别是不带头结点的不好处理
Status InsertList( LinkList LL, int n, ElemType e)
{
//找到第n-1个结点,n=1时为头结点
LNode *PNode=LL;
for(int i = 0;i<n-1;i++)
{
if(PNode != NULL)
PNode = PNode->next;
}
if(PNode == NULL){
return ERROR; //超出表长
}
//新结点,必须申请动态内存
LNode *NewNode = (LNode *)malloc(sizeof(LNode));
NewNode->data = e;
NewNode->next = NULL;
NewNode->next = PNode->next;
PNode->next= NewNode;
return OK;//插入成功
}
Status DeleteListN( LinkList LL,int n){
LNode *tmp = LL;
//拿到n-1
for(int i = 0;i<n-1;i++){
if(tmp != NULL){
tmp = tmp->next;
}
}
tmp->next = (tmp->next)->next;
printf("将位置 %d的元素删除\n",n);
free(tmp->next);
return OK;
}
Status ReverseList(LinkList LL){
//当前结点 current,上一个结点previous,下一个结点next
LNode *cur,*pre,*nex;
cur = LL->next;
pre = NULL;
while(cur != NULL){
nex = cur->next;
cur->next = pre;
pre = cur;
cur = nex;
}
LL->next = pre;
printf("反转链表(迭代)\n");
return OK;
}
Status RReverseList(LNode *p,LinkList LL){
if(p->next == NULL){
LL->next = p;
printf("反转链表(递归)\n");
return OK;
}
RReverseList(p->next,LL);
LNode *nex = p->next;
nex->next = p;
p->next = NULL;
}
Status SortList(LinkList LL){
LNode *ctmp = LL->next;
LNode *ntmp = NULL;
int data;
while((ctmp->next) != NULL){
data = ctmp->data;
ntmp = ctmp->next;
while(ntmp != NULL){
if(data<(ntmp->data)){
ctmp->data = ntmp->data;
ntmp->data = data;
data = ctmp->data;
}
ntmp = ntmp->next;
}
ctmp = ctmp->next;
}
printf("排序\n");
return OK;
}
// 打印链表中全部的元素。
void PrintList(LinkList LL)
{
//不打印头结点
LNode *tmp = LL->next;
while(tmp != NULL){
printf("%d ",tmp->data);
tmp = tmp->next;
}
printf("\n");
}
Status InsertDList( DLinkList DLL, int n, ElemType e) {
DLNode *tmp = DLL;
int i = 0;
//拿到n结点即可
//可以插入的位置为表长+1
//头结点不计入表长
while (i<n) {
if(tmp->next != NULL){
tmp = tmp->next;
}
i++;
if(tmp->next == DLL && i<n-1){
printf("位置%d过长\n",n);
return ERROR;
}
}
DLNode *p = (DLNode *) malloc(sizeof(DLNode));
p->data = e;
//当链表为空时
if(tmp == DLL && tmp->next == NULL){
p->next = tmp;
p->prev = tmp;
tmp->next = p;
tmp->prev = p;
}
else{
p->next = tmp;
p->prev = tmp->prev;
(tmp->prev)->next = p;
tmp->prev = p;
}
return OK;
}
void PrintDList(DLinkList DLL){
DLNode *tmp = DLL->next;//不打印头结点
while(tmp->next != DLL){
printf("%d ",tmp->data);
tmp = tmp->next;
}
printf("%d\n",tmp->data);
}
封面来源:https://www.bilibili.com/video/BV1Fv4y1f7T1?p=5
视频讲的和我写的有点出入,但可以看思路