数据结构笔记
必须吐槽一下,我都学了c的数据结构了,这一下子来了c++,就很烦,我又得重新整理,又出来那么多不理解的东西。
乱七八糟的知识准备:
当初c语言没学好的,都是要还的。
首先了解一下&(当然不怪我,这是c++的内容),参数的引用,什么时候用,有什么含义那?,可以理解对参数的结果需要带回来。下面看一下代码理解:
#include "stdio.h"
void test(int x){
x=1024;
printf("test 内部函数的x的值为:%d\n",x);
}
int main(){
int x =1;
printf("调用test前x的值为%d\n",x);
test(x);
printf("调用test后x的值为%d\n",x);
}
这就属于对于参数的结果没有带回来。那么如果我们在test函数里面传入的不是是x而是**&x**那?结果你也许猜到了,没错结果的值带了回来。结果如下
单链表
单链表的定义
typedef struct LNode{
int data;
struct LNode* next;
}LNode,*LinkList;
不说别的,就这个定义就够了解一壶的了。
首先给还原一下,上面的定义与下面的定义相同
typedef struct LNode{
int data;
struct LNode* next;
}
typedef struct LNode LNode;
typedef struct LNode* LinkList;
稍微明白一点了把,这是两个重命名,**一把这个结构体重命名为LNode ,另一个是把指向这个结构体的指针重命名为LinkList。**一脸懵逼,这是为什么?
而且LNode*其实是完全等价于LinkList,是不是感觉什么鬼,越来越乱,多此一举问什么要整两个那。不要急一点一点的表示。
先在此说一下,助于理解
- 强调这是一个单链表 ,–使用LinkList
- 强调这是一个节点 --使用LNode *
单链表的初始化
代码都是默认带头节点的
bool InitList(LinkList &L){
L=new LNode;
if(L==NULL) return false;
L->next=NULL;
return true;
}
//这是测试,不是属于初始化的内容但是检测初始化的内容
void test(){
LinkList L;
InitList(L);
}
算了都补一下把,不带头节点:
bool InitList(LinkList &L){
if(L==NULL) //区别在这
return true;
}
单链表的判空
为什么传入的参数是L而不是&L,很简单,我们只需要判断,也不需要带回
bool Empty(LinkList L){
if(L->next==NULL) return false;
else
return true;
}
不带头节点:
bool Empty(LinkList L){
if(L==NULL) return false;//区别在这
else
return true;
}
单链表的插入
bool InsertLink(LinkList &L,int index,int element){
if(index<1)
return false;
LNode * p; //指正p指向当前扫描到的节点
p=L;
int j=0; //当前p指向的是第几个节点
while (p!=NULL && j<index-1){
p=p->next;
j++;
}
if(p==NULL)
return false;
LNode* s=new LNode;//LNode* s =(LNode* s)malloc(sizeof(LNode));c语言可以这样写;
s->data=element;
s->next=p->next;
p->next=s;
return true;
}
不带头节点:
bool InsertLink(LinkList &L,int index,int element){
if(index<1)
return false;
//对于i==1进行特殊处理,插入第一个节点与其他操作不同
if(i==1){
LNode *s =new LNode;
s->data =e;
s->next =L;
L=s;
return true;
}
LNode * p; //指正p指向当前扫描到的节点
p=L;
int j=1; //去呗在这里
while (p!=NULL && j<index-1){
p=p->next;
j++;
}
if(p==NULL)
return false;
LNode* s=new LNode;//LNode* s =(LNode* s)malloc(sizeof(LNode));c语言可以这样写;
s->data=element;
s->next=p->next;
p->next=s;
return true;
}
拓展一下,后插操作(很有作用):
单链表的删除
bool DeleteList(LinkList &L,int index,int &e){
if(index<1) return false;
LNode *p;//指正p当前扫描的节点
int j=0;//当前p指向第几个节点
p=L;
while (p!=NULL && j<index-1){
p=p->next;
j++;
}
if(p==NULL) return false;
if(p->next==NULL) return false;
LNode *q=p->next;
e=q->data;
p->next=q->next;
free(q);
}
单链表按位查找
LNode *GetElem(LinkList L ,int index){
if(index<0) return NULL;//因为我们是带头节点,所以头节点可以看做第0个元素
LNode *p;
int j=0;
p=L;
while (p!=NULL &&j<index){
p=p->next;
j++;
}
return p;
第二种,可以参考理解一下
LNode *GetElem(LinkList L ,int index){
int j=1;
LNode *p = L->next;
if(index==0) return L;
if(index<1) return NULL;
while (p!=NULL &&j<index){
p=p->next;
j++;
}
return p;
}
这里提一下,在我们学完按位查找之后,可以利用其封装性,应用到单链表的插入和删除中搜索到前节点的过程
单链表的按值查找
LNode* LocateElem(LinkList L, int element) {
LNode* p = L->next;
while (p != NULL && p->data != element) {
p = p->next;
}
return p;
}
总结:
下面是整个链表的展示,包括实现功能
#include <stdio.h>
#include <stdlib.h>
typedef struct LNode {
int data;
struct LNode* next;
} LNode, *LinkList;
// 初始化
bool InitList(LinkList& L) {
L = new LNode;
if (L == NULL) return false;
L->next = NULL;
return true;
}
// 判断是否为空
bool Empty(LinkList L) {
if (L->next == NULL) return true;
else return false;
}
// 插入操作
bool InsertList(LinkList& L, int index, int element) {
if (index < 1) return false;
LNode* p; //指针p指向当前扫描到的节点
p = L;
int j = 0; //当前p指向的是第几个节点
while (p != NULL && j < index - 1) {
p = p->next;
j++;
}
if (p == NULL) return false;
LNode* s = new LNode;
s->data = element;
s->next = p->next;
p->next = s;
return true;
}
// 删除操作
bool DeleteList(LinkList& L, int index, int& e) {
if (index < 1) return false;
LNode* p; //指针p当前扫描的节点
int j = 0; //当前p指向第几个节点
p = L;
while (p != NULL && j < index - 1) {
p = p->next;
j++;
}
if (p == NULL || p->next == NULL) return false;
LNode* q = p->next;
e = q->data;
p->next = q->next;
free(q);
return true;
}
// 按位置查找
LNode* GetElem(LinkList L, int index) {
if (index < 0) return NULL; //因为我们是带头节点,所以头节点可以看做第0个元素
LNode* p;
int j = 0;
p = L->next; // 从第一个节点开始查找
while (p != NULL && j < index) {
p = p->next;
j++;
}
return p;
}
// 按值查找,找到数据域==element的节点
LNode* LocateElem(LinkList L, int element) {
LNode* p = L->next;
while (p != NULL && p->data != element) {
p = p->next;
}
return p;
}
// 求表长的长度
int Length(LinkList L) {
int len = 0;
LNode* p = L->next;
while (p != NULL) {
p = p->next;
len++;
}
return len;
}
void test() {
LinkList L;
if (InitList(L)) {
printf("链表初始化成功.\n");
} else {
printf("链表初始化失败。\n");
return;
}
// 测试插入操作
for (int i = 1; i <= 5; i++) {
if (InsertList(L, i, i * 10)) {
printf("在位置%d插入元素%d成功。\n", i, i * 10);
} else {
printf("位置%d的插入失败。\n", i);
}
}
// 测试删除操作
int deletedElement;
if (DeleteList(L, 3, deletedElement)) {
printf("删除的元素:%d\n", deletedElement);
} else {
printf("3号位置的删除失败。\n");
}
// 测试查找操作
int findElement = 20;
LNode* foundNode = LocateElem(L, findElement);
if (foundNode) {
printf("在位置%p找到元素%d。\n", foundNode, findElement);
} else {
printf("没有找到元素%d\n", findElement);
}
// 输出链表长度
int len = Length(L);
printf("链表长度:%d\n", len);
}
int main() {
test();
return 0;
}