1. 链表
1.1 C++中的结构体和类的区别
- 在C++中,结构体与类基本相同,唯一不同的是:
(1)结构体:成员默认为公有成员
(2)类:成员默认为私有成员。
1.2 链表的定义
- 链表:是一种物理存储单元上非连续、非顺序的存储结构;
- 链表:由一系列结点(链表中每一个元素称为一个结点)组成;
- 链表:它解决了数组(就像容器)不可调节大小的缺陷,它可以将一个容器分解成若干个小容器,每一个小容器放入合适大小的元素,然后根据需要将它们链接起来;
1.3 链表元素的定义
- 链表中数据元素的逻辑顺序:是通过链表中的指针链接次序实现的。
- 链表中每个元素(结点)包括两个部分:
(1)存储数据元素的数据域;
(2)存储下一个结点地址的指针域; 声明一个链表结构,如:
struct book { int num; float price; //数据域 book *next; //指针域 } <=>等价于 class book { public: int num; float price; //数据域 book *next; //指针域 }
1.4 静态链表
- 静态链表:链表中所有结点的数据内存中的分布都是在编译时就确定好了的,程序运行后不能进行改动。
代码示例:静态链表的实现
#include <iostream> using namespace std; struct book { int num; float price; //数据域 book* next; //指针域 } void main() { book x, y, z, *head, *p; x.num = 10000; x.price = 14.7; y.num = 10005; y.price = 12.7; z.num = 10008; z.price = 44.7; head = &x;//将x变量结构的开始地址作为一个结点赋给头指针head x.next = &y;//将y变量结构的开始地址作为一个结点赋给x变量结构的next指针成员 y.next = &z;//将z变量结构的开始地址作为一个结点赋给y变量结构的next指针成员 z.next = NULL;//将z变量结构的next指针成员赋为空,即表示该结点是个尾结点 p = head;//将p指针指向头结点head while(p) { cout<<p->num<<"\t"<<p->price<<endl; p = p->next; } system("pause"); }
1.5 动态链表
- 动态链表:链表结构也可以是动态地分配存储的,即在需要时才开辟结点的存储空间。
注:动态链表的操作中将只使用new和delete。如:
book* p = new book;
delete p; 示例代码:动态链表的创建
#include <iostream> #include <string> using namespace std; struct book { int num; float price; //数据域 book* next; //指针域 } book* head = NULL; //声明了一个指向book结构的全局指针变量head book* creat() { book *p1, *p2; p1 = new book; //在堆中新建了一个book类对象或叫结点,并将指针p1指向它 head = p1; p2 = p1; cout<<"请输入图书的编号,以0结束"<<endl; cin>>p1->num; if (p1->num!=0) { cout<<"请输入图书的价格"<<endl; cin>>p1->price; } else { delete p1; p2 = NULL; head = NULL; return head; } while(p1->num != 0) { p2 = p1; //用p2来保存p1的地址,也就是上次创建成功结点的位置 p1 = new book; //作为下一个节点的指针p1 cout<<"请输入图书的编号,以0结束" <<endl; cin>>p1->price; if (p1->num!=0) { cout<<"请输入图书的价格"<<endl; cin>>p1->price; } p2->next = p1; //将p1的值付给p2->next,由于目前p1所指向的是个新结点,而p2指向的是第1个结点,因此p2->next = p1也就是将新结点的地址赋给第1个结点的next指针成员 } delete p1; //会删除掉最后一次创建的结点 p2->next = NULL; //将最后一次创建的结点的上一个结点的next成员赋为空,这样该结点就变成了尾结点,它不再指向任何结点 return head; } void main() { creat(); }
示例代码:遍历显示动态链表
void Showbook(book* head) { while(head) { cout<<head->num<<"\t"<<head->price<<endl; } }
示例代码:删除动态链表中的指定结点
void DeleteNode(book* head, int num) { book* l; if (head->num == num) { l = head; //将头结点的地址赋给指针l head = head->next; //用头指针head来访问第1个结点的next成员,并将next成员所存放的第2个结点的地址赋给head,这样head就指向了第2个结点 ::head = head; //跟着在将head的值赋给全局的head cout<<"操作成功"<<endl; return; } while (head) { if (head->next == NULL) { cout<<"找不到要删除的编号。"<<endl; return; } if (head->next->num == num) { l = head->next; head->next = l->next; delete l; cout<<"操作成功"<<endl; return; } head = head->next; //进入下一次循环 } cout<<"找不到要删除的编号。"<<endl; }
示例代码:在动态链表尾端插入结点
void InsertNode(book* head, int num, float price) { book* l; book* list = new book; while (head) { l = head; head = head->next; } list->num = num; list->price = price; list->next = NULL; l->next = list; //在尾端插入结点list }
示例代码:统计动态链表总结点数
int CountNode(book* head) { int count = 0; while (head) { count++; head = head->next; } return count; }
参考文献:
[1]《C++全方位学习》范磊——第十五章
[2] 百度搜索关键字:C++链表、结构体与类的区别、链表元素、静态链表、动态链表