利用头插法实现逆置
下面简单介绍一下,算法思想结合图示看
算法思想:“删除”头结点与链表其他结点的原有联系(即将头结点的指针置空),再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的头结点,如此循环,直至原链表为空。
这是鬼话,看不懂可以不看,看下面就行…
void NiList(LinkList &L) //逆置
{
LinkList p = L->next, q; //L->next是头结点的指针,p指针指向了首结点
L->next = NULL; //将头结点的指针置空
while (p != NULL)
{
q = p; //指针q从指向第一个结点开始后移
p = p->next; //指针p从指向第二个结点开始后移
q->next = L->next; //指针q所指向结点的指针q->next指向其上一个结点
L->next = q; //头结点的指针后移
}
}
接下来,进行图解:
刚开始是这样
L->next是头结点指针。循环前的操作,p指向首结点(即第一个结点),头结点的指针置空
进入循环,q和p分别指向第一个和第二个节点
q所指向结点的指针q->next指向其(q->next)上一个结点,这里上一个结点的指针为空,故q->next也为空
L->next = q; //头指针后移,指向首结点
进入第二轮循环,这是发生重大变化的关键时期
q和p继续后移,这个图有点错误懒得改了,就是后移后,指针q指向了b结点,指针p指向了c结点
q所指向结点的指针q->next指向其上一个结点
头指针后移,指向第二个结点
你可以看到此时已经开始逆置,如此循环, 直到p==NULL为空
链表完整代码:
1):从键盘输入生成链表
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode* next;
}LNode,*LinkList;
/*定义了两种新的数据类型LNode和LinkList,显然各个结点是LNode类型的,
头指针和结点的next成员是LinkList类型的,L是LinkList这个新的结构体指针类型定义的头指针*/
Status InitList(LinkList &L) //初始化
{
L = (LinkList)malloc(sizeof(LNode));
if (L == NULL)return ERROR;
L->next = NULL;
return OK;
}
Status ListEmpty(LinkList L) //判空
{
if (L->next == NULL) return TRUE;
return FALSE;
}
Status ListInsert(LinkList &L, int i, ElemType e) //插入
{
int j = 0;
LinkList p = L, s; //指针p指向头指针
if (i<1) return ERROR;
while ((p != NULL) && (j<i - 1))
{
p = p->next;
j++;
}
if(p==NULL)return ERROR;
s = (LNode*)malloc(sizeof(LNode)); //生成新节点
if (s == NULL) return ERROR;
s->data = e; //s结点暂存e
s->next = p->next; //s结点的指针s->next指向第i个结点
p->next = s; //第i-1个结点的指针p->next指向s结点
return OK;
}
Status ScanfList(LinkList &L) //键盘输入
{
ElemType e;
int i = 1;
printf("输入整数,以0结束:\n");
scanf("%d", &e);
while (e != 0)
{
if (!ListInsert(L, i, e)) return ERROR;
i++;
scanf("%d", &e);
}
return OK;
}
Status ListDelete(LinkList &L, int i, ElemType &e) //删除
{
int j = 0;
LinkList p = L, q;
if ((i<1) || (L->next == NULL)) return ERROR;
while ((p != NULL) && (j<i - 1))
{
p = p->next;
j++;
}
if (p == NULL) return ERROR;
q = p->next; //指针q暂存被删结点(第i个结点)的地址
p->next = q->next; //指针p(即第i-1个结点的指针)指向被删结点(第i+1个结点)
e = q->data;
free(q);
return OK;
}
Status GetElem(LinkList L, int i, ElemType &e) //取值
{
int j = 1;
LinkList p = L->next;
if (i<1) return ERROR;
while ((p != NULL) && (j<i))
{
p = p->next;
j++;
}
if (p == NULL) return ERROR;
e = p->data;
return OK;
}
int LocateElem(LinkList L, ElemType e) //定位
{
int j = 1;
LinkList p = L->next;
while (p != NULL)
{
if (p->data == e)return j;
p = p->next;
j++;
}
return j;
}
Status PriorElem(LinkList L, ElemType e, ElemType &pr_e) //直接前驱
{
LinkList p = L->next;
if (p->data == e) return ERROR; //首结点没有直接前驱
while (p != NULL)
{
if (p->next->data == e) break;
p = p->next;
}
if (p == NULL) return ERROR; //指针p一直移到尾结点仍找不到e,返回错误
pr_e = p->data;
return OK;
}
int GetLength(LinkList L) //求长度
{
int i = 0;
LinkList p = L;
while (p->next != NULL)
{
p = p->next;
i++;
}
return i;
}
void PrnList(LinkList L) //遍历
{
LinkList p = L->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
void NiList(LinkList &L) //逆置
{
LinkList p = L->next, q; //p指针指向了首结点
L->next = NULL; //将头结点的指针置空
while (p != NULL)
{
q = p; //指针q从指向第一个结点开始后移
p = p->next; //指针p从指向第二个结点开始后移
q->next = L->next; //指针q所指向结点的指针q->next指向其上一个结点
L->next = q; //头结点的指针后移
}
}
Status Destroy(LinkList &L) //销毁,从首结点开始
{
LinkList p = L->next, q;
while (p != NULL)
{
q = p->next;
free(p);
p = q;
}
free(L);
return OK;
}
int main()
{
int i;
ElemType e, e1;
LinkList L;
if (InitList(L)) printf("OK\n");
ScanfList(L);
PrnList(L);
int k;
printf("\n1.插入\n2:删除\n3:取值\n4:定位\n5:直接前驱\n");
printf("6.求长度\n7:遍历\n8:逆置\n9:销毁\n\n0.退出\n");
scanf("%d", &k);
while (k != 0)
{
switch (k)
{
case 1:
printf("在第几个位置插入何数:");
scanf("%d%d", &i, &e);
if (ListInsert(L, i, e)) printf("OK\n");
break;
case 2:
printf("删除第几个数:");
scanf("%d", &i);
if (ListDelete(L, i, e))printf("删除数为:%d\n", e);
break;
case 3:
printf("获取第几个数:");
scanf("%d", &i);
if (GetElem(L, i, e)) printf("数为:%d\n", e);
break;
case 4:
printf("定位何数:");
scanf("%d", &e);
if (LocateElem(L, e)) printf("位序为:%d\n", LocateElem(L, e));
break;
case 5:
printf("寻找何数直接前驱:");
scanf("%d", &e);
if (PriorElem(L, e, e1)) printf("前驱为:%d\n", e1);
break;
case 6:
printf("表长为:");
printf("%d\n", GetLength(L));
break;
case 7:
printf("遍历:\n");
PrnList(L);
break;
case 8:
NiList(L);
PrnList(L);
printf("逆置成功\n");
break;
case 9:
if (Destroy(L))printf("销毁成功\n");
break;
default:
printf("ERROR\n");
}
scanf("%d", &k);
}
return 0;
}
2):读取数组生成链表
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
/*定义了两种新的数据类型LNode和LinkList,显然各个结点是LNode类型的,
头指针和结点的next成员是LinkList类型的,L是LinkList结点指针类型定义的头指针*/
Status InitList(LinkList &L) //初始化
{
L = (LinkList)malloc(sizeof(LNode));
if (L == NULL)return ERROR;
L->next = NULL;
return OK;
}
Status ListEmpty(LinkList L) //判空
{
if (L->next == NULL)return ERROR;
else return FALSE;
}
Status ListInsert(LinkList &L, int i, ElemType e) //插入
{
int j = 0;
LinkList p = L, s; //指针p指向头指针
if (i < 1)return ERROR;
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)return ERROR;
s = (LNode*)malloc(sizeof(LNode)); //生成新节点
if (s == NULL)return ERROR;
s->data = e; //结点s暂存e
s->next = p->next; //s结点的指针s->next指向第i个结点
p->next = s; //指针p指向s结点
return OK;
}
Status CreateList(LinkList &L,ElemType element[], int n) //数组生成链表
{
int i;
for (i = 0; i < n; i++)
if (!ListInsert(L, i + 1, element[i])) return ERROR;
return OK;
}
Status ListDelete(LinkList &L, int i, ElemType &e) //删除
{
int j = 0;
LinkList p = L, q;
if (i < 1 || p->next == NULL)return ERROR;
while (p != NULL && j<i - 1)
{
p = p->next;
j++;
}
if (p == NULL)return ERROR;
q = p->next; //指针q暂存被删结点(第i个结点)的地址,故指针q指向了被删结点
p->next = q->next; //指针p(即第i-1个结点的指针)指向被删结点的下一结点(第i+1个结点)
e = q->data;
free(q);
return OK;
}
Status GetElem(LinkList L, int i, ElemType &e) //取值
{
int j = 1;
LinkList p = L->next;
if (i < 1)return ERROR;
while (p != NULL && j<i)
{
p = p->next;
j++;
}
if (p == NULL)return ERROR;
e = p->data;
return OK;
}
int LocateElem(LinkList L, ElemType e) //定位
{
int j = 1;
LinkList p = L->next;
while (p != NULL)
{
if (p->data == e)return j;
p = p->next;
j++;
}
return j;
}
Status PriorElem(LinkList L, ElemType e, ElemType &pr_e) //直接前驱
{
LinkList p = L->next;
if (p->data==e)return ERROR; //首结点没有直接前驱
while (p != NULL)
{
p = p->next;
if (p->next->data == e)break;
}
if (p == NULL)return ERROR; //指针p一直移到尾结点仍找不到e,返回错误
pr_e = p->data;
return OK;
}
int GetLength(LinkList L) //求长度
{
int i = 0;
LinkList p = L;
while (p->next != NULL)
{
p = p->next;
i++;
}
return i;
}
void PrnList(LinkList L) //遍历
{
LinkList p = L->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
Status NiList(LinkList &L) //逆置
{
LinkList p = L->next, q; //指针p指向了首结点
L->next = NULL; //将头结点指针置空
while (p != NULL)
{
q = p; //指针q从指向第一个结点开始后移
p = p->next; //指针p从指向第二个结点开始后移
q->next = L->next; //指针q所指向结点的指针q->next指向其上一个结点
L->next = q; //头结点的指针后移
}
return OK;
}
Status Destroy(LinkList &L) //销毁,从首结点开始
{
LinkList p = L->next, q;
if (p == NULL)return ERROR;
while (p != NULL)
{
q = p->next;
free(p);
p = q;
}
free(L);
return OK;
}
int main()
{
int i;
ElemType e, e1;
LinkList L;
ElemType element[] = { 15, 3, 59, 27, 8, 11, 32 };
if (InitList(L)) printf("OK\n");
CreateList(L,element,7);
PrnList(L);
int k;
printf("\n1.插入\n2:删除\n3:取值\n4:定位\n5:直接前驱\n");
printf("6.求长度\n7:遍历\n8:逆置\n9:销毁\n\n0.退出\n");
scanf("%d", &k);
while (k != 0)
{
switch (k)
{
case 1:
printf("在第几个位置插入何数:");
scanf("%d%d", &i, &e);
if (ListInsert(L, i, e)) printf("OK\n");
break;
case 2:
printf("删除第几个数:");
scanf("%d", &i);
if (ListDelete(L, i, e))printf("删除数为:%d\n", e);
break;
case 3:
printf("获取第几个数:");
scanf("%d", &i);
if (GetElem(L, i, e)) printf("数为:%d\n", e);
break;
case 4:
printf("定位何数:");
scanf("%d", &e);
if (LocateElem(L, e)) printf("位序为:%d\n", LocateElem(L, e));
break;
case 5:
printf("寻找何数直接前驱:");
scanf("%d", &e);
if (PriorElem(L, e, e1)) printf("前驱为:%d\n", e1);
break;
case 6:
printf("表长为:");
printf("%d\n", GetLength(L));
break;
case 7:
printf("遍历:\n");
PrnList(L);
break;
case 8:
NiList(L);
PrnList(L);
printf("逆置成功\n");
break;
case 9:
if (Destroy(L))printf("销毁成功\n");
break;
default:
printf("ERROR\n");
}
scanf("%d", &k);
}
return 0;
}
-----------------------------------------------------最后的倔强:转载需备注博主名和原创网址!!!-----------------------------------------------------