文章目录
所用语言——C语言
数据结构
数据结构就是数据存放的思想
数组
特点:元素是连续的
缺点:增、删元素很复杂
链表
链表的概念
链表是很多结构体通过存放下一结构体指针地址的数据结构。
特点:链表各节点的地址是不连续的
初始化链表
#include <stdio.h>
#include <stdlib.h>
// 1.定义链表节点结构体
struct Node{
int data;//数据域
struct Node *next;//指针域
};
int main()
{
// 2.初始化各节点
struct Node node1 = {1,NULL};
struct Node node2 = {2,NULL};
struct Node node3 = {3,NULL};
// 3.连接各节点
node1.next = &node2;
node2.next = &node3;
// 4.通过首节点打印整个链表内容
printf("%d\t%d\t%d",node1.data,node1.next->data,node1.next->next->data);
return 0;
}
链表的遍历
通过链表头遍历整个链表;不同于遍历数组通过for循环中下标的递增来遍历,遍历链表通过while循环中指针指向的变更来遍历
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node *next;
};
// 传入链表头遍历链表
void printLink(struct Node *head){
struct Node *point;
point = head;
while(point != NULL){
printf("%d ",point->data);
// 打印完数据域指针移到下一个节点
point = point->next;
}
putchar('\n');
}
int main()
{
struct Node node1 = {1,NULL};
struct Node node2 = {2,NULL};
struct Node node3 = {3,NULL};
struct Node node4 = {4,NULL};
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
printLink(&node1);
return 0;
}
统计链表节点个数及链表查找
查询链表中是否有data这个数据,有的话返回1没有返回0
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node *next;
};
void printLink(struct Node *head){
struct Node *point;
point = head;
while(point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
// 统计链表节点个数
int getLinkTotalNodeNum(struct Node *head){
int cnt = 0;
while(head != NULL){
cnt++;
head = head->next;
}
return cnt;
}
// 查找数据
int searchLink(struct Node *head,int data){
while(head != NULL){
if(head->data == data){
return 1;
}
head = head->next;
}
return 0;
}
int main()
{
struct Node node1 = {1,NULL};
struct Node node2 = {2,NULL};
struct Node node3 = {3,NULL};
struct Node node4 = {4,NULL};
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
printLink(&node1);
int ret = getLinkTotalNodeNum(&node1);
printf("total num = %d\n",ret);
ret = searchLink(&node1,1);
if(ret == 0){
printf("no 1");
}else{
printf("have 1");
}
return 0;
}
从指定节点后插入新节点
先将新节点指向原节点的下一个节点,再让原节点指向新节点。注意:函数参数尽量传指针,直接传结构体啊哈C会出错
如果有链表节点的数据重复还能插入新节点吗?
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node *next;
};
// 遍历链表
void printLink(struct Node *head){
struct Node *point;
point = head;
while(point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
// 在指定节点后插入新节点
int insertFromBehind(struct Node *head, int data, struct Node *new){
struct Node *p = head;
while(p != NULL){
if(p->data == data){
new->next = p->next;
p->next = new;
return 1;
}
p = p->next;
}
return 0;
}
int main()
{
struct Node node1 = {1,NULL};
struct Node node2 = {2,NULL};
struct Node node3 = {3,NULL};
struct Node node4 = {4,NULL};
struct Node new = {100,NULL};
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
insertFromBehind(&node1,3,&new);
printLink(&node1);//1 2 3 100 4
return 0;
}
从指定节点前插入新节点
为什么要有返回值为结构体指针?不能是void吗?
因为链表头也有可能被改变
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node *next;
};
// 遍历链表
void printLink(struct Node *head){
struct Node *point;
point = head;
while(point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
// 从节点前插入新节点
struct Node* insertFromfor(struct Node *head, int data, struct Node *new){
struct Node *p = head;
if(p->data == data){
new->next = head;
return new;
}
while(p->next != NULL){
if(p->next->data == data){
new->next = p->next;
p->next = new;
return head;
//一定要在这里return head,因为不return下一句p指向的永远是新节点,新节点的next节点中data永远等于data,会一直进到if中,即在data前一直插入新节点
}
p = p->next;
}
return head;
}
int main()
{
struct Node node1 = {1,NULL};
struct Node node2 = {2,NULL};
struct Node node3 = {3,NULL};
struct Node node4 = {4,NULL};
struct Node new = {100,NULL};
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
struct Node *head = NULL;
head = &node1;
head = insertFromfor(head, 2, &new);
printLink(head);//1 100 2 3 4
return 0;
}
链表删除指定节点
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node *next;
};
void printLink(struct Node *head){
struct Node *point;
point = head;
while(point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
// 删除指定节点
struct Node* deleteNode(struct Node *head, int data){
struct Node *p = head;
if(p->data == data){
head = head->next;
// free(p);动态创建链表用malloc函数时可以用free
return head;
}
while(p->next != NULL){
if(p->next->data == data){
p->next = p->next->next;
return head;
//这里return掉是因为防止最后一个节点是NULL后,没有p->next无法进行while判断导致程序崩溃
}
//这里的遍历只为找if的条件
p = p->next;
}
return head;
}
int main()
{
struct Node node1 = {1,NULL};
struct Node node2 = {2,NULL};
struct Node node3 = {3,NULL};
struct Node node4 = {4,NULL};
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
struct Node *head = &node1;
printLink(head);
head = deleteNode(head, 2);
printLink(head);
return 0;
}
链表动态创建之头插法
不断在链表的头部插入新节点
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node *next;
};
void printLink(struct Node *head){
struct Node *point;
point = head;
while(point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
// 头插法
struct Node* insertFromHead(struct Node *head){
struct Node *newNode;
while(1){
newNode = (struct Node *)malloc(sizeof(struct Node));
// 不要出现野指针,要给next初始化为NULL
newNode->next = NULL;
printf("请输入新节点的数据:");
scanf("%d",&(newNode->data));
if(newNode->data == 0){
printf("0 quit\n");
return head;
}
if(head == NULL){
head = newNode;
}else{
newNode->next = head;
head = newNode;
}
}
return head;
}
int main()
{
struct Node *head = NULL;
head = insertFromHead(head);
printLink(head);
return 0;
}
头插法优化
尾插法创建链表
从链表的尾部不断插入新节点
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node *next;
};
// 打印链表
void printLink(struct Node *head){
struct Node *node = head;
while(node != NULL){
printf("%d\t",node->data);
node = node->next;
}
putchar('\n');
}
// 尾插法不断插入新节点
struct Node* insertFromTail(struct Node *head){
struct Node *node = head;
struct Node *newNode = NULL;
while(1){
newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->data = 0;
newNode->next = NULL;
printf("请输入要插入的节点数据:");
scanf("%d",&newNode->data);
if(newNode->data == 0){
return head;
}
if(head == NULL){
head = newNode;
node = head;
}else{
// 在任意链表后插入新节点都可以
// 将node定位到链表的最后一位
while(node != NULL){
if(node->next == NULL){
break;
}
node = node->next;
}
node->next = newNode;
node = newNode;
}
}
return head;
}
int main()
{
// 用尾插法不断插入新节点
struct Node *head = NULL;
head = insertFromTail(head);
// 打印链表
printLink(head);
return 0;
}
链表综合
#include <stdio.h>
#include <stdlib.h>
#define GET_RESULT 1
typedef struct Node{
int data;
struct Node *next;
}Node;
// 遍历链表
void printLink(Node *head){
Node *node = head;
// printf("链表:");
if(head == NULL){
printf("NULL");
}
while(node != NULL){
printf("%d\t",node->data);
node = node->next;
}
putchar('\n');
}
// 统计链表节点个数
int getNodeNum(Node *head){
int count = 0;
Node *node = head;
while(node != NULL){
count++;
node = node->next;
}
return count;
}
// 链表查找
int searchLink(Node *head, int data){
Node *node = head;
while(node != NULL){
if(node->data == data){
return 1;
}
node = node->next;
}
return 0;
}
// 从指定节点后插入新节点
Node* insertFromBehind(Node *head, int data, Node *newNode){
Node *node = head;
if(head == NULL){
head = newNode;
return head;
}
while(node != NULL){
if(node->data == data){
newNode->next = node->next;
node->next = newNode;
return head;
}
node = node->next;
}
return head;
}
// 从指定节点前插入新节点
Node* insertFromForward(Node *head, int data, Node *newNode){
Node *node = head;
if(head == NULL){
head = newNode;
return head;
}
if(head->data == data){
newNode->next = head;
head = newNode;
return head;
}
while(node->next != NULL){
if(node->next->data == data){
newNode->next = node->next;
node->next = newNode;
return head;
}
node = node->next;
}
return head;
}
// 不断删除指定节点
Node* deleteNode(Node *head){
int data = 0;
Node *node = head;
while(1){
printf("请输入要删除的节点:");
scanf("%d",&data);
if(data == 0){
return head;
}
if(head->data == data){
head = head->next;
node = head;
continue;
}
while(node->next != NULL){
if(node->next->data == data){
node->next = node->next->next;
break;
}
node = node->next;
}
node = head;
}
}
// 头插法
Node* insertFromHead(Node *head){
Node *newNode;
while(1){
newNode = (Node *)malloc(sizeof(Node));
newNode->data = 0;
newNode->next = NULL;
printf("请输入头插法要插入的新节点数据:");
scanf("%d",&newNode->data);
if(newNode->data == 0){
return head;
}
if(head == NULL){
head = newNode;
}else{
newNode->next = head;
head = newNode;
}
}
}
// 尾插法
Node* insertFromTail(Node *head){
Node *newNode;
Node *node = head;
while(1){
newNode = (Node *)malloc(sizeof(Node));
newNode->data = 0;
newNode->next = NULL;
printf("请输入尾插法要插入的新节点数据:");
scanf("%d",&newNode->data);
if(newNode->data == 0){
return head;
}
if(head == NULL){
head = newNode;
node = head;
}else{
while(node != NULL){
if(node->next == NULL){
break;
}
node = node->next;
}
node->next = newNode;
node = newNode;
}
}
}
int main()
{
// 初始化链表
Node node1 = {1,NULL};
Node *head = &node1;
Node node2 = {2,NULL};
Node node3 = {3,NULL};
head->next = &node2;
node2.next = &node3;
// 遍历链表
printLink(head);
// 统计链表节点个数
int nodeNum = getNodeNum(head);
printf("节点有%d个\n",nodeNum);
// 链表查找
int data = 0;
printf("请输入要查找的节点:");
scanf("%d",&data);
int result = searchLink(head,data);
if(result == GET_RESULT){
printf("存在该节点\n");
}else{
printf("该节点不存在\n");
}
// 从指定节点后插入新节点
printf("请输入要从哪个节点后插入新节点:");
scanf("%d",&data);
Node newNode1 = {101,NULL};
head = insertFromBehind(head,data,&newNode1);
printLink(head);
// 从指定节点前插入新节点
printf("请输入要从哪个节点前插入新节点:");
scanf("%d",&data);
Node newNode2 = {100,NULL};
head = insertFromForward(head,data,&newNode2);
printLink(head);
// 不断删除指定节点
head = deleteNode(head);
printLink(head);
// 头插法
head = insertFromHead(head);
printLink(head);
// 尾插法
head = insertFromTail(head);
printLink(head);
return 0;
}
基础算法
冒泡排序
给定一个数组nums,有numsSize个元素,将其元素从小到大排序
//将数组中前一个元素和后一个元素比较,如果后面的元素更大,就交换元素位置,以此类推
//比如nums = {5,4,3,2,1};
//第1轮比较了4次,最大值5被排到了最后
//第2轮比较了3次,此轮的最大值4被排到了倒数第2位
//以此类推,用i代表第几轮比较,j代表第几次比较
//共比较了numsSize - 1轮,每一轮比较了numsSize - i次
void bubbleSort(int* nums, int numsSize){
int temp, i, j;
for (i = 1; i <= numsSize - 1; i++) {
for(j = 1; j <= numsSize - i; j++){
if(nums[j - 1] > nums[j]){
temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
}
}
}
}