好几天没有码了,今天弄好了自习室,继续了考研复习,晚上回来敲一敲代码,单链表的相关操作都整理了,后续在码双链表,循环链表等的函数,不过和单链表相比大同小异,甚至更加方便
头文件一共包含如下操作:
- 单链表节点定义LNode
- 求表长getLength
- 在给定指针p前面插入结点frontInsert
- 在给定指针p后面插入结点behindInsert
- 头插法函数head_insert,手动输入
- 尾插法函数tail_insert,手动输入
- 给空表自动赋值auto_assignment
- 遍历函数printList
- 判空函数emptyList
- 按值查找locateElem
- 按位查找getElem
- 删除节点deleteElem
个人认为这些操作里边比较精彩的是3.在指针p之前插入节点和12.删除节点。3涉及一个时间复杂度的优化,偷梁换柱,o(n)->o(1);12涉及一个细节的处理,如果删除的节点是链表最后一位,则必须单独处理,否则会报错,因为无法将末尾的指针变为NULL,这会影响求表长以及遍历函数的使用,因这些函数都是靠NULL来判断链表的结束的。
代码如下:
#include<iostream>
using namespace std;
#define MAX 25//用于控制链表的最大表长
//带头结点的单链表操作
//定义单链表结点
struct LNode {
int data;
LNode* next;
};
//求表长getLength
int getLength(const LNode* L) {
int i = 0;
LNode* s = (LNode*)(L->next);
while (i < MAX) {
if (s == NULL)break;
i++;
s = s->next;
}
return i;
}
//在给定指针p前面插入结点
bool frontInsert(LNode* p,int e) {
LNode *s = (LNode*)malloc(sizeof(LNode));
if (s == NULL)return false;
s->data = p->data;
s->next = p->next;
p->next = s;
p->data = e;
return true;
}
//在给定指针p后面插入结点
bool behindInsert(LNode* p,int e) {
LNode *s = (LNode*)malloc(sizeof(LNode));
if (s == NULL)return false;
s->data = e;
//两步插入节点
s->next = p->next;
p->next = s;
return true;
}
//头插法函数head_insert,手动输入,初始链表为空
//输入-1代表结束输入
bool head_insert(LNode* L) {
L->next = NULL;
LNode* s;
int x;
while (1) {
cin >> x;
if (x == -1)break;
s = (LNode*)malloc(sizeof(LNode));
if (s == NULL )return false;
s->next = L->next;
L->next = s;
s->data = x;
}
return true;
}
//尾插法函数tail_insert,手动输入,初始链表为空
bool tail_insert(LNode* L) {
L->next = NULL;
int x=0;
LNode *s = L;//s指向最后一个节点
while (1) {//输入-1结束插入操作
cin >> x;
if (x == -1)break;
s->next = (LNode*)malloc(sizeof(LNode));
if (s == NULL)return false;
s->next->data = x;
s->next->next = NULL;
s = s->next;
}
return true;
}
//给空表自动赋值auto_assignment
//单链表L,num表示自动尾插的节点个数
bool auto_assignment(LNode* L, int num=20) {
if (num<1||num > MAX||L->next!=NULL) return false;
LNode *s = L;//s指向最后一个节点
for (int i = 0; i < num;i++) {
s->next = (LNode*)malloc(sizeof(LNode));
s->next->next = NULL;
s->next->data = rand() % 100;
s = s->next;
}
return true;
}
//遍历函数printList
bool printList(const LNode* L) {
if (L->next == NULL)return false;
LNode*s = L->next;
int i = 0;
while(s!=NULL) {
cout << s->data << " " ;
s = s->next;
if (i % 10 == 9)cout << endl;
i++;
}
cout << endl;
return true;
}
//判空函数
bool emptyList(const LNode* L) {
if (L->next == NULL) {
return true;
}
return false;
}
//按值查找locateElem
//查找成功返回指针,失败返回NULL
LNode* locateElem(const LNode* L, int e) {
LNode* s = (LNode*)L->next;
if (s == NULL) {//表空则直接结束,NULL
return NULL;
}
for (int i = 1; i <= getLength(L);i++) {
if (e == s->data)return s;//成功则返回指针
s = s->next;
}
return NULL;//未找到则返回NULL
}
//按位查找getElem,查找第i个元素
//成功:返回结点指针,失败:返回NULL;
LNode *getElem(const LNode* L,int i) {
LNode* s = (LNode *)(L->next);
if (i<1||i>getLength(L)) {//i的范围不合理
return NULL;
}
else {
for (int j = 1; j <i;j++) {//向后遍历
s = s->next;
}
return s;
}
}
//删除节点操作
//给定一个节点的指针,删除该指针指向的节点
bool deleteElem(const LNode* L, LNode* p) {
if(p->next!=NULL){
p->data = p->next->data;
p->next = p->next->next;
free(p->next);
}
else {//如果删除的节点是链表最后一个,那么需要从表头开始遍历
LNode* s = L->next;
for (int i = 1; i < MAX;i++) {
if (s->next==p) {
s->next = NULL;
free(p);
break;
}
s = s->next;
}
}
return true;
}
疲惫,准备洗洗睡了。。。。。。
加油奥力给~~~~~~~~~~~~~