- 线性表是n个数据元素的有限序列
- 线性表分为:
- 顺序表(数组):特点是访问速度快,搜索能力强
- 链表:静态链表,单链表,循环链表,双向链表
- 应用场景:通讯录;一元多项式;
线性表
c语言表示:
#ifndef LIST_H
#define LIST_H
typedef int Elem;
class List
{
public:
List(int size); //构造函数
~List(); //析构函数
void ClearList();
bool ListEmpty();//在c中没有bool类型,需要用宏定义定义BOOL
int ListLength();
bool GetElem(int i,Elem *e);//将下标为i的元素用e指针所指向的内存获取
int LocateElem(Elem *e);
bool PriorElem(Elem *currentElem, Elem *preElem);
bool NextElem(Elem *currentElem, Elem *nextElem);
void ListTraverse();
bool ListInsert(int i,Elem *e);
bool ListDelete(int i,Elem *e);
private:
int *m_pList; //指向一块内存
int m_iSize; //内存多大
int m_iLength;//线性表长度
};
#endif
#include"List.h"
#include<iostream>
using namespace std;
List::List(int size)
{
m_iSize=size;
m_pList = new int[m_iSize];
m_iLength = 0;
}
List::~List()
{
delete []m_pList;//释放数组
m_pList=NULL;
}
void List::ClearList()
{
m_iLength=0;
}
bool List::ListEmpty()
{
if(m_iLength==0)
{
return true;
}
else{
return false;
}
//return m_iLenght==0?true:false;
}
int List::ListLength()
{
return m_iLength;
}
bool List::GetElem(int i,Elem *e)
{
if(i<0||i>=m_iSize)
{
return false;
}
*e =m_pList[i];
return true;
}
int List::LocateElem(Elem *e)
{
for(int i=0;i<m_iLength;i++)
{
if(m_pList[i] ==*e)
{
return i;
}
}
return -1;
}
bool List::PriorElem(Elem *currentElem, Elem *preElem)
{
int temp= LocateElem(currentElem);
if(temp==-1)
{
return false;
}
else
{
if(temp==0)//第一个位置没有前驱
{
return false;
}
else{
*preElem = m_pList[temp-1];
return true;
}
}
}
bool List::NextElem(Elem *currentElem, Elem *nextElem)
{
int temp= LocateElem(currentElem);
if(temp==-1)
{
return false;
}
else
{
if(temp==m_iLength-1)//最后一个元素没有后继
{
return false;
}
else{
*nextElem = m_pList[temp+1];
return true;
}
}
}
void List::ListTraverse()
{
for(int i=0;i<m_iLength;i++)
{
cout<<m_pList[i]<<endl;
}
}
bool List::ListInsert(int i,Elem *e)
{
if(i<0||i>m_iLength) // i=m_iLength即在线性表最后一个位置,不需要移动任何元素,直接插入即可
{
return false;
}
for(int k=m_iLength-1;k>=i;k--)//从后到前移动
{
m_pList[k+1]=m_pList[k];
}
m_pList[i]=*e;
m_iLength++;
return true;
}
bool List::ListDelete(int i,Elem *e)
{
if(i<0||i>=m_iLength)//与上述有区别注意
{
return false;
}
*e= m_pList[i];
for(int k=i+1;k<m_iLength;k++)//从前到后移动
{
m_pList[k-1]=m_pList[k];
}
m_iLength--;
return true;
}
使线性表适用于其他类型,例如coordinate类型
- 对于list的函数声明,把数据类型改为coordinate类即可
int LocateElem(Coordinate *e);
- 需要修改的函数体:
- 遍历函数: 遍历时输出coordinate类型得元素,使用cout输出要提前重载操作符
void List::ListTraverse()
{
for(int i=0;i<m_iLength;i++)
{
cout<<m_pList[i]<<endl;//能否这样输出取决于是否重载了操作符
//这样也可以:m_pLit[i].printCoordinate()
}
}
- 比较查找元素函数 :对于coordinate的==操作要重载
int List::LocateElem(Coordinate *e)
{
for(int i=0;i<m_iLength;i++)
{
if(m_pList[i] ==*e)//需要堆coordiane做比较==运算符的重载
{
return i;
}
}
return -1;
}
- 其他函数体不变
- 如何重载?:
class Coordinate
{
public:
friend ostream &operator<<(ostream &out,Coordinate &coor);
Coordinate(int x=0, int y=0);//默认构造函数
void printCoordinate();
bool operator==(Coordinate &coor);
private:
int m_iX;
int m_iY;
};
#include"Coordinate.h"
#include<iostream>
using namespace std;
Coordinate::Coordinate(int x,int y)
{
m_iX=x;
m_iY=y;
}
void Coordinate::printCoordinate()
{
cout<<"("<<m_iX<<","<<m_iY<<")";
}
ostream &operator<<(ostream &out,Coordinate &coor)
{
out<<"("<<coor.m_iX<<","<<coor.m_iY<<")";
return out;
}
bool Coordinate::operator==(Coordinate &coor)
{
if(this->m_iX==coor.m_iX&&this->m_iY==coor.m_iY)
{
return true;
}
else{
return false;
}
}
- 测试:
// 线性表 顺序表
#include<iostream>
#include<stdlib.h>
#include"List.h"
using namespace std;
int main()
{
//3 5 7 2 9 1 8
Coordinate e1(3,5),e2=(5,7),e3=(6,8);
List *list1=new List(10);
list1->ListInsert(0,&e1);
list1->ListInsert(1,&e2);
list1->ListInsert(2,&e3);
Coordinate temp;
list1->ListTraverse();
delete list1;
system("pause");
return 0;
}
链表
- 单链表:结点有指针域数据域
- 循环链表:最后一个结点指针域又指向头结点
- 双向链表:结点有数据域,两个指针域
- 静态链表:没有指针的情况下用数组完成
单链表实现:
#ifndef NODE_H
#define NODE_H
class Node
{
public:
int data;
Node *next;
void printNode();
};
void Node::printNode()
{
cout<<data<<endl;
}
#endif // NODE_H
#ifndef LIST_H
#define LIST_H
#include"Node.h"
class List
{
public:
List();
~List();
void ClearList();
bool ListEmpty();
int ListLength();
bool GetElem(int i,Node *pNode);
int LocateElem(Node *pNode);
bool PriorElem(Node *pcurrentNode, Node *pPreNode);
bool NextElem(Node *pcurrentNode, Node *pNextNode);
void ListTraverse();
bool ListInsert(int i,Node *pNode);//指定位置插入
bool ListDelete(int i,Node *pNode);
bool ListInsertHead(Node *pNode);
bool ListInsertTail(Node *pNode);
private:
Node *m_pList; //指向一块内存
int m_iLength;//线性表长度
};
List::List()
{
//定义一个头结点,通过头结点操控整个链表
m_pList = new Node;
m_pList->data = 0;
m_pList->next=NULL;
m_iLength=0;//该头结点置空,不算在链表长度之中
}
List::~List()
{
//清除所有节点(包括头结点)
ClearList();
delete m_pList;
m_pList=NULL;
}
void List::ClearList()
{
//清除除了头结点所有节点,不断找下线删除
Node *currentNode= m_pList->next;
while(currentNode!=NULL)
{
Node *temp = currentNode->next;
delete currentNode;
currentNode=temp;
}
m_pList->next=NULL;
}
bool List::ListEmpty()
{
if(m_iLength==0)
{
return true;
}
else{
return false;
}
}
int List::ListLength()
{
return m_iLength;
}
bool List::ListInsertHead(Node *pNode)
{
Node *temp =m_pList->next;
Node *newNode =new Node;//从堆中申请内存,从栈中申请函数执行完后内存会被回收掉,所以一定要从堆中申请内存
if(newNode==NULL)
{
return false;
}
newNode->data=pNode->data;
m_pList->next = newNode;//insert
newNode->next=temp;
m_iLength++;
return true;
}
bool List::ListInsertTail(Node *pNode)
{
Node *currentNode= m_pList;
while(currentNode->next!=NULL)
{
currentNode=currentNode->next;
}
Node *newNode =new Node;//从堆中申请内存,从栈中申请函数执行完后内存会被回收掉,所以一定要从堆中申请内存
if(newNode==NULL)
{
return false;
}
newNode->data=pNode->data;
newNode->next=NULL;
currentNode->next=newNode;
m_iLength++;
return true;
}
bool List::ListInsert(int i,Node *pNode)
{
if(i<0||i>m_iLength)
{
return false;
}
Node *currentNode= m_pList;
for(int k=0;k<i;k++)
{
currentNode=currentNode->next;
}
Node *newNode =new Node;
if(newNode==NULL)
{
return false;
}
newNode->data=pNode->data;
newNode->next=currentNode->next;
currentNode->next=newNode;
return true;
}
bool List::ListDelete(int i,Node *pNode)
{
if(i<0||i>=m_iLength)
{
return false;
}
Node *currentNode=m_pList;
Node *currentNodeBefore =NULL;
for(int k=0;k<=i;k++)
{
currentNodeBefore=currentNode;
currentNode=currentNode->next;
}
currentNodeBefore->next=currentNode->next;
pNode->data=currentNode->data;
delete currentNode;
currentNode=NULL;
m_iLength--;
return true;
}
bool List::GetElem(int i,Node *pNode)
{
if(i<0||i>=m_iLength)
{
return false;
}
Node *currentNode=m_pList;
Node *currentNodeBefore =NULL;
for(int k=0;k<=i;k++)
{
currentNodeBefore=currentNode;
currentNode=currentNode->next;//找到第i个节点
}
pNode->data=currentNode->data;
return true;
}
int List::LocateElem(Node *pNode)
{
Node *currentNode = m_pList;
int count=0;//计数变量
while(currentNode->next!=NULL)
{
currentNode=currentNode->next;
if(currentNode->data==pNode->data)
{
return count;//若count为0就return即返回的是头结点后的第一个结点
}
count++;
}
return -1;
}
bool List::PriorElem(Node *pcurrentNode, Node *pPreNode)
{
Node *currentNode = m_pList;
Node *tempNode = NULL;
while(currentNode->next!=NULL)
{
tempNode=currentNode;
currentNode=currentNode->next;
if(currentNode->data==pcurrentNode->data)
{
if(tempNode==m_pList)//如果前驱就是头结点,认定找不到该节点的前驱
{
return false;
}
pPreNode->data=tempNode->data;
return true;
}
}
return false;
}
bool List::NextElem(Node *pcurrentNode, Node *pNextNode)
{
Node *currentNode = m_pList;
while(currentNode->next!=NULL)
{
currentNode=currentNode->next;
if(currentNode->data==pcurrentNode->data)
{
if(currentNode->next==NULL)//找到的当前结点已经是最后一个结点
{
return false;
}
pNextNode->data=currentNode->next->data;
return true;
}
}
return false;
}
void List::ListTraverse()
{
Node *currentNode=m_pList;
while(currentNode->next!=NULL)
{
currentNode=currentNode->next;
currentNode->printNode();
}
}
#endif
测试:
// ÏßÐÔ±í ˳Ðò±í
#include<iostream>
#include<stdlib.h>
#include"List.h"
using namespace std;
int main()
{
Node node1,node2,node3,node4;
node1.data=3;node2.data=4;node3.data=5;node4.data=6;
Node node5;
node5.data=7;
List *pList = new List();
// pList->ListInsertHead(&node1);
// pList->ListInsertHead(&node2);
// pList->ListInsertHead(&node3);
// pList->ListInsertHead(&node4); //遍历后输出结果为 6 5 4 3
pList->ListInsertTail(&node1);
pList->ListInsertTail(&node2);
pList->ListInsertTail(&node3);
pList->ListInsertTail(&node4); //遍历后输出结果为 3 4 5 6
pList->ListInsert(1,&node5);
Node temp;
//pList->ListDelete(1,&temp);
pList->NextElem(&node5,&temp);
pList->ListTraverse();
cout<<"temp:"<<temp.data<<endl;
delete pList;
pList=NULL;
system("pause");
return 0;
}
链表应用——通讯录
- 结点Node的data是person类型
newNode->data=pNode->data;
对于这样data的赋值操作,要重载f(currentNode->data==pNode->data)
对于data之间的比较操作,要重载void Node::printNode() { cout<<data<<endl; }
对于打印节点操作,要重载cout
person.h
#ifndef PERSON_H_INCLUDED
#define PERSON_H_INCLUDED
#include<string>
#include<ostream>
using namespace std;
class Person
{
friend ostream &operator<<(ostream &out,Person &person);
public:
string name;
string phone;
Person &operator = (Person &person);
bool operator ==(Person &person);
};
ostream &operator<<(ostream &out,Person &person)
{
out<<person.name<<"----" <<person.phone<<endl;
return out;
}
Person &Person::operator = (Person &person)
{
this ->name = person.name;
this->phone=person.phone;
return *this;
}
bool Person::operator==(Person &person)
{
if(this->name==person.name&&this->phone==person.phone)
{
return true;
}
return false;
}
#endif // PERSON_H_INCLUDED
测试
#include<iostream>
#include<stdlib.h>
#include"List.h"
using namespace std;
int main()
{
Node node1;
node1.data.name="sss";
node1.data.phone="123456";
Node node2;
node2.data.name="sjx";
node2
.data.phone="238956";
List *pList= new List();
pList->ListInsertTail(&node1);
pList->ListInsertTail(&node2);
pList->ListTraverse();
delete pList;
pList=NULL;
system("pause");
return 0;
}
一切就绪之后,开始编写通讯录代码
通讯录.cpp
#include<iostream>
#include<stdlib.h>
#include"List.h"
using namespace std;
int menu()
{
//显示通讯录功能菜单
cout<<"功能菜单"<<endl;
cout<<"1.新建联系人"<<endl;
cout<<"2.删除联系人"<<endl;
cout<<"3.浏览通讯录"<<endl;
cout<<"4.退出通讯录"<<endl;
cout<<"请输入:"<<endl;
int order=0;
cin>>order;
return order;
}
void createPerson(List *pList)
{
Node node ;
Person person;
cout<<"请输入姓名 :";
cin>>person.name;
cout<<"请输入电话 :";
cin>>person.phone;
node.data=person;
pList->ListInsertTail(&node);
}
void deletePerson(List *pList,Node *temp)
{
Node node;
cout << "请输入要删除的联系人的姓名:" << endl;
cin >> node.data.name;
cout << "请输入要删除的联系人的电话:" << endl;
cin >> node.data.phone;
int locate = pList->LocateElem(&node);//先查找联系人的位置
if(locate == -1)
{
cout << "没找到此联系人" << endl;
return;
}
pList->ListDelete(locate,temp);//删除联系人
cout << "成功删除联系人" << endl;
}
int main()
{
int userOrder = 0;
List *pList= new List();
while(userOrder!=4)
{
userOrder = menu();
Node temp;
switch(userOrder)
{
case 1:
cout<<"用户指令---->>新建联系人"<<endl;
createPerson(pList);
break;
case 2:
cout<<"用户指令---->>删除联系人"<<endl;
deletePerson(pList,&temp);
break;
case 3:
cout<<"用户指令---->>浏览通讯录"<<endl;
pList->ListTraverse();
break;
case 4:
cout<<"用户指令---->>退出通讯录"<<endl;
break;
}
}
delete pList;
pList=NULL;
return 0;
}
对于课程布置的删除作业,可参考https://www.imooc.com/qadetail/163402