您的位置:首页 > 理论基础 > 数据结构算法

【数据结构与算法003】基本数据结构——线性表(链表)

2016-11-04 16:55 916 查看
线性表分为顺序表(数组)和链表,其中链表包括静态链表(对于有些计算语言没有指针)、单链表、循环链表和双向链表,我们主要学习单链表。

一、顺序表的基本操作

首先看一下线性顺序表的基本操作List.h

#ifndef LIST_H
#define LIST_H

/************************************************************************/
/* 线性表--顺序表

3 5 7 2 9 1 8

前驱 后继

BOOL InitList(List **list); //创建线性表
void DestroyList(List *list); //销毁线性表
void ClearList(List *list); //清空线性表
BOOL ListEmpty(List *list); //判断线性表是否为空
int ListLength(List *list); //获取线性表长度
BOOL GetElem(List *list,int i,Elem *e); //获取指定元素
int LocateElem(List *list,Elem *e); //寻找第一个满足e的数据元素的位序
BOOL PriorElem(List *list,Elem *currentElem,Elem *preElem); //获取指定元素的前驱
BOOL NextElem(List *list,Elem *currentElem,Elem *nextElem); //获取指定元素的后继
BOOL ListInsert(List *list,int i,Elem *e); //在第i个位置插入元素
BOOL ListDelete(List *list,int i,Elem *e); //在删除第i个位置的元素
void ListTraverse(List *list); //遍历线性表

*/
/************************************************************************/

class List{

public:
List(int size);
~List();
void ClearList();
bool ListEmpty();
int ListLength();
bool GetElem(int i, int *e);
int LocateElem(int *e);
bool PriorElem(int *currentElem, int *preElem);
bool NextElem(int *currentElem, int *nextElem);
void ListTraverse();
bool ListInsert(int i, int *e);
bool ListDelete(int i, int *e);

private:
int *m_pList;
int m_iSize;
int m_iLength;
};

#endif
List的具体实现List.cpp

#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_iLength == 0 ? true : false;
}

int List::ListLength(){

return m_iLength;
}

bool List::GetElem(int i, int *e){

if (i < 0 || i >= m_iSize)
{
return false;
}

*e = m_pList[i];
return true;
}

int List::LocateElem(int *e){

for (int i = 0; i < m_iLength; i++)
{
if (m_pList[i] == *e)
{
return i;
}
}
return -1;
}

bool List::PriorElem(int *currentElem, int *preElem){

int temp = LocateElem(currentElem);

if (temp == -1 || temp == 0)
{
return false;
}
else
{
*preElem = m_pList[temp - 1];
return true;
}

}

bool List::NextElem(int *currentElem, int *nextElem){

int temp = LocateElem(currentElem);

if (temp == -1 || 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];
}
}

bool List::ListInsert(int i, int *e){

if (i<0 || 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, int *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;
}

顺序表的优点:在进行遍历和寻址的时候非常快速,效率很高。

缺点:显而易见,当我们想往顺序表中插入一个元素的时候,当前位置向后的所有元素都要向后移动一个位置,这样数据才能顺利地插入进去,删除时同理。那么如何才能避免现象呢?我们需要用到链表。

二、链表的基本操作

我们主要学习单链表,单链表 = 顺序表 + 链表节点,主要操作掌握插入、删除节点。

链表节点Node.h

#ifndef NODE_H
#define NODE_H

class Node{

public:
int data; //数据域
Node *next; //指针域
void printNode();
};

#endif


链表节点Node.cpp

#include "Node.h"
#include <iostream>
using namespace std;

void Node::printNode(){

cout << data << endl;
}
顺序表List.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;
};

#endif


顺序表List.cpp

#include "List.h"
#include <iostream>
using namespace std;

List::List(){

m_pList = new Node;
m_pList->data = 0;
m_pList->next = NULL;
m_iLength = 0;
}

bool List::ListEmpty(){

if (m_iLength == 0)
{
return true;
}
else
{
return false;
}
}

int List::ListLength(){

return m_iLength;
}

void List::ClearList(){

Node *currentNode = m_pList->next;

while (currentNode != NULL)
{
Node *temp = currentNode->next;
delete currentNode;
currentNode = temp;
}
m_pList->next = NULL;
}

List::~List(){

ClearList();
delete m_pList;
m_pList = NULL;
}

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;
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;
m_iLength++;
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;

for (int k = 0; k <= i; k++)
{
currentNode = currentNode->next;
}

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++;
}

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)
{
pPreNode->data = tempNode->data;
}
}
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();
}
}
测试demo.cpp

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "List.h"
using namespace std;

int main(void){

Node node1;
node1.data = 3;
Node node2;
node2.data = 4;
Node node3;
node3.data = 5;
Node node4;
node4.data = 6;

Node node5;
node5.data = 7;

Node temp;

List *pList = new List();

/*pList->ListInsertHead(&node1);
pList->ListInsertHead(&node2);
pList->ListInsertHead(&node3);
pList->ListInsertHead(&node4);*/

pList->ListInsertTail(&node1);
pList->ListInsertTail(&node2);
pList->ListInsertTail(&node3);
pList->ListInsertTail(&node4);
pList->ListInsert(1, &node5);
//pList->ListDelete(1, &temp);
//pList->GetElem(1, &temp);
//pList->PriorElem(&node5, &temp);
pList->NextElem(&node5, &temp);
pList->ListTraverse();

cout << "temp=" << temp.data << endl;

delete pList;
pList = NULL;

system("pause");
return 0;
}
测试结果:



三、链表的应用之通讯录

通讯录的实现我们可以定义Person类,Person类重载了赋值运算符、比较运算符和输出<<运算符,Person.h

#ifndef PERSON_H
#define PERSON_H
#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); //重载比较运算符
};

#endifPerson.cpp
#include "Person.h"

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐