C语言实现数据机构链表的基本操作(从键盘输入生成链表、读取数组生成链表)
利用头插法实现逆置
下面简单介绍一下,算法思想结合图示看
算法思想:“删除”头结点与链表其他结点的原有联系(即将头结点的指针置空),再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的头结点,如此循环,直至原链表为空。
这是鬼话,看不懂可以不看,看下面就行......
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; }
-----------------------------------------------------转载需备注博主名和原创网址!!!------------------------------------------------------