数据结构与算法 浙江大学
2.1线性表的链式存储
C语言实现
#include<iostream>
using namespace std;
typedef int ElementType; // ElementType 可定义为任意类型
typedef struct LNode* List;
//template<class ElementType>
struct LNode
{
ElementType Data;
List Next;
};
// List L;
List MakeEmpty(); //初始化链表
int Length(List L); //遍历链表求链表长度
List FindKth(int K, List L); //返回序号K的值
List Find(ElementType X, List L); // 按值查找
List Insert(ElementType X, int i, List L); //将 X插入到第 i-1(i>0)个结点之后
List Delete(int i, List L);
void Print(List L);
List MakeEmpty()
{
List L = (List)malloc(sizeof(struct LNode));
// List L = new LNode;
L = nullptr;
return L;
}
//求表长
int Length(List L)
{
List p = L;
int len = 0;
//从表头开始遍历,直到最后一个(nullptr),计数
while (p)
{
p = p->Next;
++len;
}
return len;
}
List FindKth(int K, List L) //返回序号K的值
{
List p = L;
int len = 1; //从1开始
while (p && len < K) //p为空指针时 或 当前序号>=K时 跳出循环
{
p= p->Next;
len++;
}
if (len == K) //跳出循环后检查 是否找到K
{
return p;
}
else //没找到K 返回空指针
{
return nullptr;
}
}
List Find(ElementType X, List L) // 按值查找
{
List p = L;
while (p && p->Data != X) //p为空指针时 或 当前值=X时 跳出循环
{
p = p->Next;
}
return p;
}
//将 X插入到第 i-1(i>0)个结点之后
List Insert(ElementType X, int i, List L)
{
List s, p;
if (i == 1) //表头插入情况
{
// List s = MakeEmpty();//这个会保错。
//插入s
s = (List)malloc(sizeof(struct LNode));//申请内存
s->Data = X; //给s赋值
s->Next = L;
return s;
}
//不是表头情况
p = FindKth(i-1, L); // 找到i-1结点
if (p) //找到i-1
{
//插入s
s = (List)malloc(sizeof(struct LNode));
s->Next = p->Next;
s->Data = X;
p->Next = s;
return L;
}
else
{
cout << "结点错误" << endl;
return nullptr;
}
}
//将L的第i个元素删除,找到i-1个结点,i-1的next = i的next,释放i。
List Delete(int i, List L)
{
List s,p;
//删除表头,没有i-1的情况
if (i == 1)
{
s = L;
if (L != nullptr) //当前表不为空,删除表头
{
L = L->Next;
}
else{ //当前表为空,无法删除,返回空指针
return nullptr;
}
free(s);
return L;
}
//i不是表头的情况,找到i-1,改变Next的赋值实现删除
p = FindKth(i-1, L);
if (p == nullptr)
{
cout<<"结点"<<i-1<<"不存在"<<endl;
}
else if(p->Next == nullptr)
{
cout<<"结点"<<i<<"不存在"<<endl;
}
else{
s = p->Next;
p->Next = s->Next;
free(s);
return L;
}
}
void PrintList(List L)
{
List t;
int flag = 1;
cout << "当前链表为:";
for (t = L; t; t = t->Next)
{
cout << t->Data << " ";
flag = 0;
}
if (flag)
cout << "NULL";
cout << endl;
}
int main()
{
List L = MakeEmpty();
PrintList(L);
L = Insert(11, 1, L);
L = Insert(25, 1, L);
L = Insert(33, 2, L);
L = Insert(77, 3, L);
PrintList(L);
}
C++写成类实现 即单链表
仿STL中list的接口
#pragma once
#include <iostream>
#include <string>
#include <list>
using namespace std;
typedef int DataType;
// template<class DataType>
struct Node
{
DataType data;
Node *next;
};
//元素编号从1开始
// template<class DataType>
class LinkList
{
public:
LinkList() //无参构造
{
head = new Node;
head = nullptr;
// head->next = nullptr;
this->size = 0;
}
LinkList(DataType elem)
{
head = new Node;
head->data = elem;
head->next = nullptr;
this->size = 1;
}
LinkList(LinkList & list) //拷贝构造
{
this->head = new Node;
this->head = list.head;
this->size = list.size;
}
LinkList(int size, DataType elem=0)
{
head = new Node;
head = nullptr;
// head->next = nullptr;
if (size > 0)//防止参数为负数
{
for (size_t i = 0; i < size; i++)
{
Push_back(elem);
}
}
this->size = Size();
}
~LinkList();
bool isEmpty()const; //链表是否为空
int Size(); //通过遍历获取链表长度
int getLen()const; //返回size
int Display()const; //打印当前链表
Node * FindKth(int K); //查找第K个结点 元素编号从1开始
Node * Find(DataType X); //查找值为X的第一个结点
Node * Front(); //获取第一个结点
Node * Back(); //获取最后一个结点
int Push_front(DataType elem); //头插
int Push_back(DataType elem); //尾插
int Insert(DataType elem, int pos, int num=1); //插入
int Pop_front(); //头删
int Pop_back(); //尾删
int Erase(int beg, int end=0); //删除
int Clear(); //清理链表
int Remove(DataType elem); //删除容器中所有与elem值匹配的元素。
int Reverse(); //链表前后翻转,倒置
int size{0};//初始值为0
Node *head;
};
LinkList::~LinkList()
{
Clear();
}
//返回链表长度
int LinkList::Size()
{
Node *currNode = head;
int len = 0;
while (currNode)
{
currNode = currNode->next;
++len;
}
this->size = len;
return len;
}
//打印链表
int LinkList::Display() const
{
cout << "当前链表元素为:";
int flag = 1;
int count = 0;
Node *t;
for (t = this->head; t; t = t->next)
{
cout << t->data << " ";
flag = 0;
if (++count % 10 ==0)
{
cout<<endl;
}
}
if (flag)
cout << "NULL";
cout << endl;
}
Node * LinkList::FindKth(int K)
{
Node *currNode = head;
int len = 1; //元素编号从1开始
while (currNode && len < K)
{
currNode = currNode->next;
++len;
}
if (len == K)
{
return currNode;
}
else
{
return nullptr;
}
}
Node * LinkList::Find(DataType X)
{
Node *currNode = head;
while (currNode && currNode->data != X)
{
currNode = currNode->next;
}
return currNode;
}
Node * LinkList::Front() //获取第一个结点
{
return this->head;
}
Node * LinkList::Back() //获取最后一个结点
{
return FindKth(this->size); //元素编号从1开始
}
int LinkList::Push_front(DataType elem)
{
Insert(elem,1);
}
int LinkList::Push_back(DataType elem)
{
if (isEmpty())
{
Insert(elem,1); //列表为空,相当于头插
}
else
{
Insert(elem,this->size + 1); //尾插,且序号从1开始,故插入到长度+1
}
}
int LinkList::Clear()
{
if (this->head == nullptr)
{
cout<<"链表当前已经为空,无需再clear "<<endl;
return -1;
}
Node *ptemp;
while (this->head)
{
ptemp = head->next;
delete head;
head = ptemp;
}
head = nullptr;
head->next == nullptr;
this->size = 0;
cout<<"clear链表完成!"<<endl;
return 0;
}
int LinkList::Insert(DataType elem, int pos, int num)
{
//插入一个的情况
if (1==num)
{
//需要插入的位置为pos,则需要将新结点的next指向结点pos,将结点pos-1的next指向新结点
Node * pnewNode, *preNode;//待插入的新结点, 前一个结点
//头插
if (pos == 1)
{
//备份头结点
preNode = this->head;
//创建待插入的新节点
pnewNode = new Node;
pnewNode->data = elem;
//新结点next指向头结点
pnewNode->next = preNode;
//更新头结点
this->head = pnewNode;
this->size++;
return 0;
}
//非 头插
preNode = FindKth(pos-1); //元素编号从1开始
if (preNode == nullptr)
{
cout << "不存在该结点" << pos-1 << endl;
return -1;
}
else
{
//创建待插入的新节点
pnewNode = new Node;
pnewNode->data = elem;
//新结点next指向 结点pos
pnewNode->next = preNode->next;
//将结点pos-1的next指向新结点
preNode->next = pnewNode;
}
this->size++;
return 0;
}
//异常情况
else if (num < 1)
{
cout<<"插入个数错误"<<endl;
return -1;
}
// 插入多个的情况,递归调用自己即可
else
{
for (size_t i = 0; i < num; i++)
{
Insert(elem,pos++);
}
}
return 0;
}
int LinkList::Pop_front() //头删
{
return Erase(1);
}
int LinkList::Pop_back() //尾删
{
return Erase(this->size);
}
int LinkList::Erase(int beg, int end)
{
//入参是区间的情况,
if (end)
{
//计算删除次数
int count = min(end-beg, this->size-beg) + 1;//防止end越界
if (count <= 0) //防止 end 大于 beg
{
cout << "beg 需小于 end"<<endl;
return -1;
}
//开始删除
for (size_t i = 0; i < count; i++)
{
Erase(beg); //连续删除时,删除的是相同的位置
}
return 0;
}
//入参是一个的情况,即删除一个
else
{
//需要删除的结点为beg,则结点beg-1的next 指向 结点beg+1,并释放结点i。考虑边界情况
Node * currNode, *preNode;//待删除的结点, 前一个结点
//头删
if (1 == beg)
{
if (!isEmpty())
{
//备份需要删除的结点
currNode = this->head;
//head结点后移
this->head = this->head->next;
this->size--;
//释放已删除的结点
delete currNode;
return 0;
}
else
{
cout<<"无法删除,列表为空列表"<<endl;
return -1;
}
}
//非 头删
preNode = FindKth(beg-1);
if (preNode && preNode->next)
{
//备份需要删除的结点
currNode = preNode->next;
//结点i-1的next 指向 结点i+1
preNode->next = currNode->next;
//释放已删除的结点
delete currNode;
this->size--;
return 0;
}
else
{
cout<<"无该结点,无法删除"<<endl;
return -1;
}
}
}
int LinkList::getLen()const
{
return this->size;
}
bool LinkList::isEmpty()const
{
if (this->head == nullptr) //头指针为空,链表为空
{
return true;
}
else
{
return false;
}
}
int LinkList::Remove(DataType elem) //删除容器中所有与elem值匹配的元素。
{
Node * currNode = head;
int len = 1;
while (currNode)
{
if (currNode->data == elem) //找到则删除,并继续往后,且len不变
{
Erase(len);
// currNode指向的结点已删除,需要重新赋值
currNode = FindKth(len);
}
else //未找到则并继续往后
{
len ++;
currNode = currNode->next;
}
}
return 0;
}
int LinkList::Reverse() //链表前后翻转,倒置
{
if (size <= 1)
{
return -1;
}
Node *preNode = head, *currNode = preNode->next, *temp = nullptr;
//第一个结点断开 即next指向空
head->next = nullptr;
while (currNode) //currNode为最后一个结点的next时,跳出循环
{
//备份curr的next
temp = currNode->next;
//替换curr的next为前一个结点
currNode->next = preNode;
//更新preNode currNode两个指针
preNode = currNode;
currNode = temp;
}
//最后一个结点赋值给头指针,
head = preNode;
//翻转完成,依旧通过头指针访问链表
}
//一些测试
void test()
{
cout<<"STL list<int>"<<endl;
list<int> l1(5,5);
l1.front();
l1.back();
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);
l1.push_front(1);
l1.push_front(2);
l1.push_front(3);
l1.pop_back();
list<int> l2;
cout<<"l1.size "<<l1.size()<<endl;
cout<<"l1.size "<<l2.size()<<endl;
cout<<"-------"<<endl;
}
void test002()
{
cout<<"my list"<<endl;
LinkList mylist(5,5);
mylist.Display();
cout<<mylist.getLen()<<endl;
cout<<mylist.Size()<<endl;
mylist.Push_front(1);
mylist.Push_front(2);
mylist.Push_front(3);
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Push_back(1);
mylist.Push_back(2);
mylist.Push_back(3);
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Insert(6,4);
mylist.Insert(6,4);
mylist.Insert(6,4);
mylist.Insert(6,12,3);
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Insert(6,100);
mylist.Insert(6,100,-1);
mylist.Pop_back();
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Pop_back();
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Pop_back();
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Pop_front();
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Pop_front();
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Pop_front();
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Erase(1);
mylist.Erase(2);
mylist.Erase(3);
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Erase(7,2);
mylist.Erase(6,8);
mylist.Display();
cout<<mylist.getLen()<<endl;
mylist.Remove(5);
mylist.Display();
cout<<mylist.getLen()<<endl;
cout<<mylist.Size()<<endl;
}
void test003()
{
int * ptrnull = NULL;
cout << "ptrnull "<< ptrnull <<endl;
int * ptr = new int(1);
cout << "ptr "<< ptr <<endl;
cout << "*ptr "<< *ptr <<endl;
delete ptr;
cout<<"delete ptr:"<<endl;
cout << "ptr "<< ptr <<endl;
cout << "ptr "<< ptr <<endl;
cout << "*ptr "<< *ptr <<endl;
cout << "*ptr "<< *ptr <<endl;
ptr = nullptr;
int* ptr4 =new int;
cout << "ptr4 "<< ptr4 <<endl;
cout << "*ptr4 "<< *ptr4 <<endl;
ptr = new int(13);
cout << "ptr "<< ptr <<endl;
cout << "*ptr "<< *ptr <<endl;
}
void test004()
{
LinkList mylist;
mylist.Push_back(1);
mylist.Push_back(2);
mylist.Push_back(3);
mylist.Push_back(4);
mylist.Push_back(5);
mylist.Push_back(6);
mylist.Display();
mylist.Reverse();
mylist.Display();
}
int main()
{
test004();
return 0;
}
链表倒置的流程图
参考链接
1 数据结构(二)—— 线性结构(1):线性表
2 单链表C++实现代码
3 单链表的C++实现(采用模板类)