数据结构-链表的基本实现
1.单链表
带头结点
InitList(LinkList& L) 初始化,时间复杂度O(1)
ListInsert(LinkList& L, int i, ElemType e) 指定位序后插,时间复杂度O(n)
ListDelete(LinkList& L, int i, ElemType& e) 位序删除元素,传回结点元素,时间复杂度O(n)
GetElem(LinkList L, int i) 按位查找,传回第一个结点元素等e的结点,时间复杂度O(n)
#include <iostream>
using namespace std;
#define ElemType int
#define MaxSize 2
typedef struct LNode {
ElemType data;
LNode* next;
}LNode, * LinkList;
//初始化,时间复杂度O(1)
bool InitList(LinkList& L) {
L = new LNode; //创建带头结点
if (L == NULL) {
printf("内存分配失败\n");
return false;
}
L->next = NULL;
return true;
}
//指定位序后插,时间复杂度O(n)
bool ListInsert(LinkList& L, int i, ElemType e) {
if (i < 1) {
printf("插入位置错误,至少在第一位插入\n");
return false;
}
LNode* p = L;//定义当前指针指向头结点
int j = 0;//当前指针位于第几位结点
while (p != NULL && j < i - 1) { //循环遍历,使当前指针指向插入位置的前一位
p = p->next;
j++;
}
/*****************/
if (p == NULL) { //避免超出范围
cout << "插入位置错误,最多在长度+1位(结尾)插入" << endl;
return false;
}
//先令插入的结点next指向下一个结点
//再让上一个结点(p)指向插入的结点
LNode* s = new LNode;
s->data = e;
s->next = p->next;
p->next = s;
/*****************/ //可以直接用后面“InsertNextNode”函数简化
return true;
}
//位序删除元素,传回结点元素,时间复杂度O(n)
bool ListDelete(LinkList& L, int i, ElemType& e) {
if (i < 1) {
printf("位序错误,位序从1开始\n");
return false;
}
LNode* p = L;
int j = 0;
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
//判断第i-1个结点是否存在
//判断是否结尾(if i = 4,长度为3,i-1个结点为结尾,i超出范围)
if (p == NULL || p->next == NULL) {
printf("位序超出范围\n");
return false;
}
LNode* d = p->next;
e = d->data;
p->next = d->next;
delete d; //释放结点空间
return true;
}
//按位查找,传回第一个结点元素等e的结点,时间复杂度O(n)
LNode* GetElem(LinkList L, int i) {
if (i < 1) {
cout << "位序错误" << endl;
return NULL;
}
LNode* p = L;
int j = 0;
while (p != NULL && j < i) {
p = p->next; //if i>长度,p=NULL
j++;
}
return p;
}
void PrintList(LinkList L) {
printf("链表元素为:");
for (LNode* p = L->next; p != NULL; p = p->next) {
printf("%d ", p->data);
}
printf("\n");
}
void Insert(LinkList&L) {
int i;
ElemType e;
printf("请输入插入位置和元素:");
scanf("%d%d", &i,&e);
ListInsert(L, i, e);
PrintList(L); //调用函数,输出链表
}
void Delete(LinkList &L) {
int i;
ElemType e;
printf("请输入需要删除元素的位置:");
scanf("%d", &i);
if (ListDelete(L, i, e)) {
printf("第%d位元素:%d 已删除!\n", i, e);
}
else {
printf("删除失败!\n");
}
}
void Search(LinkList L) {
int i;
LNode* p;
printf("请输入元素位置查找:");
scanf("%d", &i);
p = GetElem(L, i); //不存在则返回NULL
if (p != NULL) {
printf("第%d位元素为:%d\n", i, p->data);
}
else {
printf("位序超出范围!\n");
}
}
void menu()
{
printf("*********** 1.指定位序插入 2.指定位序删除 3.打印链表 4.指定位序查找 ***********\n");
}
int main()
{
LinkList L;
int choice;
InitList(L);
while (true)
{
menu();
printf("请输入菜单序号:");
scanf("%d", &choice);
switch (choice)
{
case 1:Insert(L); break;
case 2:Delete(L); break;
case 3:PrintList(L); break;
case 4:Search(L); break;
default:printf("输入错误!!!\n");
}
}
}
其他操作
//指定结点前插,时间复杂度O(1)
/*因为指定结点的前一个结点是未知的
所以无法实现前驱结点指针->next = s
但可以指定结点称为前驱结点,交换数据
*/
bool InsertPriorNode(LNode* p, ElemType e) {
if (p == NULL) {
printf("指定结点为空\n");
return false;
}
LNode* s = new LNode;
s->data = p->data; //交换数据
p->data = e;
s->next = p->next;
p->next = s;
return true;
}
//按值查找,传回第一个结点元素等e的结点,时间复杂度O(n)
LNode* LocateElem(LinkList L, ElemType e) {
LNode* p = L->next;//当前指针指向第一数据结点
while (p != NULL && p->data != e) {
p = p->next;
}
return p;
}
//获取链表长度,时间复杂度O(n)
int ListLength(LinkList L) {
LNode* p = L;
int len = 0;
while (p->next != NULL) {
p = p->next;
len++;
}
/*或者
for (LNode* p = L; p->next != NULL; p = p->next) {
len++;
}
*/
return len;
}
不带头结点
bool InitList(LinkList& L) {
L = NULL; //空表,防止脏数据,同时也为了后面插入操作,结点指向NULL
return true;
}
//指定位序插入,时间复杂度O(n)
bool ListInsert(LinkList& L, int i, ElemType e) {
if (i < 1) {
cout << "插入位置错误,至少在第一位插入" << endl;
return false;
}
else if (i == 1) {
LNode* s = new LNode;
s->data = e;
s->next = L; //第一次插入结点时,L=NULL
L = s;
return true;
}
LNode* p = L;//定义当前指针指向第1个结点
int j = 1;//当前指针指向第1位结点
while (p != NULL && j < i - 1) { //循环遍历,使当前指针指向插入位置的前一位
p = p->next;
j++;
}
if (p == NULL) { //避免超出范围
cout << "插入位置错误,最多在长度+1位插入" << endl;
return false;
}
//先令插入的结点next指向下一个结点
//再让上一个结点(p)指向插入的结点
LNode* s = new LNode;
s->data = e;
s->next = p->next;
p->next = s;
return true;
}