bool List::InsertHead(Node *pNode)
{
Node* temp = m_pList->next;
Node* newNode = new Node;
if(newNode == NULL)
{
return fasle;
}
newNode->data = pNode->data;
m_pList->next = newNode;
newNode = temp;
return true;
}
bool List::InsertTail(Node *pNode)
{
Node* currentNode = m_pList;
while(currentNode->next != NULL)
{
currentNode = currentNode->next;
}
Node* newNode = new Node;
if(newNode == NULL)
{
return fasle;
}
newNode->data = pNode->data;
newNode->next = NULL;
currnetNode->next = newNode;
return true;
}
bool List::InsertHead(Node *pNode)
{
Node* temp = m_pList->next;
Node* newNode = new Node;
if(newNode == NULL)
{
return fasle;
}
newNode->data = pNode->data;
m_pList->next = newNode;
newNode = temp;
return true;
}
bool List::InsertTail(Node *pNode)
{
Node* currentNode = m_pList;
while(currentNode->next != NULL)
{
currentNode = currentNode->next;
}
Node* newNode = new Node;
if(newNode == NULL)
{
return fasle;
}
newNode->data = pNode->data;
newNode->next = NULL;
currnetNode->next = newNode;
return true;
}
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;
}
List::List()
{
m_pList = new Node;
m_pList->data = 0;
m_pList->next = NULL;
m_pList->iLength = 0;
}
bool List::ListEmpty()
{
if(m_iLength == 0)
{
return true;
}
else
{
return false;
}
}
int List::ListLength()
{
return m_iLength;
}
1234567
数据结构之线性表
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。 析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。
do more
建立链表的时候,头结点我们把数据域设置为固定的0,并且这个数据域没有任何意义,这个头结点存在的意义只是为了指向这一条链表。 头结点之后的第一个节点, 我们认为他是第0个节点。
建立一个毫无意义的头结点的好处在于:
1、可以很好的固定住链表的入口
2、再清空整个链表的时候(清空不是释放),可以留有一个入口记录下链表的内存位置。 如果没有这个节点,把链表清空了 就相当于释放了
什么是线性表:n个 数据元素的有限序列
1、顺序表:使用数组,访问速度快,搜索能力强(数组本身就有下标)
2、链表:静态链表、单链表、循环链表、双向链表
栈与队列都是一种特殊的操作受限的线性表,只允许在端点处进行插入和删除,二者的区别是:栈只允许在表的一端进行插入和删除操作,是一种“后进先出”的线性表;而队列是允许在一端进行插入操作,在别一端进行删除和操作,是一种”先进先出“的线性表
线性表的应用场景:通讯录、一元多项式
List.h:
//修改主要:
//1.将Elem改为Node
//2.加了两个操作:一个向头插入节点,一个向尾插入节点
#ifndef INC_0131_LIST_H
#define INC_0131_LIST_H
#include "Node.h"
class List
{
public:
List();//先放一个头节点,不需要size作为参数
~List();
void ClearList();//清空链表较为麻烦
bool ListEmpty();
int ListLength();
bool GetElem(int i, Node *pNode);//获取指定元素
int LocateElem(Node *pNode);//寻找第一个满足e的元素的位序
bool PriorElem(Node *pCurrentNode,Node *preNode);//获取指定元素的前驱
bool NextElem(Node *pCurrentNode,Node *pNextNode);//获取指定元素的后继
bool ListInsert(int i,Node *pNode);
bool ListDelete(int i,Node *pNode);
void ListTraverse();//遍历链表元素
bool ListInsertHead(Node *pNode);//插入头节点的下一个节点
bool ListInserTail(Node *pNode);//插入到最后一个节点
private:
Node *m_pList;
//int m_iSize;//链表不需要
int m_iLength;
};
#endif //INC_0131_LIST_HList.cpp:
//n 2020-02-06.
//
#include "List.h"
#include <iostream>
#include "Node.h"
using namespace std;
//构造函数
List::List() {
m_pList = new Node;//头节点
m_pList->data = 0;//头节点的数据域没有意义
m_pList->next = NULL;
m_iLength = 0;//头节点不计入
}
void List::ClearList() {
//顺藤摸瓜式清除,先找头节点,直到找到指针域为空,用while循环
Node *currentNode = m_pList->next;
while(currentNode != NULL){
Node *tmp = currentNode->next;
delete currentNode;//释放掉当前currentNode的内存
currentNode = tmp;
}
//不要忘记将头节点的next置为0
m_pList->next = NULL;
}
//析构函数:将整个内存释放掉,
//与ClearList有异曲同工之处:~List需要将头节点和后续所有节点都释放掉,而ClearList不需要释放头节点
List::~List(){//可以利用已经写好的clearlist
ClearList();
delete m_pList;
m_pList =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 *tmp = m_pList->next;
Node *newNode = new Node;//一定要从堆中去申请内存,因为如果从栈中申请内存,函数执行完成之后这个内存就被回收了
//注意考虑内存申请失败的情况
if(newNode == NULL){
return false;
}
newNode->data = pNode->data;
m_pList->next = newNode;
newNode->next = tmp;
m_iLength++;
return true;
}
bool List::ListInserTail(Node *pNode){
Node *curentNode = m_pList;
while(curentNode->next != NULL){
curentNode = curentNode->next;
}
Node *newNode = new Node;
if(newNode == NULL){
return false;
}
newNode->data = pNode->data;
newNode->next = NULL;
curentNode->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 = currentNode->next;
// currentNode->next = pNode;
// pNode->next = newNode;
//错误,为什么?
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--;
}
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;
}
pNode->data = currentNode->data;
return true;
}
int List::LocateElem(Node *pNode){
Node *currentNode = m_pList;
int i = 0;
while(currentNode->next != NULL){
currentNode = currentNode->next;//对链表进行遍历,对比数据域
//i++;不应该写在这里,只有不相同时才++
if(currentNode->data == pNode->data) {//返回什么?位置?而且只返回第一个符合的值(可能有多个)
return i;
}
i++;//不写在if语句之前,因为m_pList的数据域无效。
}
//如果一个节点都没有找到,易忽略
return -1;
}
bool List::PriorElem(Node *pCurrentNode,Node *preNode){
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;
}
preNode->data = tempNode->data;
return true;
}
}
}
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;
}
}
}
void List::ListTraverse(){
Node *currentNode = m_pList;
while (currentNode->next != NULL){
currentNode = currentNode->next;
currentNode->printNode();
}
}Node.h:
//
// Created by w on 2020-02-07.
//
#ifndef INC_0131_NODE_H
#define INC_0131_NODE_H
class Node{
public:
int data;//数据域,直接写在public下边就是为了方便付值
Node *next;//指针域
void printNode();
};
#endif //INC_0131_NODE_HNode.cpp:
//
// Created by x on 2020-02-07.
//
#include <iostream>
#include "Node.h"
using namespace std;
void Node::printNode(){
cout << data <<endl;
}main.cpp:
#include <iostream>
#include <stdlib.h>
#include "List.h"
using namespace std;
//int a=3,b=5 ;
//printf( "max=%d\n" , max(a,b) ); //这里的a,b就是实参
//int max( int a , int b ) ;//这里的a,b就是形参
//在main函数中
// 调用函数swap(&a,&b);
//定义函数时:
//void swap(int *a, int *b);
//这个是配套使用的。
int main(){
Node node1;//括号加了会出错?why?
node1.data = 3;
Node node2;//括号加了会出错?why?
node2.data = 4;
Node node3;//括号加了会出错?why?
node3.data = 5;
Node node4;//括号加了会出错?why?
node4.data = 6;
List *pList = new List();
Node node5;
node5.data =7;
Node tmp;
// pList->ListInsertHead(&node1);
// pList->ListInsertHead(&node2);
// pList->ListInsertHead(&node3);
// pList->ListInsertHead(&node4);
// pList->ListTraverse();
pList->ListInserTail(&node1);
pList->ListInserTail(&node2);
pList->ListInserTail(&node3);
pList->ListInserTail(&node4);
pList->ListInsert(1,&node5);
// pList->ListDelete(1,&tmp);
pList->PriorElem(&node5,&tmp);
pList->ListTraverse();
cout << "tmp = " << tmp.data <<endl;
delete pList;
pList = NULL;
return 0;
}
为什么有了顺序表还需要链表,因为两者互为补充
顺序表的优缺点:
优点:遍历和寻址时非常方便(因为基于数组)
缺点:插入删除元素
链表:



有些计算机语言没有指针:

未完成,待细学
List.h:
//
#ifndef INC_0131_LIST_H
#define INC_0131_LIST_H
class List
{
public:
List(int size);
~List();
void ClearList();//清空线性表不等于释放内存
bool ListEmpty();
int ListLength();
bool GetElem(int i, int *e);//获取指定元素
int LocateElem(int *e);//寻找第一个满足e的元素的位序
bool PriorElem(int *currentElem,int *preElem);//获取指定元素的前驱
bool NextElem(int *currentElem,int *nextElem);//获取指定元素的后继
bool ListInsert(int i,int *e);
bool ListDelete(int i,int *e);
void ListTraverse();//遍历链表元素
private:
int *m_pList;
int m_iSize;
int m_iLength;
};
#endif //INC_0131_LIST_HList.cpp:
//n 2020-02-06.
//
#include "List.h"
#include <iostream>
using namespace std;
//构造函数
List::List(int size) {
m_iSize = size;
//c++中分配内存,确定此线性表的容量:
m_pList = new int[size];
m_iLength = 0;
}
//析构函数:作用主要是将在构造函数中申请的内存释放掉
List::~List() {
delete []m_pList;
m_pList = NULL;//iSize置0无所谓,因为内存被释放后该对象也不存在了
}
void List::ClearList(){
m_iLength = 0;
}
bool List::ListEmpty(){
if(m_iLength == 0){
return true;
} else{
return false;
}
//也可:
//reture 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 tmp = LocateElem(currentElem);
//不是先判断是否是第一个元素,先判断是否找得到这个数
if(tmp == -1){
return false;
} else{
if(tmp == 0){
return false;
} else{
*preElem = m_pList[tmp - 1];//注意是*preElem
return true;
}
}
}
bool List::NextElem(int *currentElem,int *nextElem){
//判断是否存在这样一个元素
int tmp = LocateElem(currentElem);
if(tmp == -1){
return false;
} else{
if(tmp == m_iLength-1){
return false;
} else{
*nextElem = m_pList[tmp+1];
return true;
}
}
}
//自己写的,有错误
//bool List::PriorElem(int *currentElem,int *preElem){
// //先判断是否是第一个元素
// int tmp = LocateElem(currentElem);//注意用之前写好的函数
// if(tmp == 1){
// return false;
// } else {
// preElem = m_pList[tmp - 1];
// return true;
// }
//}
//
//bool List::NextElem(int *currentElem,int *nextElem){
// //先判断是否为最后一个元素
// int tmp = LocateElem(currentElem);
// if(tmp == m_iLength-1){
// return false;
// } else{
// nextElem = m_pList[tmp+1];
// return true;
// }
//}
void List::ListTraverse(){
for(int i = 0; i < m_iLength;i++){
cout << m_pList[i] <<endl;
}
}
bool List::ListInsert(int i,int *e){
//先判断是否超过size了
if(m_iSize == m_iLength || i < 0 || i > m_iLength){//已经满了或i不符合标准
return false;
} else{
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){
//先判断i是否合法
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;
}main.cpp:
#include <iostream>
#include <stdlib.h>
#include "List.h"
using namespace std;
int main(){
int e1 = 1;
int e2 = 2;
int e3 = 3;
int e4 = 4;
int e5 = 5;
int e6 = 6;
int tmp = 1;
List *list1 = new List(10);
cout << "length:" << list1->ListLength() <<endl;
list1->ListInsert(0,&e1);
cout << "length:" << list1->ListLength() <<endl;
list1->ListInsert(1,&e2);
list1->ListInsert(2,&e3);
list1->ListInsert(3,&e4);
list1->ListInsert(4,&e5);
list1->ListInsert(5,&e6);
list1->ListDelete(0,&tmp);
cout << "#" << tmp <<endl;
if(!list1->ListEmpty()){
cout << "not empty" <<endl;
}
list1->ClearList();
list1->ListTraverse();
list1->ListInsert(0,&e1);
list1->ListInsert(1,&e2);
list1->ListInsert(2,&e3);
list1->ListInsert(3,&e4);
list1->ListInsert(4,&e5);
list1->ListInsert(5,&e6);
list1->GetElem(4,&tmp);
cout << "tmp:" << tmp <<endl;
cout << list1->LocateElem(&tmp) << endl;//注意是传地址
list1->PriorElem(&e4,&tmp);
cout<<"前驱:" << tmp <<endl;
list1->NextElem(&e4,&tmp);
cout<<"后继:" << tmp <<endl;
delete list1;
list1 = NULL;
return 0;
}
顺序表编码:

什么是线性表:n个 数据元素的有限序列

线性表分为
1.顺序表(数组) 2.链表
链表:
1.静态链表
2.单链表
3.循环链表
4.双向链表
线性表的应用场景:通讯录、一元多项式
头结点没有数据域?
取出第N个节点的数据,只需要找到该节点,将data部分赋值出去则可
删除第N个节点
思路:需保留第N个节点的上一个节点
将当前的节点的next赋值给上一个节点的next则可,再释放掉当前节点
链表插入到第N个节点
原理都是找到要使用的当前节点,新结点被当前节点指,前节点的next赋值给新结点的next
链表尾部插入新结点
思路:先找到最后一个节点,在申请一个新结点,再让最后一个节点的next指向新结点,并且传参的节点只取了其中的数据,指针是自己new出来的
链表在头部插入新结点
思路:其实是放到头节点后的第一个位置
并且传参的节点只取了其中的数据,指针是自己new出来的
循环清空链表的数据 将当前的下一个指针赋值给临时指针 删掉当前指针 再将临时指针赋值给当前指针
链表:指针域 数据域 头结点 节点
顺序表缺点:插入删除元素时,顺序表需前移或者后移
顺序表链表互为补充
数组前移,for循环从小到大赋值
for(int k=i+1;k<m_length;k++)
{
m_plist[k-1]=m_plist[k];
}
数组后移操作 倒序循环赋值
for(int k=m_length-1;k>=i;k--)
{
}