C语言中顺序表的使用及相关经典案例

1. 线性顺序表的定义

结构体定义的经典定义方式,必备

#define MAX_SIZE 100
typedef int ElementType;
typedef struct sqlist{
    
    
	ElementType data[MAX_SIZE];
	int length;
} SqList;

2. 分配空间

SqList * L->data = (ElementType *) malloc(sizeof(ElementType) * MAX_SIZE);

3.顺序表的查找

查找元素e在表中的位置,如果查找到就返回数组下标加1,没有知道就返回-1

// 按值查找时,只能顺序查找
int FindByValue(SqList *L, int e){
    
    
	int i;
	for(i = 0; i < L->length; i++)
		if(L->data[i] == e)
		return i + 1;
	return -1;
}

4. 顺序表的插入

在顺序表L的第i个位置(1<= i <= n)个位置上插入一个新结点e。插入思路如下:

  1. 将线性表L中的第i个至第n个节点向后移动一个位置;
  2. 将结点e插入到 i-1位置;
  3. 线性长度加1。
bool ListInsert(SqList *L, int i, int e){
    
    
	if (i<1 || i>L->length + 1) return false;
	if (L->length >= MAX_SIZE) 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 true;
}

5.线性表的删除

5.1 按照位置进行删除

在顺序表L中删除第i个位置(1<= i <= n)。思路如下:

  1. 将线性表L中的第i + 1个至第n个节点依次向前移动一个位置;
  2. 线性长度减1。
bool ListDelete(SqList *L, int i){
    
    
	if (L->length === 0) return false;
	if (i < 1 || i > L->length) return false;
	for (int j = i; j < L->length; j++)
		L->data[j-1] = L->data[j];
	L ->length--;
	return true;
}

5.2 按照值进行删除

在顺序表L中删除值为x的结点。当表n较大时,算法的效率相当低,因此算法的平均时间复杂度为O(n)。思路如下:

  1. 从线性表L中的查找值为x的第一个数据元素;
  2. 将从找到的位置至最有一个结点依次向前移动一个位置;
  3. 线性长度减1。
bool Locate_Delete_SqList(SqList *L, int x){
    
    
	 int i = 0, k;
	 while (i < L->length){
    
    
	 	if(L->data[i] != x) i++;
	 	else{
    
    
	 		for (k = i; k < L->length; k++)
	 			L->data[k - 1] = L->data[k];
	 		L->length--;
	 		break;
	 	}
	 }
	 if (i >= L->length) {
    
    
	 	printf("要删除的数据元素不存在!\n");
	 	return false;
	 }
	 return true;
}

6. 顺序表的经典算法题

6.1 双指针不回溯

题目描述:
编写算法,将两个非递减有序顺序表A和B合并成一个新的非递减有序顺序表C,已知顺序表A和B的元素个数分别为m和n。其中顺序表采用动态分配空间,定义如下:

Typedef struct{
    
    
	ElementType *elem;
	int length;
	int listsize;
}SqList;

解题思路:
要合并两个有序的顺序表A和B,那么生成一个数据空问C,当A和B都未到末尾时,逐个比较A和B的元素,将值小的元素放入到C中,当元索相等时,只保留一个。当A或B结束时,将未结束表的元素逐个放入到C中。

解题代码:

void Combination(SqList * L1, SqList * L2,SqList * L3){
    
    
	int i=j=k=0;
	while((i!=L1->length) && (j!=L2->length)){
    
    
		if(L1->data[i] > L2->data[j]){
    
     //L1中元素大,合并L2中元素到L3中
			L3->data[k++] = L2->data[j++];
		}else if(L1->data[i] == L2->data[j]){
    
     //两元素值相等
			L3->data[k++] = L2->data[j++];
			i++;
		}else{
    
      //L2中元素大
			L3->data[k++] = L1->data[i++];
		}
		L3->length++;
	}
	while(i < L1-->length){
    
     //L2结束,合并L1中元素到L3末尾
		L3->data[k++] = L1->data[i++];
		L3->length++;
	}
	while(j < L2-->length){
    
     //L1结束,合并L2中元素到L3中
		L3->data[k++] = L2->data[j++];
		L3->length++;
	}
}

6.2 顺序表的逆序问题

题目描述:
试写一算法,实现顺序表的就地逆置,即利用原表的存储空间将线性表逆置。

解题思路:
要实现数组的逆置,且要求使用原有空间,只需要将对应的数组元素位置交换就可以,如第1个(对应下标是0)和第n个(对应下标是n-1)交换,第2个(对应下标是1)和第n一1个(对应下标是n-2)交换,需要交换的两个元素的下标之和是n-1,其中n是表长。
实现代码如下:

int ListOppose(SqList *L){
    
     //交换元素的首尾位置
    int i;
    ElementType x;
    for(i = 0; i < L->length / 2; i++){
    
    
        x = L->data[i];
        L->data[i] = L->data[L->length - i - 1];  //数据元素交换位置
        L->data[L->length - i - 1] = x;  //数组长度加1
    }
    return 1;
}

6.3 左右指针法

题目描述:
一个线性表中的元素全部为正或负整数,试设计一算法,在尽可能少的时间内重排该表,将正、负整数分开,使线性表中所有负整数在正整数前面。

解题思路:
采用快速排序的思想,将首部第一个元素(会被替换,因此比较结束后,需要将该元素放在合适位置)作为暂存值,列表中每个元素与0进行比较,判断对应的元素是否是正数或者负数,然后放到对应位置。

实现代码:

int ReArrange(ElementType * a, int n){
    
    
    int low = 0, high = n - 1;
    int t = a[low];
    int j;
    while(low < high){
    
     // 内部两个while循环不可交换位置,枢轴元素在首部,应先比较高位,低位置先排序好
        /*while (low < high && a[low] < 0) {    // 若要先比较低位,则枢轴元素应为尾部
            low++;
        }
        a[high] = a[low];*/
        while (low < high && a[high] >= 0){
    
     //对高位进行比较,符合条件进行自减
            high--;
        }
        a[low] = a[high]; // 优先对低位进行规整
        while (low < high && a[low] < 0) {
    
     //对低位进行比较,符合条件进行自增
            low++;
        }
        a[high] = a[low];
    }
    a[low] = t; //将枢轴元素放在最终的位置
}

6.3.1 奇偶数区分

一个线性表中的元素全部为整数,设计一算法,在尽可能少的时间内重排该表,将奇数和偶数分开,使线性表中所有奇数在偶数前面。

// 方法1
void part_method1(int *a, int n){
    
    
    int t, low = 0, high = n - 1;
    t = a[low];
    while (low < high){
    
    
        while ((low < high) && (a[high] % 2 == 0)){
    
    
            high--;
        }
        a[low] = a[high];
        while((low < high) && (a[low] % 2 != 0)){
    
    
            low++;
        }
        a[high] = a[low];
    }
    a[low] = t;
}
//方法2
void part_method2(int * a, int n){
    
    
    int t, low = 0, high = n - 1;
    while (low < high){
    
    
        while ((low < high) && (a[high] % 2 == 0)){
    
    
            high--;
        }
        while((low < high) && (a[low] % 2 != 0)){
    
    
            low++;
        }
        if (low < high){
    
    
            t = a[low];
            a[low] = a[high];
            a[high] = t;
        }
    }
}

6.4 数据元素的旋转

6.4.1 例子1

题目描述:
已知在一维数组A[0,…,m十n一1]中依次存放着两个顺序表:(a1,a2,…,am)和(b1,b2,…,bn)。试编写程序,将数组中两个顺序表的位置互换,即将(b1,b2,…,bn)放在(a1,a2,…,am)的前面。

解题思路:

  1. 将整个数组全部进行逆序;
  2. 将逆序后的数组(b1,…,bn)进行逆序;
  3. 将逆序后的数组(a1,…,am)进行逆序。

实现代码如下:

typedef int ElementType;

void Reverse(ElementType  arr[], int left, int right, int arr_size){
    
     // 输入数组,需要交换的左边索引,需要交换的右边索引,及数组的大小
    if ((left >= right) || (right >= arr_size))
        return;
    int mid = (left + right) / 2;
    for(int i = 0; i <= mid - left; i++){
    
    
        ElementType temp = arr[left + i];
        arr[left + i] = arr[right - i];
        arr[right - i] = temp;
    }
}

void Exchange(ElementType arr[],int m, int n, int arr_size){
    
     //注意,参数中的m和n是两数组中元素个数
    Reverse(arr, 0, arr_size - 1, arr_size);
    Reverse(arr, 0, n - 1, arr_size);
    Reverse(arr, n, arr_size - 1, arr_size);
}

6.4.2 例子2

题目描述:
设有一个线性表存放在一维数组α[0,…,n-1]中,编写一算法,将数组中每个元素循环右移k位,要求只用
一个辅助单元,时间复杂度为O(n)。

解题思路:
1.先将所有元素进行逆序;
2.右移k位,则会有k%n个元素会被移动至头部,对这部分数据元素进行逆序;
3.将剩余的n-(k%n)个元素进行逆序排序。

实现代码如下:

typedef int ElementType;

void Reverse(ElementType  arr[], int p, int q){
    
     // 输入数组,需要交换的左边索引,需要交换的右边索引,并进行交换
    for(;p < q; p++, q--){
    
    
        ElementType temp = arr[p];
        arr[p] = arr[q];
        arr[q] = temp;
    }
}

void RightShift(ElementType arr[], int n, int k){
    
    
    k = k % n;  //k%n个元素,会被移动到头部,剩下的元素向后移动
    Reverse(arr, 0, n - 1);
    Reverse(arr, 0, k - 1);
    Reverse(arr, k, n - 1);
}

猜你喜欢

转载自blog.csdn.net/qq_41780234/article/details/127189470