在學習了C語言之後,我們先來了解一下簡單的數據結構,順序表和鏈表。
順序表和鏈表都屬於線性數據結構。順序表的底層相當於一個數組,因爲它的空間是一段地址連續的存儲單元;鏈表的底層不需要所有的空間都連續,只要通過指針就可以找到下一個存儲空間。
下面就用C語言簡單的實現一下靜態順序表和動態順序表。
1、靜態順序表
SeqList.h
#ifndef __SQLLIST_H__
#define __SQLLIST_H__
#include<stdio.h>
#include<assert.h>
#include<string.h>
typedef int Datatype;
#define MAX 10
typedef struct SeqList
{
Datatype data[MAX];
int sz;
}SeqList, *pSeqlist;
void InitSeqList(pSeqlist ps); //初始化順序表
void PushBack(pSeqlist ps, Datatype key); //尾部插入元素
void PopBack(pSeqlist ps); //尾部刪除元素
void PushFront(pSeqlist ps, Datatype key); //頭部插入元素
void PopFront(pSeqlist ps); //頭部刪除元素
int Find(pSeqlist ps, Datatype key); //查找指定元素,並返回下標
int Insert(pSeqlist ps, Datatype key, int pos); //在指定位置插入元素
void Remove(pSeqlist ps, Datatype key); //刪除指定元素
void RemoveAll(pSeqlist ps, Datatype key);//刪除指定的所有元素
void Reverse(pSeqlist ps); //逆置順序表
void Sort(pSeqlist ps); //升序排序
int BinarSearch(pSeqlist ps, Datatype key); //二分查找指定元素
#endif
SeqList.c
#include"SeqList.h"
void InitSeqList(pSeqlist ps)
{
ps->sz = 0;
memset(ps->data, 0, sizeof(ps->data));
}
void Display(const pSeqlist ps)
{//打印順序表中的元素
int i = 0;
assert(ps != NULL);
for (i = 0; i < ps->sz; i++)
{
printf("%d ", ps->data[i]);
}
printf("\n");
}
void PushBack(pSeqlist ps, Datatype key)
{
assert(ps != NULL);
if (ps->sz == MAX)
{
return;
}
ps->data[ps->sz] = key;
ps->sz++;
}
void PopBack(pSeqlist ps)
{
assert(ps != NULL);
if (ps->sz == 0)
{
return;
}
ps->sz--;
}
void PushFront(pSeqlist ps, Datatype key)
{
assert(ps != NULL);
if (ps->sz == MAX)
return;
if (ps->sz < MAX)
{
int i = 0;
//memmove(目標,源,字節數)
memmove(ps->data + 1, ps->data, sizeof(Datatype)*(ps->sz));
/*for (i = ps->sz; i>0; i--)
{ 將從最後一個元素開始,每個元素往後挪一個
ps->data[i] = ps->data[i - 1];
}*/
ps->data[0] = key;
ps->sz++;
}
}
void PopFront(pSeqlist ps)
{
int i = 0;
assert(ps != NULL);
if (ps->sz == 0)
return;
for (i = 0; i<ps->sz - 1; i++)
{ //從第二個元素開始,每個都往前挪一個
ps->data[i] = ps->data[i + 1];
}
ps->sz--;
}
int Find(pSeqlist ps, Datatype key)
{
int i = 0;
assert(ps != NULL);
for (i = 0; i < ps->sz; i++)
{
if (key == ps->data[i])
return i;
}
return -1;
}
int Insert(pSeqlist ps, Datatype key, int pos)
{
int i = 0;
assert(ps != NULL);
if (ps->sz == MAX)
return;
if (ps->sz < MAX)
{
for (i = ps->sz; i >pos; i--)
{
ps->data[i] = ps->data[i - 1];
}
ps->data[pos] = key;
ps->sz++;
}
}
void Remove(pSeqlist ps, Datatype key)
{
int pos = 0;
assert(ps);
pos = Find(ps, key);
if (pos != -1)
{
memmove(ps->data + pos, ps->data + pos + 1, (ps->sz - pos - 1)*sizeof(Datatype));
ps->sz--;
}
}
void RemoveAll(pSeqlist ps, Datatype key)//刪除所有的key
{
int pos = 0;
assert(ps);
while ((pos = Find(ps, key)) != -1)
{
Remove(ps, key);
}
}
void Swap(Datatype *a, Datatype *b)
{
Datatype tmp = *a;
*a = *b;
*b = tmp;
}
void Reverse(pSeqlist ps)
{
Datatype* left = ps->data;
Datatype* right = ps->data + ps->sz - 1;
assert(ps != NULL);
while (left < right)
{
Swap(left, right);
left++;
right--;
}
}
void Sort(pSeqlist ps)
{
int i = 0;
int j = 0;
assert(ps);
for (i = 0; i < (ps->sz - 1); i++)
{
for (j = 0; j < ps->sz - 1 - i; j++)
{
if (ps->data[j] > ps->data[j + 1])
{
Swap(&ps->data[j], &ps->data[j + 1]);
/*Datatype tmp = ps->data[j];
ps->data[j ] = ps->data[j+1];
ps->data[j + 1] = tmp;*/
}
}
}
}
int BinarSearch(pSeqlist ps, Datatype key)
{
int left = 0;
int right = ps->sz - 1;
assert(ps);
while (left <= right)
{
int mid = left + ((right - left) >> 1);
if (key == ps->data[mid])
{
return mid;
}
else if (key > ps->data[mid])
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return -1;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void test1()//尾插尾刪
{
SeqList my_list;
InitSeqList(&my_list);
PushBack(&my_list, 1);
PushBack(&my_list, 2);
PushBack(&my_list, 3);
PushBack(&my_list, 4);
Display(&my_list);
PopBack(&my_list);
Display(&my_list);
PopBack(&my_list);
Display(&my_list);
PopBack(&my_list);
Display(&my_list);
}
void test2()//頭插頭刪
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 3);
PushFront(&my_list, 4);
Display(&my_list);
PopFront(&my_list);
Display(&my_list);
PopFront(&my_list);
Display(&my_list);
PopFront(&my_list);
Display(&my_list);
}
void test3()
{
SeqList my_list;
int pos = 0;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 3);
PushFront(&my_list, 4);
PushFront(&my_list, 5);
pos = Find(&my_list, 4);
if (pos == -1)
{
printf("要查找的u元素不存在");
}
else
{
Insert(&my_list, 6, pos);
}
Display(&my_list);
}
void test4()
{
SeqList my_list;
int pos = 0;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 3);
PushFront(&my_list, 5);
PushFront(&my_list, 4);
PushFront(&my_list, 2);
Display(&my_list);
Sort(&my_list);
Display(&my_list);
}
void test5()
{
SeqList my_list;
int pos = 0;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 3);
PushFront(&my_list, 4);
PushFront(&my_list, 5);
Display(&my_list);
Sort(&my_list);
pos = BinarSearch(&my_list, 3);
printf("%d\n", pos);
pos = BinarSearch(&my_list, 6);
printf("%d\n", pos);
}
int main()
{ //對順序表中鎖實現函數的簡單測試
test5();
system("pause");
return 0;
}
這是簡單的實現了一個靜態的順序表,但它是有缺陷的,就是他的數組大小是固定的,接下來我們就來實現一個動態的也就是數組大小可變的順序表。
2、動態順序表
在編寫動態順序表的時候,更多的是要檢測在插入元素時是否需要增容。在定義順序表時,不僅需要一個數組的大小sz,還需要一個容量capacity,當sz<capacity時,不需要增容,而當sz==capacity時,就需要動態增容,然後再插入元素。
SeqList.h
#ifndef __SQLLIST_H__
#define __SQLLIST_H__
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#define DEFAULT_SZ 3
#define INC 3
typedef int Datatype;
typedef struct SeqList
{
Datatype* data;
int sz;
int capacity;
}SeqList,*pSeqlist;
void InitSeqList(pSeqlist ps);
void PushBack(pSeqlist ps, Datatype key);
void PopBack(pSeqlist ps);
void PushFront(pSeqlist ps, Datatype key);
void PopFront(pSeqlist ps);
int Find(pSeqlist ps, Datatype key);
int Insert(pSeqlist ps, Datatype key, int pos);
void Remove(pSeqlist ps, Datatype key);
void RemoveAll(pSeqlist ps, Datatype key);//刪除所有的key
void Reverse(pSeqlist ps);
void Sort(pSeqlist ps);
int BinarSearch(pSeqlist ps, Datatype key);
#endif
SeqList.c
#include"SeqList.h"
void InitSeqList(pSeqlist ps)
{ //初始化:元素個數爲0,容量爲DEFAULT_SZ
assert(ps);
ps->sz = 0;
ps->capacity = DEFAULT_SZ;
ps->data = malloc((ps->capacity)*sizeof(Datatype));
if (ps->data == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
memset(ps->data, 0, (ps->capacity)*sizeof(Datatype));
}
void Destroy(pSeqlist ps)
{
assert(ps);
free(ps->data);
ps->data = NULL;
ps->capacity = 0;
ps->sz = 0;
}
void Display(const pSeqlist ps)
{//打印順序表中的元素
int i = 0;
assert(ps != NULL);
for (i = 0; i < ps->sz; i++)
{
printf("%d ", ps->data[i]);
}
printf("\n");
}
void Checkcapacity(pSeqlist ps)
{
assert(ps);
if (ps->sz == ps->capacity)
{ //當sz=capacity時,說明已經沒有空間可以進行插入操作,只能進行增容
Datatype* ptr = realloc(ps->data, (ps->capacity + INC)*sizeof(Datatype));
if (ptr != NULL)
{ //增容成功,將capacity置成新增容的空間大小,空間也爲增容後的空間
ps->data = ptr;
ps->capacity += INC;
}
else
{ //增容失敗
perror("realloc");
exit(EXIT_FAILURE);
}
}
}
void PushBack(pSeqlist ps, Datatype key)
{
assert(ps != NULL);
assert(ps->data);
Checkcapacity(ps);//先來檢測一下是否需要增容
ps->data[ps->sz] = key;
ps->sz++;
}
void PopBack(pSeqlist ps)
{
assert(ps != NULL);
if (ps->sz == 0)
{ //順序表爲空,並不需要刪除
return;
}//只需將sz--,但底層該值仍存在,知識不能訪問而已
ps->sz--;
}
void PushFront(pSeqlist ps, Datatype key)
{
assert(ps != NULL);
if (ps->sz == ps->capacity)
Checkcapacity(ps);
if (ps->sz < ps->capacity)
{
int i = 0;
//memmove(目標,源,字節數)
memmove(ps->data+1, ps->data,sizeof(Datatype)*(ps->sz));
/*for (i = ps->sz; i>0; i--)
{ 將從最後一個元素開始,每個元素往後挪一個
ps->data[i] = ps->data[i - 1];
}*/
ps->data[0] = key;
ps->sz++;
}
}
void PopFront(pSeqlist ps)
{
int i = 0;
assert(ps != NULL);
if (ps->sz == 0)
return;
for (i = 0; i<ps->sz-1; i++)
{ //從第二個元素開始,每個都往前挪一個
ps->data[i] = ps->data[i + 1];
}
ps->sz--;
}
int Find(pSeqlist ps, Datatype key)
{ //查找指定值
int i = 0;
assert(ps != NULL);
for (i = 0; i < ps->sz; i++)
{
if (key == ps->data[i])
return i;
}
return -1;
}
int Insert(pSeqlist ps, Datatype key, int pos)
{ //指定位置插入
int i = 0;
assert(ps != NULL);
if (ps->sz == ps->capacity)//檢測是否需要增容
Checkcapacity(ps);
if (ps->sz <ps->capacity)
{ //當sz<capacity時,將pos以及pos後面的所有元素都向後挪一個
for (i = ps->sz; i >pos; i--)
{
ps->data[i] = ps->data[i-1];
} //挪完之後把要插入的值插入到pos位置
ps->data[pos] = key;
ps->sz++;
}
}
void Remove(pSeqlist ps, Datatype key)
{ //刪除指定的值
int pos = 0;
assert(ps);
pos=Find(ps, key); //在順序表中查找是否有該元素
if (pos != -1)//pos爲-1就說明順序表中不存在該元素,
{ //pos返回的是該元素所在的下標,將pos後邊的元素都往前挪一個
memmove(ps->data + pos, ps->data + pos + 1, (ps->sz - pos - 1)*sizeof(Datatype));
ps->sz--;
}
}
void RemoveAll(pSeqlist ps, Datatype key)//刪除所有的key
{
int pos = 0;
assert(ps);
while ((pos = Find(ps, key))!=-1)
{
Remove(ps, key);
}
}
void Swap(Datatype *a, Datatype *b)
{
Datatype tmp = *a;
*a = *b;
*b = tmp;
}
void Reverse(pSeqlist ps)
{ //逆置順序表,即將順序表中的元素逆置
Datatype* left = ps->data;
Datatype* right = ps->data + ps->sz - 1;
assert(ps!=NULL);
while (left < right)
{ //將最左邊的和最右邊的元素交換,然後座標的往後挪一個,右邊的往前挪一個繼續交換
Swap(left, right);
left++;
right--;
}
}
void Sort(pSeqlist ps)
{ //給順序表中的元素進行升序排序
int i = 0;
int j = 0;
assert(ps);
for (i = 0; i < (ps->sz - 1); i++)
{ //採用冒泡排序的思想
for (j = 0; j < ps->sz-1-i; j++)
{
if (ps->data[j] > ps->data[j + 1])
{
Swap(&ps->data[j], &ps->data[j + 1]);
/*Datatype tmp = ps->data[j];
ps->data[j ] = ps->data[j+1];
ps->data[j + 1] = tmp;*/
}
}
}
}
int BinarSearch(pSeqlist ps, Datatype key)
{ //二分查找
int left = 0;
int right = ps->sz - 1;
assert(ps);
while (left <= right)
{
int mid = left + ((right - left) >> 1);
if (key == ps->data[mid])
{
return mid;
}
else if (key > ps->data[mid])
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return -1;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void test1()//尾插尾刪
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 1);
//PushFront(&my_list, 2);
PushFront(&my_list, 3);
//PushFront(&my_list, 4);
PushFront(&my_list, 5);
Display(&my_list);
Insert(&my_list,2,2);
PopFront(&my_list);
Display(&my_list);
PopFront(&my_list);
Display(&my_list);
Destroy(&my_list);
}
void test2()
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 5);
PushFront(&my_list, 3);
PushFront(&my_list, 1);
Display(&my_list);
Insert(&my_list, 4, 2);
Display(&my_list);
Insert(&my_list, 2, 1);
Display(&my_list);
Destroy(&my_list);
}
void test3()
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 5);
PushFront(&my_list, 4);
PushFront(&my_list, 4);
PushFront(&my_list, 3);
PushFront(&my_list, 1);
PushFront(&my_list, 1);
Display(&my_list);
RemoveAll(&my_list, 1);
Display(&my_list);
RemoveAll(&my_list, 4);
Display(&my_list);
Destroy(&my_list);
}
void test4()
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 4);
PushFront(&my_list, 3);
PushFront(&my_list, 6);
PushFront(&my_list, 5);
Display(&my_list);
Sort(&my_list);
Display(&my_list);
Reverse(&my_list);
Display(&my_list);
Destroy(&my_list);
}
void test5()
{
SeqList my_list;
int pos = 0;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 3);
PushFront(&my_list, 4);
PushFront(&my_list, 5);
Display(&my_list);
Sort(&my_list);
pos = BinarSearch(&my_list, 3);
printf("%d\n", pos);
pos = BinarSearch(&my_list, 6);
printf("%d\n", pos);
}
int main()
{
test5();
system("pause");
return 0;
}
好了,以上就是動態順序表的實現。其實靜態順序表和動態順序表的實現區別只是在插入元素時需要檢測是否需要增容,需要就用realloc()進行增容。