第二章线性表

本文详细介绍了线性表的特性,包括同一性、有穷性和有序性,并探讨了顺序存储结构和链式存储结构。重点讲述了顺序表的动态分配和静态分配,以及一系列基本操作的实现,如插入、删除、查找、逆置和合并等。此外,还包含了处理重复元素、删除指定范围数值的方法,以及如何找到序列中位数和多数元素。
摘要由CSDN通过智能技术生成

线性表的特点:

(1)同一性,线性表由同类数据元素组成,每一个ai必须属于同一数据类型。

(2)有穷性,由有限个数据元素组成,表长度就是表中数据元素的个数

(3)有序性,线性表中相邻数据元素之间存在着序偶关系<ai,ai+1>

存放线性表的两种基本存储结构:顺序存储结构和链式存储结构

顺序表:表中元素的逻辑顺序与物理顺序相同,通常用数组来描述顺序表

注:线性表中元素的位序从1开始,数组中元素的下标是从0开始的。

静态分配:数组的大小和空间事先已经固定,一旦空间占满,再加入新的数据就会产生溢出,进而导致程序崩溃。

#define MaxSize 50
typedef int ElemType;
typedef struct {
    ElemType data[MaxSize];//顺序表的元素
    int length;//顺序表的长度
}SqList;//顺序表的类型定义

动态分配:存储数组的空间是在程序执行过程中通过动态存储分配语句分配,一旦数据空间占满,就另外开辟一块更大的存储空间,用以替换原来的存储空间。

typedef struct {
    ElemType* data;//指示动态分配数组的指针
    int Maxsize, length;//数组的最大容量和当前个数
}SeqList;
基本操作:
void IncreaseSize(SeqList* L, int len) {
    int *p = L->data;
    L->data = (ElemType*)malloc((L->Maxsize + len) * sizeof(ElemType));
    for (int i = 0; i < L->length; i++) {
        L->data[i] = p[i];
    }
    L->Maxsize = L->Maxsize + len;
    free(p);
}
void InitList(SeqList* L) {
    L->data = (ElemType*)malloc(InitSize * sizeof(ElemType));
    L->length = 0;
    L->Maxsize = InitSize;
}
int ListInsert(SqList* L, int i, ElemType e) {
    if (i<1 || i>L->length + 1)//判断i是否有效,因为顺序表中数据元素存储是连续的,所以当i=length+2时无效,造成不连续
        return false;
    if (L->length >= MaxSize)//存储空间已满,不能插入
        return false;
    for (int j = L->length; j >= i; j--) 
        L->data[j] = L->data[j - 1];
    L->data[i - 1] = e;
    L->length++;
    return 1;
}
int ListDelete(SqList* L, int i, ElemType* e) {
    if (i<1 || i>L->length)
        return false;
    e = L->data[i - 1];
    for (int j = i; j <= L->length; j++)
        L->data[j - 1] = L->data[j];
    L->length--;
    return 1;
}int LocateElem(SqList L, ElemType e) {
    int i;
    for (i = 0; i <L.length; i++)
        if (L.data[i] == e)
            return i + 1;
    return 0;
}
ElemType GetElem(SqList L, int i) {
    return L.data[i - 1];
}
//删最小
int DelMin(SeqList* L, ElemType* e) {
    if (L->length = 0)
        return 0;
    e=L->data[0];
    int i;
    for (i = 1; i < L->length; i++) {
        if (e > L->data[i])
            e = L->data[i];
    }
    L->data[i] = L->data[L->length-1];
    L->length--;
    return e;
}
//逆置
int Reverse(SeqList* L) {
    ElemType temp;
    int i;
    for (i = 0; i < L->length / 2; i++)
    {
        temp = L->data[i];
        L->data[i] = L->data[L->length - i-1];
        L->data[L->length - i - 1] = temp;
    }
}
 

//删所有x顺序表,记录等于x的个数,改变顺序表长度
void DelX(SqList* L,ElemType x) {
    int count = 0;//记录值等于x的个数
    int i=0;
    while (i < L->length) {
        if (L->data[i] == x)
            count++;
        else
            L->data[i - count] = L->data[i];
        i++;
    }
    L->length = L->length - count;
}
//
void Del2X(SqList* L, ElemType x) {
    int k = 0;
    for (int i = 0; i < L->length; i++)
        if (L->data[i] != x)
        { 
            L->data[k] = L->data[i];
            k++;
        }
}
//删值在s和t之间的数,有序顺序表
int DeLST(SqList* L, ElemType s, ElemType t) {
    int i, j;
    if (s >= t || L->length == 0)
        return false;
    for (i = 0; i < L->length && L->data[i] < s; i++);//找到大于等于s的第一个元素
    if (i >= L->length)
        return false;
    for (j = i; j < L->length && L->data[j] <= t; j++); //找到大于t的第一个元素
    for (; j < L->length; i++, j++)//前移,填补被删元素位置
        L->data[i] = L->data[j];
    L->length = i;
    return true;
}
//删值在s和t之间的数,顺序表
int DELST(SqList* L, ElemType s, ElemType t) {
    int i, k=0;
    if (s >= t || L->length == 0)
        return false;
    for (i = 0; i < L->length; i++) {
        if (L->data[i] >= s && L->data[i] <= t)
            k++;
        else
            L->data[i - k] = L->data[i];
    }
    L->length = L->length - k;
    return true;
}
//删除有序表中相同元素保留一个
int DELSame(SqList* L) {
    if (L->length == 0)
        return false;
    int i,j;
    for (i = 0, j = 1; j < L->length; j++)
        if (L->data[i] != L->data[j])//查找下一个与上个元素值不同的元素
            L->data[++i]=L->data[j];//找到后,将元素前移
    L->length = i + 1;
    return true;
}
int Merge(SqList A, SqList B, SeqList* C) {
    if (A.length + B.length > C->Maxsize)
        return false;
    int i = 0, j = 0, k = 0;
    while (i < A.length && j< B.length) {
        if (A.data[i] <= B.data[j])
            C->data[k++] = A.data[i++];
        else
            C->data[k++] = B.data[j++];
    }
    while (i < A.length)
        C->data[k++] = A.data[i++];
    while (j < B.length)
        C->data[k++] = B.data[j++];
    C->length = k;
    return true;
}
 
//(a1,a2,...an,b1,b2,b3,...bn)转换成(b1,b2,...,bn,a1,a2,a3,...am)1.先将整个数组逆置,然后对bn....逆置,在对am...逆置
void reverse(ElemType A[], int left, int right, int arraySize) {//逆置
    if (left >= right || right >= arraySize)
        return;
    int mid = (left + right) / 2;
    for (int i = 0; i < mid - left; i++) {
        ElemType temp = A[left + i];
        A[left + i] = A[right - i];
        A[right - i] = temp;
    }
}
void Exchange(ElemType A[], int m, int n, int arraysize) {
    Reverse(A, 0, m + n - 1, arraysize);
    Reverse(A, 0, n - 1, arraysize);
    Reverse(A, n, m + n - 1, arraysize);
}
void Binsearch(SqList* L, ElemType x) {
    int low = 0, high = L->length - 1;
    ElemType t;
    int mid,i;
    while (low<=high) {
        mid = (low + high) / 2;
        if (L->data[mid] == x)
            break;
        else if (L->data[mid] < x) {
            low = mid + 1;
        }
        else if (L->data[mid] > x)
            high = mid - 1;
    }
    if (L->data[mid] == x && mid != L->length - 1) {//若最后一个元素与mid处的元素相等,便不需要交换
        t = L->data[mid];
        L->data[mid] = L->data[L->length - 1];
        L->data[L->length - 1] = t;
    }
    if (low > high) {
        for (i = L->length - 1; i > high; i--)
            L->data[i + 1] = L->data[i];//元素后移
        L->data[i+1] = x;
    }
}
 
//ab--->ba(逆置a,在逆置b,在逆置整个数组)时复杂度O(n),空复杂度O(1)
void REverse(int R[], int from, int to) {
    int mid,temp,i;
    mid = (from + to) / 2;
    for (i = 0; i < mid - from; i++)
    {
        temp = R[from + i];
        R[from + i] = R[to - i];
        R[to - i] = temp;
    }
}
void Converse(int R[], int n, int p) {
    REverse(R, 0, p - 1);
    REverse(R, p, n - 1);
    REverse(R, 0, n - 1);
}
//分别求两个升序序列的中位数,1.若相等则输出 2若A[mid]<B[mid],舍弃A中较小部分,舍弃B较大部分,舍弃长度相同
//3.若A[mid]>B[mid],舍弃A中较大部分,舍弃B较小部分,舍弃长度相同 .重复123,直到两个序列中均只含一个元素为止,较小者为所求中位数
int M_Search(int A[], int B[], int n) {
    int s1 = 0, d1 = n - 1, m1, s2 = 0, d2 = n - 1, m2;
    while (s1 != d1 || s2 != d2) {
        m1 = (s1 + d1) / 2;
        m2 = (s2 + d2) / 2;
        if (A[m1] == B[m2])
            return A[m1];
        if (A[m1] < B[m2]) {
            if ((s1 + d1) % 2 == 0) {//元素个数为奇数
                s1 = m1;//舍弃A中间点以前的部分且保留中间点
                d2 = m2;//舍弃B中间点以后的部分且保留中间点
            }
            else {//元素个数为偶数
                s1 = m1 + 1;//舍弃A中间点以前的部分以及中间点
                d2 = m2;//舍弃B中间点以后的部分且保留中间点
            }
        }
        else {
            if ((s1 + d1)%2==0) {
                d1 = m1;
                s2 = m2;
            }
            else {
                d1 = m1;
                s2 = m2 + 1;
            }
        }
    }
    return A[m1] < B[m2] ? A[s1] : B[s2];
}
int Majority(int A[], int n) {
    int i, c, count = 1;
    c = A[0];
    for (i = 1; i < n; i++)
        if (A[i] == c)
            count++;
        else
            if (count > 0)
                count--;
            else
            {
                c = A[i];
                count = 1;
            }
    if (count < 0)
        for (i = count = 0; i < n; i++)
            if (A[i] == c)
                count++;
    if (count > n / 2)
        return c;
    else
        return -1;

}
//找未出现的最小正整数
int FindMissMin(int A[], int n) {
    int i, *B;
    B = (int*)malloc(sizeof(int) * n);//分配空间
    memset(B, 0, sizeof(int) * n);//赋初值为0
    for (i = 0; i < n; i++)
        if (A[i] > 0 && A[i] <= n)//A[i]的值介于1-n,则标记数组B
            B[A[i] - 1] = 1;
    for (i = 0; i < n; i++)//扫描数组B,找到目标值
        if (B[i] == 0)
            break;
    return i + 1;//返回结果
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值