数据结构1

数据结构

简单记录《剑指offer》数据结构部分的学习,主要分为数组、字符串、链表、树、栈和队列。数组和字符串用连续内存存放数字和字符;链表和树操作需要大量的指针;栈与递归紧密相连,队列与广度优先遍历算法紧密相关。

数组

由于数组中的内存的连续性,可实现O(1)时间内快速查找;但创建数组时需先制定数组容量的大小(导致数组空间使用效率不好);故存在动态数组STL中的vector,对vector进行扩容时,新的容量都是前一次的两倍,会把之前的数据复制到新的数组中,再把之前的内存释放掉(扩容时会产生大量的额外操作,因此使用vector时尽量减少改变数组容量大小的次数)

声明数组时,数组的名字本身也是一个指针,指向数组的第一个元素(C++中没有记录数组的大小,用指针访问数组元素时,需确保没有超出数组的边界)。数组作为函数的参数进行传递时,会自动退化为同类的指针数组禁止拷贝和赋值使用数组是通常将其转化成指针

#include<iostream>
using namespace std;
 
int GetSize(int data[]) {
    return sizeof(data);
}
int main() {
    int data1[] = {1,2,3,4,5};
    int size1 = sizeof(data1); // 20
 
    int *data2 = data1;
    int size2 = sizeof(data2); // 4
 
    int size3 = GetSize(data1); //4
 
    cout<<size1<<" "<<size2<<" "<<size3<<endl;
    return 0;
int a[] = {0,1,2};    // 含有三个整数的数组
int s2[] = a;           // 错误:不允许使用一个数组初始化另一个数组
a2 = a;               // 错误:不能把一个数组直接赋值给另一个数组

二维数组传参

方式一:数组作为形参(但第二维必须标明

shuchu(num); // 实参
void shuchu(num[3][4]); //形参, 两种都可
void shuchu(num[][4]);

方式二:一重指针作为形参,即指向数组的指针–数组指针(行指针)第二维必须标明,即数组长度)-- int (*p)[n]

void display2(int (*parr)[4],const int irows); //  可采用 parr[i][j];  parr[i] 表示第i行

数组指针
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++;       //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

指针数组
定义 int* p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 p=a; 这里p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:
int *p[3];
int a[3][4];
p++; //该语句表示p数组指向下一个数组元素。注:此数组每一个元素都是一个指针
for(i=0;i<3;i++)
p[i]=a[i]
这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。

方式三:形参为指针的指针

#include <stdio.h>  
  
void subfun(int n, char **subargs)  
{  
    int i;   
    for (i = 0; i < n; i++) {  
        printf("subargs[%d] = %s\n", i, subargs[i]);  
    }  
}  
  
void main()  
{  
    char *a[3];  
    char args[][5] = {"abc", "def", "ghi"};  
    a[0] = args[0];  //equals with a[0] = &args[0][0];  
    a[1] = args[1];  
    a[2] = args[2];  
    subfun(3, a);  //若此处为subfun(3, args);则会编译出错  
}  
#include <stdio.h>  
  
void subfun(int n, char **subargs)  
{  
    int i;   
    for (i = 0; i < n; i++) {  
        printf("subargs[%d] = %s\n", i, subargs[i]);  
    }  
}  
  
void main()  
{  
    char *args[] = {"abc", "def", "ghi"};//equals with char *args[3] = {"abc", "def", "ghi"};  
    subfun(3, args);  
}  

方式四:一重指针


#include <stdio.h>
#include <stdlib.h>
 
void test(double *p,const int m,const int n)
{
	for(int i=0;i<m;i++)
		for(int j=0;j<n;j++)
			printf("%f, \n",p[i*m+j]);
}
 
int main(int argc, char *argv[])
{
	double a[2][2]={{1,2},{3,4}};
	test((double*)a,2,2);
 
	return 0;

字符串

每个字符串的结尾都以字符‘\0’作为结尾(需特别注意字符串越界问题)。C++中常量字符串放到一个单独的内存区域,当指针赋值给相同的常量字符串时,会指向相同的内存地址;但初始化数组则不会。

替换字符串内空格,采用双指针法(时间复杂度为O(n))

void ReplaceBlank(char str[], int length)
{
    if(str == nullptr && length <= 0)
        return;

    int originalLength = 0;
    int numberOfBlank = 0;
    int i = 0;
    while(str[i] != '\0')
    {
        ++ originalLength;

        if(str[i] == ' ')
            ++ numberOfBlank;

        ++ i;
    }

    int newLength = originalLength + numberOfBlank * 2;
    if(newLength > length)
        return;

    int indexOfOriginal = originalLength;
    int indexOfNew = newLength;
    while(indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
    {
        if(str[indexOfOriginal] == ' ')
        {
            str[indexOfNew --] = '0';
            str[indexOfNew --] = '2';
            str[indexOfNew --] = '%';
        }
        else
        {
            str[indexOfNew --] = str[indexOfOriginal];
        }

        -- indexOfOriginal;
    }
}

字符串cout 或 比较时 仅用他的名称即指向首地址的指针即可。

双指针法例程

两个有序数组a1,a2;a1有足够的空间容纳a2;将a2所有的数字插入至a1中,且所有的数字都是有序排列的
void insert1( int* _a1, int* _a2 , int _a1_length, int _a2_length ){
    if (_a1 == nullptr)
        return;
    int indexofOriginal = _a1_length; 
    int indexofa2 = _a2_length; 
    int indexofNew = _a1_length + _a2_length; 
    while (indexofOriginal >=0 && indexofNew > indexofOriginal) {
        if (indexofOriginal == 0 && indexofa2 != 0){
            _a1[--indexofNew] = _a2[--indexofa2];
            continue;
        }
        if (_a1[indexofOriginal - 1] >= _a2[indexofa2 -1] )
            _a1[--indexofNew] = _a1[--indexofOriginal ];
        else
        {
            _a1[--indexofNew] = _a2[--indexofa2];
        }
    }
    for (int i = 0; i< _a1_length + _a2_length ; i++){

        std::cout<< _a1[i] << std::endl;
    }    
}

注意a1[]数组容量足够(数组的大小在定义时要事先规定,不能在程序中进行调整,否则内存不足时会产生错误的数据),且需要考虑特殊情况, a1 全部大于a2时

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值