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

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

一、顺序表的基本操作

首先看一下线性顺序表的基本操作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 
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 
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 
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 
#include 
#include 
#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;
}
测试结果:

【数据结构与算法003】基本数据结构——线性表(链表)_第1张图片

三、链表的应用之通讯录

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

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

#endif
Person.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;
}

你可能感兴趣的:(数据结构与算法笔面试)