单链表头插法
不带头结点
void FronttList1(List *L) { List p; ElemType x; printf_s("请输入一组数据,以‘0’为结束符\n"); scanf_s("%d", &x); *L = NULL; while (x) { p = (List)malloc(sizeof(Lnode)); p->data = x; p->next = *L; *L = p; scanf_s("%d", &x); } }
带头结点
void FrontList2(List *L) { List p; ElemType x; *L = (List)malloc(sizeof(Lnode)); //生成一个空间,给头指针 (*L)->next = NULL; printf_s("请输入一组数据,以'0'为结束符\n"); scanf_s("%d", &x); while (x) { p = (List)malloc(sizeof(Lnode)); p->data = x; p->next = (*L)->next; (*L)->next = p; scanf_s("%d", &x); } }
区别:此处无明显区别
单链表尾插法:
不带头结点
void RearList1(List *L) { List p, r; ElemType x; *L = r = NULL; printf_s("请输入一组数据,以'0'为结束符\n"); scanf_s("%d", &x); while (x) { p = (List)malloc(sizeof(Lnode)); p->data = x; if (*L == NULL) { *L = p; } else { r->next = p; } r = p; scanf_s("%d", &x); } if (r) r->next = NULL; }
带头结点
void RearList2(List *L) { List r, p; ElemType x; *L = (List)malloc(sizeof(Lnode)); (*L)->next = NULL; r = *L; printf_s("请输入一组数据,以'0'为结束符\n"); scanf_s("%d", &x); while (x) { p = (List)malloc(sizeof(Lnode)); p->data = x; p->next = NULL; r->next = p; r = p; scanf_s("%d", &x); } }
区别:
- 不带头:结点需要单独考虑首元结点,及最后还要将最后一个元素指针域制空。
- 带头结点,一气呵成,将首元结点一起考虑进去。
查找第i个元素的值并返回地址
不带头结点
List GetElem1(List L) { List p; int i; int j = 1; p = L; printf_s("请输入要查找的位置\n"); scanf_s("%d", &i); while (p&&j<i){ p = p->next; j++; } if (!p|| i < 1) { printf_s("该位置不存在\n"); exit(1); } printf_s("该值为%d", p->data); return L; }
带头结点
List GetElem2(List L) { List p; int i; int j = 1; p = L->next; printf_s("请输入要查找的位置\n"); scanf_s("%d", &i); while (p&&j < i) { p = p->next; j++; } if (!p || i < 1) { printf_s("该位置不存在\n"); exit(1); } printf_s("该值为%d", p->data); return L; }
区别:无明显区别
按值查找
不带头结点
void LocateElem1(List L) { ElemType x; int i = 1; List p; p = L; printf_s("请输入要查找的值的位置\n"); scanf_s("%d", &x); while(p->data != x&&p) { p = p->next; i++; } if (!p) { printf_s("无该值\n"); exit(1); } else{ printf_s("该位置%d", i); } }
带头结点
void LocateElem2(List L) { ElemType x; int i = 1; List p; p = L->next; printf_s("请输入要查找的值的位置\n"); scanf_s("%d", &x); while (p->data != x && p) { p = p->next; i++; } if (!p) { printf_s("无该值\n"); exit(1); } else { printf_s("该位置%d", i); } }
区别:无明显区别
将元素插入指定位置
不带头结点
List ListInsert1(List L) { List p,q; int i; int j = 1; q = (List)malloc(sizeof(Lnode)); q->data = 666; p = L; printf_s("请输入要插入的位置\n"); scanf_s("%d", &i); while (p&&j < i-1) { p = p->next; j++; } if ((!p&&i!=0) || i < 1) { printf_s("该位置不存在\n"); exit(1); } else { if (i == 1) { q->next = L; L = q; } else { q->next = p->next; p->next = q; } } return L; }
带头结点
List ListInsert2(List L) { List p,q; int i; int j = 0; q = (List)malloc(sizeof(Lnode)); q->data = 666; p = L; printf_s("请输入要插入的位置\n"); scanf_s("%d", &i); while (p&&j < i-1) { p = p->next; j++; } if (!p || i < 1) { printf_s("该位置不存在\n"); exit(1); } q->next = p->next; p->next = q; return L; }
区别:
- 不带头结点:需要单独考虑首元结点,需要单独考虑首元结点,且判断条件还多了是否为空表
- 带头结点:可一起处理,不用考虑是否非空表
删除指定位置
不带头结点
List DeleteList1(List L) { List p; int i; int j = 1; p = L; printf_s("请输入要删除的位置\n"); scanf_s("%d", &i); while (p&&j < i - 1) { p = p->next; j++; } if (!p->next || i < 1) { printf_s("该位置不存在\n"); exit(1); } else { if (i == 1) { L = p->next ; } else{ p->next = p->next->next; } } return L; }
带头结点
List DeleteList2(List L) { List p; int i; int j = 0; p = L; printf_s("请输入要删除的位置\n"); scanf_s("%d", &i); //判断循环条件 while (p&&j < i - 1) { p = p->next; j++; } //判断表长 if (!p->next || i < 1) { printf_s("该位置不存在\n"); exit(1); } p->next = p->next->next; return L; }
区别:
- 不带头结点:需要单独判断首选结点
- 带头结点:可一起处理
总结:
凡是初始阶段,需要带头结点 “P =L->next” ,与不带头结点做法一样,没有用到头结点的功能;
凡是初始阶段,需要带头结点“P=L”,带头结点做法都比不带头结点方便,不用单独考虑特殊情况
好处:
便于首元结点的处理
首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其他位置一致,无须特殊处理;
便于空表的统一处理
无论空表是否为空,头指针都是指向头结点的非空指针,因此空表与非空白表的处理也就一样