顺序表
整体大小为9-size
元素个数为5-count
插入的时候size++,count不变
扩充:size不变,count加容量
结构定义:size count 连续存储区
realloc
- 直接往后扩容,没空间呢?
- 找一篇新的空间,并删除原内存,找不到这么大的?
- 直接返回null,且原内存不懂
c++
//
// Created by cry on 2024/3/6.
//
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#include <time.h>
#define MAX_OP 20
//结构定义+结构操作
//1.结构定义
//size count 连续存储区
typedef struct acm_1_1_List_vector{
int size,count;
int *data;
} acm_1_1_List_vector;
//返回大小为n的新顺序表
acm_1_1_List_vector *acm_1_1_List_getNewVector(int n){
//开辟空间
acm_1_1_List_vector *p=(acm_1_1_List_vector *)malloc(sizeof (acm_1_1_List_vector));
p->size=n;
p->count=0;
p->data=(int *)malloc(sizeof(int) *n);
return p;
}
//销毁,先销毁存储区然后销毁整个
void acm_1_1_List_clear(acm_1_1_List_vector *v){
if(v==NULL) return;
free(v->data);
free(v);
return ;
}
int acm_1_1_List_expand(acm_1_1_List_vector *v){
if(v==NULL){return 0;}
printf("expand v from %d to %d\n",v->size,2*v->size);
//新定义一个指针,并把扩充后的这个值赋值给指针,不为空就给data
int *p=(int *)(v->data,sizeof(int)*2*v->size); //进行重新分配内存大小
if(p==NULL)return 0; //为NULL代表扩容失败
v->data=p; //扩容成功
v->size *=2;
return 1;
}
//插入操作
int acm_1_1_List_insert(acm_1_1_List_vector *v,int pos,int val){
if(pos <0 || pos >v->count) return 0;
if(v->size==v->count && !acm_1_1_List_expand(v))return 0; //满了
for(int i=v->count;i>=pos;i--){ //从后往前
v->data[i+1] =v->data[i];
}
v->data[pos]=val;
v->count+=1;
return 1;
}
int acm_1_1_List_erase(acm_1_1_List_vector *v,int pos){
if(pos <0 || pos >=v->count) return 0;
for(int i=pos+1;i<v->count;i++){ //前移
v->data[i-1]=v->data[i];
}
v->count-=1;
return 1;
}
void acm_1_1_List_output_vector(acm_1_1_List_vector *v){
int len=0;
for(int i=0;i<v->size;i++){
len+=printf("%5d",i);
}
printf("\n");
for(int i=0;i<len;i++){
printf("-");
}
printf("\n");
for(int i=0;i<v->count;i++){
printf("%5d",v->data[i]);
}
printf("\n");
return;
}
void acm_1_1_List_test(){
srand(time(0));
int pos,val,op,ret;
acm_1_1_List_vector *v=acm_1_1_List_getNewVector(2);
for(int i=0;i<MAX_OP;i++){
op=rand()%4; //决定插入还是删除
switch(op){
case 0: //0 1 2插入 ,3删除
case 1:
case 2:
pos=rand()%(v->count+2);
val=rand()%100;
ret=acm_1_1_List_insert(v,pos,val);
printf("insert %d at %d to vector=%d\n",
val,pos,ret);
break;
case 3:
pos=rand()%(v->count+2);
ret=acm_1_1_List_erase(v,pos);
printf("erase item at %d in vector=%d\n",
pos,ret);
break;
}
acm_1_1_List_output_vector(v);
printf("\n\n");
}
acm_1_1_List_clear(v);
}
链表
数据结构=定义+操作
定义:数据,下一个节点地址
操作:插入删除
注意:错误的插入会导致内存泄漏(就是后面不用的变量且找不到地址,没有即时free)
链表分为 有头链表 和 无头链表
c++
//
// Created by cry on 2024/3/6.
//
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
//结构定义
typedef struct Node{
int data; //数据信息
struct Node *next;//下一个节点
}Node;
//结构操作
Node *acm_1_2_Linked_getNewNode(int val){
Node *p=(Node *)malloc(sizeof(Node));
p->data=val;
p->next=NULL;
return p;
}
void acm_1_2_Linked_clear(Node *head){
if(head==NULL) return ;
//循环遍历链表的每一个节点,删除当前节点到下一个节点,直到p为空
for(Node *p=head,*q;p;p=q){
q = p->next;
free(p);
}
}
//插入
Node *acm_1_2_Linked_insert(Node *head,int pos,int val){
//当链表为空的时候需要getNewNode
if(pos==0){
Node *p= acm_1_2_Linked_getNewNode(val);
p->next=head;
return p;
}
Node *p=head;
for(int i=1;i<pos;i++){
p=p->next; //找到待插入的位置
}//结束后p为待插入节点的前一位
Node *node= acm_1_2_Linked_getNewNode(val); //待插入新节点
node->next=p->next;
p->next=node;
node->data=val;
return head;
}
void acm_1_2_Linked_output_linklist(Node *head){
int len=0,n=0;
for(Node *p=head;p;p=p->next){
n+=1;//求长度
}
for(int i=0;i<n;i++){
printf("%3d",i);
printf(" ");
}
printf("\n");
for(Node *p=head;p;p=p->next) {
printf("%3d", p->data);
printf("->");
}
printf("\n\n\n");
return;
}
void acm_1_2_Linked_test(){
srand(time(0));
#define MAX_OP 20
Node *head=NULL;
for(int i=0;i<MAX_OP;i++){
int pos=rand()%(i+1),val=rand()%100;
printf("insert %d at %d to Linklist\n",val,pos);
head=acm_1_2_Linked_insert(head,pos,val);
acm_1_2_Linked_output_linklist(head);
}
acm_1_2_Linked_clear(head);
}
//普通查找
int acm_1_2_Linked_find(Node *head,int val){
Node *p=head;
while(p){
if(p->data==val)return 1;
p=p->next;
}
return 0;
}
int acm_1_2_Linked_huaYangFind(Node *head,int val){
Node *p=head;
int n=0;
while(p){
if(p->data==val){
acm_1_2_Linked_output_linklist(head,1);
//先输出整个链表
//然后在对应位置输出小箭头
int len=n*(DL+2)+2;
for(int i=0;i<len;i++)printf(" ");
printf("^\n");
for(int i=0;i<len;i++)printf(" ");
printf("|\n");
return 1;
}
n+=1;
p=p->next;
}
return 0;
}
双向链表,第一个指向最后一个节点
双向链表比普通链表多一个prev的数据定义
链表反转
c++
// 头插法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode new_head,*p=head,*q;
new_head.next=NULL;
while(p){
q=p->next;
p->next=new_head.next;
new_head.next=p;
p=q;
}
return new_head.next;
}
};
// 递归法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL || head.next==NULl) return head; //空和一个不用动
ListNode *tail=head->next;
ListNode *new_head=reverseList(head->next);
head->next=tail->next;
tail->next=head; //默认前面都排序好了,直接将head插到最后
return new_head;
}
};
环形链表1
c++
class Solution {
public:
bool hasCycle(ListNode *head) {
//原理是,跑的快的比跑的慢的更快到目的地,表明没有环
ListNode *p=head,*q=head;
while(q && q->next){
p=p->next; //跑的慢的
q=q->next->next; //跑的快的
if(p==q) return true; //遇见了,有环
}
return false; //快的到达终点
}
};
判断循环就用快慢指针
输入:n = 19 输出:true 解释: 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1
c++
class Solution {
public:
int getNext(int x){
int d,y=0;
while(x){
d=x%10;
y+=d*d;
x/=10;
}
return y;
}
bool isHappy(int n) {
int p=n,q=n;
while(q!=1){
p=getNext(p); //走一步
q=getNext(getNext(q)); //走两步
if(p==q && p!=1) return false;//相遇,不是快乐数
}
return true; //是快乐数;
}
};
旋转链表
输入:head = [1,2,3,4,5], k = 2 输出:[4,5,1,2,3]
c++
class Solution {
public:
//获取链表长度,直接遍历链表就行
int getLength(ListNode *head){
int n=0;
while(head){
n+=1;
head=head->next;
}
return n;
}
ListNode* rotateRight(ListNode* head, int k) {
if(head==NULL) return head; //空链表直接返回
int n=getLength(head);
k%=n; //取余数之后才是要移动的位数
if(k==0) return head;
ListNode *p=head,*q=head; //先找到倒数第k+1个结点
for(int i=0;i<=k;i++){
p=p->next;
}
while(p){ //当p指向NULL的时候,q指向的地方就是分割的地方
p=p->next;
q=q->next;
} //p指向的就是第二部分的头结点
p=q->next;
q->next=NULL;
q=p; //让q遍历一遍q的所有指针
while(q->next !=NULL){
q=q->next;
} //q指向的节点就是第二部分最后一个节点
q->next=head; //将q.next接到head
return p;
}
};
leetcode19:
给你一个链表,删除链表的倒数第
n
个结点,并且返回链表的头结点。
c++
//双指针等距移动法
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode new_head,*p=&new_head,*q=p;//有头链表
new_head.next=head;//pq都指向虚拟的头newHead
//pq0(newhead)->head1->2->3->4
for(int i=0;i<=n;i++){ //q指针向后移动n+1位数,因为是虚拟节点head
q=q->next;
}
while(q)p=p->next,q=q->next; //如果q在NULL除,就两个指针同时向后移,靠后的q在空地址为止
//等距指针法,因为是倒数
p->next=p->next->next; //工程里面p->next需要回收掉,避免内存溢出
//删除p指针后面的节点
return new_head.next;
}
};
leetcode142:环形链表2
环形链表1用快慢指针方法判断是否有环
c++
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *p=head,*q=head; //双指针
while(q && q->next){ //p每次一步,q每次两步
p=p->next;
q=q->next->next;
if(p==q)break; //直到pq相等为止
}
if(q==NULL || q->next==NULL) return NULL; //为NULL表示没环
p=head; //讲一个撇回去
while(p !=q){ //pq相同的速度往后走
p=p->next;
q=q->next;
} //pq相交的位置就是环的位置,就是环的起始节点
return p;
}
};
92.反转链表2
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
if(left==1 && right==1) return head;
if(left!=1){ //左区间
//左右区间同时减一
//将剩余链表部分和区间范围进行翻转,然后挂在头结点后面
head->next=reverseBetween(head->next,left-1,right-1);
}
else{//右区间不为1
//反转完以后的尾节点,和头结点地址
ListNode *tail=head->next,*new_head;
//对剩下部分进行反转
new_head=reverseBetween(head->next,left,right-1);
head->next=tail->next;
tail->next=head;
head=new_head;
}
return head;
}
};
//左区间
//左右区间同时减一
//将剩余链表部分和区间范围进行翻转,然后挂在头结点后面
head->next=reverseBetween(head->next,left-1,right-1);
}
else{//右区间不为1
//反转完以后的尾节点,和头结点地址
ListNode *tail=head->next,*new_head;
//对剩下部分进行反转
new_head=reverseBetween(head->next,left,right-1);
head->next=tail->next;
tail->next=head;
head=new_head;
}
return head;
}
};